dm: Add additional bus functionality
Subsystems (10)
v3 cover dm: Add additional bus functionality
The current bus implementation is simple but leaves some things to drivers which are better handled in the uclass.
At present uclasses cannot provide a common way of dealing with children (i.e. devices on the bus), so we have duplication in the drivers. The same code is repeated in each driver when it would be better to put it in the uclass.
Secondly, we don't have the concept of per-child platform data for devices on the bus. Instead the per-child data can only exist when the child is actually probed. This is not really suitable. Examples of things we want to know before a child is probed are:
- chip address (for I2C)
- chip select (for SPI)
- device address (for PCI)
These things are static and do not change when the device is probed and removed. In some cases (such as SPI mode and maximum speed), the data may be copied to run-time data when the device is probed. It may then be changed while the driver is active, but the original platform data is never changed by drivers once it is set up.
To address these issues, additional functions are added:
- per-child platform data, which can be defined by the uclass and (if necessary) overriden by the bus driver. This allows the bus's uclass to provide some consistency here
- per-child post-bind and pre-probe methods in the uclass. These allow the bus uclass to set up the per-child platform data, and also to do any last-minute adjustments before the child is probed.
With these changes, some code can be removed from the existing I2C and SPI drivers and this has been done as part of this series.
With this series I2C and SPI are tested on:
- jetson-tk1 (Tegra 124)
- beaver (Tegra 30)
- seaboard (Tegra 20, I2C only)
- trimslice (Tegra 20, SPI only)
- snow (Exynos 5250)
- pit (Exynos 5420, note I2C probe is previously broken)
- link (x86)
- sandbox
Note: Some of these changes were previously included in the DM PCI RFC. This series is available at u-boot-dm/i2c-working.
Changes in v3:
- Add missing 'static' to two functions
- Change variable name from parent_drv to uc_drv
- Fix comment to say 'node references' instead of 'phandles'
- Fix stale comment in device_probe_child()
- Fix typo in commit subject
- Remove unnecessary check that dev->parent_platdata is NULL
- Remove unnecessary per_child_auto_alloc_size value
Changes in v2:
- Add a TODO to remove struct dm_spi_bus
- Add additional comments to spi.h
- Add new patch to provide an offset length parameter where needed
- Add patches to tidy up cros_ec using new I2C/SPI features
- Copy max_hz and mode from platdata to spi_slave when probing
- Drop RFC prefix since this series has been properly tested now
- Tidy up soft_spi driver also
- Update commit message to describe immuatable platform data
- Update the spi-howto docs
Simon Glass (26):
dm: i2c: Provide an offset length parameter where needed
dm: Don't run tests if U-Boot cannot be built
dm: core: Improve comments for uclass_first/next_device()
dm: core: Set device tree node for root device
dm: core: Tidy up error handling in device_bind()
dm: core: Allocate platform data when binding a device
dm: core: Allow parents to have platform data for their children
dm: core: Allow uclasses to specify platdata for a device's children
dm: core: Add a post_bind method for parents
dm: core: Add a function to get a device's uclass ID
dm: core: Add a flag to control sequence numbering
dm: core: Allow uclasses to specify private data for a device's
children
dm: spi: Move the per-child data size to the uclass
dm: core: Allow the uclass to set up a device's child after binding
dm: sandbox: sf: Tidy up the error handling in sandbox_sf_probe()
dm: core: Allow uclass to set up a device's child before it is probed
dm: spi: Set up the spi_slave device pointer in child_pre_probe()
dm: spi: Move slave details to child platdata
dm: i2c: Move slave details to child platdata
dm: tegra: Drop unused COMPAT features for I2C, SPI
dm: exynos: Drop unused COMPAT features for SPI
dm: core: Ignore disabled devices when binding
dm: cros_ec: Don't require protocol 3 support
dm: cros_ec: Move cros_ec_i2c over to driver model
dm: cros_ec_spi: Remove old pre-driver-model code
dm: Update documentation for new bus features
arch/arm/cpu/tegra20-common/pmu.c | 2 +- board/avionic-design/common/tamonten-ng.c | 2 +- board/nvidia/cardhu/cardhu.c | 4 +- board/nvidia/dalmore/dalmore.c | 4 +- board/nvidia/whistler/whistler.c | 4 +- board/toradex/apalis_t30/apalis_t30.c | 2 +- common/cmd_i2c.c | 2 +- doc/driver-model/README.txt | 91 +++++------ doc/driver-model/spi-howto.txt | 40 ++++- drivers/core/device-remove.c | 16 +- drivers/core/device.c | 121 +++++++++++---- drivers/core/root.c | 8 + drivers/core/uclass.c | 34 +++- drivers/i2c/i2c-uclass-compat.c | 2 +- drivers/i2c/i2c-uclass.c | 69 +++++---- drivers/i2c/i2c-uniphier-f.c | 12 -- drivers/i2c/i2c-uniphier.c | 12 -- drivers/i2c/s3c24x0_i2c.c | 12 -- drivers/i2c/sandbox_i2c.c | 30 +--- drivers/i2c/tegra_i2c.c | 18 --- drivers/misc/cros_ec.c | 10 +- drivers/misc/cros_ec_i2c.c | 107 +++++-------- drivers/misc/cros_ec_spi.c | 70 +-------- drivers/mtd/spi/sandbox.c | 12 +- drivers/mtd/spi/sf_probe.c | 3 +- drivers/power/as3722.c | 2 +- drivers/serial/serial-uclass.c | 1 + drivers/spi/cadence_qspi.c | 1 - drivers/spi/designware_spi.c | 1 - drivers/spi/exynos_spi.c | 1 - drivers/spi/sandbox_spi.c | 1 - drivers/spi/soft_spi.c | 10 -- drivers/spi/spi-uclass.c | 95 ++++++++---- drivers/spi/tegra114_spi.c | 1 - drivers/spi/tegra20_sflash.c | 1 - drivers/spi/tegra20_slink.c | 1 - include/configs/snow.h | 5 + include/dm/device.h | 29 ++++ include/dm/test.h | 3 + include/dm/uclass-internal.h | 11 ++ include/dm/uclass.h | 21 +++ include/fdtdec.h | 7 - include/i2c.h | 12 +- include/spi.h | 42 +++-- lib/fdtdec.c | 7 - test/dm/bus.c | 250 +++++++++++++++++++++++++++++- test/dm/core.c | 11 ++ test/dm/i2c.c | 10 +- test/dm/spi.c | 6 +- test/dm/test-dm.sh | 9 +- test/dm/test-fdt.c | 20 ++- test/dm/test.dts | 16 ++ 52 files changed, 813 insertions(+), 448 deletions(-)
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 1/26 dm: i2c: Provide an offset length parameter where needed
Rather than assuming that the chip offset length is 1, allow it to be provided. This allows chips that don't use the default offset length to be used (at present they are only supported by the command line 'i2c' command which sets the offset length explicitly).
---
Changes in v3: None
Changes in v2:
- Add new patch to provide an offset length parameter where needed
arch/arm/cpu/tegra20-common/pmu.c | 2 +- board/avionic-design/common/tamonten-ng.c | 2 +- board/nvidia/cardhu/cardhu.c | 4 ++-- board/nvidia/dalmore/dalmore.c | 4 ++-- board/nvidia/whistler/whistler.c | 4 ++-- board/toradex/apalis_t30/apalis_t30.c | 2 +- common/cmd_i2c.c | 2 +- drivers/i2c/i2c-uclass.c | 16 +++++++++------- drivers/i2c/sandbox_i2c.c | 2 +- drivers/power/as3722.c | 2 +- include/i2c.h | 8 ++++++-- test/dm/i2c.c | 10 +++++----- 12 files changed, 32 insertions(+), 26 deletions(-)
arch/arm/cpu/tegra20-common/pmu.c +1 -1
@@ -52,7 +52,7 @@ int pmu_set_nominal(void)debug ("%s: Cannot find DVC I2C bus\n" , __func__);return ret; } - ret =i2c_get_chip (bus,PMI_I2C_ADDRESS , &dev); + ret =i2c_get_chip (bus,PMI_I2C_ADDRESS ,1 , &dev);if (ret) {debug ("%s: Cannot find DVC I2C chip\n" , __func__);return ret;
board/avionic-design/common/tamonten-ng.c +1 -1
@@ -55,7 +55,7 @@ void pmu_write(uchar reg, uchar data)struct udevice *dev;int ret; - ret =i2c_get_chip_for_busnum (4 ,PMU_I2C_ADDRESS , &dev); + ret =i2c_get_chip_for_busnum (4 ,PMU_I2C_ADDRESS ,1 , &dev);if (ret) {debug ("%s: Cannot find PMIC I2C chip\n" , __func__);return ;
board/nvidia/cardhu/cardhu.c +2 -2
@@ -46,7 +46,7 @@ void board_sdmmc_voltage_init(void)int ret;int i; - ret =i2c_get_chip_for_busnum (0 ,PMU_I2C_ADDRESS , &dev); + ret =i2c_get_chip_for_busnum (0 ,PMU_I2C_ADDRESS ,1 , &dev);if (ret) {debug ("%s: Cannot find PMIC I2C chip\n" , __func__);return ;
@@ -94,7 +94,7 @@ int tegra_pcie_board_init(void)u8 addr, data[1 ];int err; - err =i2c_get_chip_for_busnum (0 ,PMU_I2C_ADDRESS , &dev); + err =i2c_get_chip_for_busnum (0 ,PMU_I2C_ADDRESS ,1 , &dev);if (err) {debug ("failed to find PMU bus\n" );return err;
board/nvidia/dalmore/dalmore.c +2 -2
@@ -55,7 +55,7 @@ void board_sdmmc_voltage_init(void)uchar reg, data_buffer[1 ];int ret; - ret =i2c_get_chip_for_busnum (0 ,PMU_I2C_ADDRESS , &dev); + ret =i2c_get_chip_for_busnum (0 ,PMU_I2C_ADDRESS ,1 , &dev);if (ret) {debug ("%s: Cannot find PMIC I2C chip\n" , __func__);return ;
@@ -83,7 +83,7 @@ void board_sdmmc_voltage_init(void) data_buffer[0 ] =0x03 ; reg =0x14 ; - ret =i2c_get_chip_for_busnum (0 ,BAT_I2C_ADDRESS , &dev); + ret =i2c_get_chip_for_busnum (0 ,BAT_I2C_ADDRESS ,1 , &dev);if (ret) {debug ("%s: Cannot find charger I2C chip\n" , __func__);return ;
board/nvidia/whistler/whistler.c +2 -2
@@ -27,7 +27,7 @@ void pin_mux_mmc(void)int ret;/* Turn on MAX8907B LDO12 to 2.8V for J40 power */ - ret =i2c_get_chip_for_busnum (0 ,0x3c , &dev); + ret =i2c_get_chip_for_busnum (0 ,0x3c ,1 , &dev);if (ret) {printf ("%s: Cannot find MAX8907B I2C chip\n" , __func__);return ;
@@ -64,7 +64,7 @@ void pin_mux_usb(void)*/ /* Turn on TAC6416's GPIO 0+1 for USB1/3's VBUS */ - ret =i2c_get_chip_for_busnum (0 ,0x20 , &dev); + ret =i2c_get_chip_for_busnum (0 ,0x20 ,1 , &dev);if (ret) {printf ("%s: Cannot find TAC6416 I2C chip\n" , __func__);return ;
board/toradex/apalis_t30/apalis_t30.c +1 -1
@@ -42,7 +42,7 @@ int tegra_pcie_board_init(void)u8 addr, data[1 ];int err; - err =i2c_get_chip_for_busnum (0 ,PMU_I2C_ADDRESS , &dev); + err =i2c_get_chip_for_busnum (0 ,PMU_I2C_ADDRESS ,1 , &dev);if (err) {debug ("%s: Cannot find PMIC I2C chip\n" , __func__);return err;
common/cmd_i2c.c +1 -1
@@ -168,7 +168,7 @@ static int i2c_get_cur_bus_chip(uint chip_addr, struct udevice **devp)if (ret)return ret; - return i2c_get_chip(bus, chip_addr, devp); + return i2c_get_chip(bus, chip_addr, 1, devp); }#endif
drivers/i2c/i2c-uclass.c +9 -7
@@ -220,7 +220,7 @@ static int i2c_probe_chip(struct udevice *bus, uint chip_addr,return ops->xfer (bus, msg,1 ); } -static int i2c_bind_driver (struct udevice *bus,uint chip_addr, +static int i2c_bind_driver (struct udevice *bus,uint chip_addr,uint offset_len,struct udevice **devp) {struct dm_i2c_chip chip;
@@ -238,7 +238,7 @@ static int i2c_bind_driver(struct udevice *bus, uint chip_addr,/* Tell the device what we know about it */ memset (&chip,'\0' ,sizeof (chip)); chip.chip_addr = chip_addr; - chip.offset_len =1 ;/* we assume */ + chip.offset_len = offset_len; ret =device_probe_child (dev, &chip);debug ("%s: device_probe_child: ret=%d\n" , __func__, ret);if (ret)
@@ -254,7 +254,8 @@ err_bind:return ret; } -int i2c_get_chip (struct udevice *bus,uint chip_addr,struct udevice **devp) +int i2c_get_chip (struct udevice *bus,uint chip_addr,uint offset_len, +struct udevice **devp) {struct udevice *dev;
@@ -281,10 +282,11 @@ int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp) } }debug ("not found\n" ); -return i2c_bind_driver (bus, chip_addr, devp); +return i2c_bind_driver (bus, chip_addr, offset_len, devp); } -int i2c_get_chip_for_busnum (int busnum,int chip_addr,struct udevice **devp) +int i2c_get_chip_for_busnum (int busnum,int chip_addr,uint offset_len, +struct udevice **devp) {struct udevice *bus;int ret;
@@ -294,7 +296,7 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)debug ("Cannot find I2C bus %d\n" , busnum);return ret; } - ret =i2c_get_chip (bus, chip_addr, devp); + ret =i2c_get_chip (bus, chip_addr, offset_len, devp);if (ret) {debug ("Cannot find I2C chip %02x on bus %d\n" , chip_addr, busnum);
@@ -319,7 +321,7 @@ int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,return ret;/* The chip was found, see if we have a driver, and probe it */ - ret =i2c_get_chip (bus, chip_addr, devp); + ret =i2c_get_chip (bus, chip_addr,1 , devp);debug ("%s: i2c_get_chip: ret=%d\n" , __func__, ret);return ret;
drivers/i2c/sandbox_i2c.c +1 -1
@@ -60,7 +60,7 @@ static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,if (msg->addr ==SANDBOX_I2C_TEST_ADDR )return 0 ; - ret =i2c_get_chip (bus, msg->addr, &dev); + ret =i2c_get_chip (bus, msg->addr,1 , &dev);if (ret)return ret;
drivers/power/as3722.c +1 -1
@@ -242,7 +242,7 @@ int as3722_init(struct udevice **devp)const unsigned int address =0x40 ;int err; - err =i2c_get_chip_for_busnum (bus, address, &pmic); + err =i2c_get_chip_for_busnum (bus, address,1 , &pmic);if (err)return err; err =as3722_read_id (pmic, &id, &revision);
include/i2c.h +6 -2
@@ -388,10 +388,12 @@ struct dm_i2c_ops {* * @bus: Bus to examine * @chip_addr: Chip address for the new device +* @offset_len: Length of a register offset in bytes (normally 1) * @devp: Returns pointer to new device if found or -ENODEV if not * found */ -int i2c_get_chip (struct udevice *bus,uint chip_addr,struct udevice **devp); +int i2c_get_chip (struct udevice *bus,uint chip_addr,uint offset_len, +struct udevice **devp);/** * i2c_get_chip() - get a device to use to access a chip on a bus number
@@ -401,10 +403,12 @@ int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp);* * @busnum: Bus number to examine * @chip_addr: Chip address for the new device +* @offset_len: Length of a register offset in bytes (normally 1) * @devp: Returns pointer to new device if found or -ENODEV if not * found */ -int i2c_get_chip_for_busnum (int busnum,int chip_addr,struct udevice **devp); +int i2c_get_chip_for_busnum (int busnum,int chip_addr,uint offset_len, +struct udevice **devp);/** * i2c_chip_ofdata_to_platdata() - Decode standard I2C platform data
test/dm/i2c.c +5 -5
@@ -49,7 +49,7 @@ static int dm_test_i2c_read_write(struct dm_test_state *dms)uint8_t buf[5 ];ut_assertok (uclass_get_device_by_seq (UCLASS_I2C , busnum, &bus)); -ut_assertok (i2c_get_chip (bus, chip, &dev)); +ut_assertok (i2c_get_chip (bus, chip,1 , &dev));ut_assertok (dm_i2c_read (dev,0 , buf,5 ));ut_assertok (memcmp (buf,"\0\0\0\0\0" ,sizeof (buf)));ut_assertok (dm_i2c_write (dev,2 , (uint8_t *)"AB" ,2 ));
@@ -66,7 +66,7 @@ static int dm_test_i2c_speed(struct dm_test_state *dms)uint8_t buf[5 ];ut_assertok (uclass_get_device_by_seq (UCLASS_I2C , busnum, &bus)); -ut_assertok (i2c_get_chip (bus, chip, &dev)); +ut_assertok (i2c_get_chip (bus, chip,1 , &dev));ut_assertok (i2c_set_bus_speed (bus,100000 ));ut_assertok (dm_i2c_read (dev,0 , buf,5 ));ut_assertok (i2c_set_bus_speed (bus,400000 ));
@@ -84,7 +84,7 @@ static int dm_test_i2c_offset_len(struct dm_test_state *dms)uint8_t buf[5 ];ut_assertok (uclass_get_device_by_seq (UCLASS_I2C , busnum, &bus)); -ut_assertok (i2c_get_chip (bus, chip, &dev)); +ut_assertok (i2c_get_chip (bus, chip,1 , &dev));ut_assertok (i2c_set_chip_offset_len (dev,1 ));ut_assertok (dm_i2c_read (dev,0 , buf,5 ));
@@ -113,7 +113,7 @@ static int dm_test_i2c_bytewise(struct dm_test_state *dms)uint8_t buf[5 ];ut_assertok (uclass_get_device_by_seq (UCLASS_I2C , busnum, &bus)); -ut_assertok (i2c_get_chip (bus, chip, &dev)); +ut_assertok (i2c_get_chip (bus, chip,1 , &dev));ut_assertok (dm_i2c_read (dev,0 , buf,5 ));ut_assertok (memcmp (buf,"\0\0\0\0\0" ,sizeof (buf)));
@@ -167,7 +167,7 @@ static int dm_test_i2c_offset(struct dm_test_state *dms)struct udevice *dev;uint8_t buf[5 ]; -ut_assertok (i2c_get_chip_for_busnum (busnum, chip, &dev)); +ut_assertok (i2c_get_chip_for_busnum (busnum, chip,1 , &dev));/* Do a transfer so we can find the emulator */ ut_assertok (dm_i2c_read (dev,0 , buf,5 ));
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 1/26 dm: i2c: Provide an offset length parameter where needed
Quoted 7 lines · Simon Glass
Rather than assuming that the chip offset length is 1, allow it to be provided. This allows chips that don't use the default offset length to be used (at present they are only supported by the command line 'i2c' command which sets the offset length explicitly).
Signed-off-by Simon Glass <[email protected]>Acked-by Heiko Schocher <[email protected]>
Applied to -u-boot-dm
PATCH v3 2/26 dm: Don't run tests if U-Boot cannot be built
In reply to Simon GlassThere is no point in running the tests if U-Boot cannot be built. Abort in this case.
---
Changes in v3: None
Changes in v2: None
test/dm/test-dm.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
test/dm/test-dm.sh +7 -2
@@ -1,9 +1,14 @@ #!/bin/sh +die() { + echo $1 + exit 1 +} + NUM_CPUS=$(cat /proc/cpuinfo |grep -c processor) dtc -I dts -O dtb test/dm/test.dts -o test/dm/test.dtb -make O=sandbox sandbox_config -make O=sandbox -s -j${NUM_CPUS} +make O=sandbox sandbox_config || die "Cannot configure U-Boot" +make O=sandbox -s -j${NUM_CPUS} || die "Cannot build U-Boot" dd if=/dev/zero of=spi.bin bs=1M count=2 ./sandbox/u-boot -d test/dm/test.dtb -c "dm test" rm spi.bin
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 2/26 dm: Don't run tests if U-Boot cannot be built
Quoted 11 lines · Simon Glass
There is no point in running the tests if U-Boot cannot be built. Abort in this case.
Signed-off-by Simon Glass <[email protected]>---
Changes in v3: None
Changes in v2: Nonetest/dm/test-dm.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
Applied to -u-boot-dm
PATCH v3 3/26 dm: core: Improve comments for uclass_first/next_device()
In reply to Simon GlassMention that the devices are probed ready for use.
---
Changes in v3: None
Changes in v2: None
include/dm/uclass.h | 4 ++++ 1 file changed, 4 insertions(+)
include/dm/uclass.h +4 -0
@@ -141,6 +141,8 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node,/** * uclass_first_device() - Get the first device in a uclass * +* The device returned is probed if necessary, and ready for use +* * @id: Uclass ID to look up * @devp: Returns pointer to the first device in that uclass, or NULL if none * @return 0 if OK (found or not found), -1 on error
@@ -150,6 +152,8 @@ int uclass_first_device(enum uclass_id id, struct udevice **devp);/** * uclass_next_device() - Get the next device in a uclass * +* The device returned is probed if necessary, and ready for use +* * @devp: On entry, pointer to device to lookup. On exit, returns pointer * to the next device in the same uclass, or NULL if none * @return 0 if OK (found or not found), -1 on error
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 3/26 dm: core: Improve comments for uclass_first/next_device()
Quoted 10 lines · Simon Glass
Mention that the devices are probed ready for use.
Signed-off-by Simon Glass <[email protected]>---
Changes in v3: None
Changes in v2: Noneinclude/dm/uclass.h | 4 ++++ 1 file changed, 4 insertions(+)
Applied to -u-boot-dm
PATCH v3 4/26 dm: core: Set device tree node for root device
In reply to Simon GlassThe root device corresponds to the root device tree node, so set this up. Also add a few notes to the documentation.
---
Changes in v3: None
Changes in v2: None
doc/driver-model/README.txt | 4 ++++ drivers/core/root.c | 3 +++ 2 files changed, 7 insertions(+)
doc/driver-model/README.txt +4 -0
@@ -363,6 +363,10 @@ can leave out platdata_auto_alloc_size. In this case you can use malloc in your ofdata_to_platdata (or probe) method to allocate the required memory, and you should free it in the remove method. +The driver model tree is intended to mirror that of the device tree. The +root driver is at device tree offset 0 (the root node, '/'), and its +children are the children of the root node. + Declaring Uclasses ------------------
drivers/core/root.c +3 -0
@@ -49,6 +49,9 @@ int dm_init(void) ret =device_bind_by_name (NULL , false, &root_info, &DM_ROOT_NON_CONST );if (ret)return ret; +#ifdef CONFIG_OF_CONTROL +DM_ROOT_NON_CONST ->of_offset =0 ; +#endif ret =device_probe (DM_ROOT_NON_CONST );if (ret)return ret;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 4/26 dm: core: Set device tree node for root device
Quoted 4 lines · Simon Glass
The root device corresponds to the root device tree node, so set this up. Also add a few notes to the documentation.
Signed-off-by Simon Glass <[email protected]>
Quoted 8 lines
---
Changes in v3: None
Changes in v2: Nonedoc/driver-model/README.txt | 4 ++++ drivers/core/root.c | 3 +++ 2 files changed, 7 insertions(+)
Applied to -u-boot-dm
PATCH v3 5/26 dm: core: Tidy up error handling in device_bind()
In reply to Simon GlassMake the error handling more standard to make it easier to build on top of it. Also correct a bug in the error path where there is no parent.
---
Changes in v3: None
Changes in v2: None
drivers/core/device.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
drivers/core/device.c +10 -8
@@ -81,18 +81,13 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name, ret =uclass_bind_device (dev);if (ret) - goto fail_bind; + goto fail_uclass_bind;/* if we fail to bind we remove device from successors and free it */ if (drv->bind) { ret = drv->bind (dev); -if (ret) { -if (uclass_unbind_device (dev)) { -dm_warn ("Failed to unbind dev '%s' on error path\n" , - dev->name); - } +if (ret) goto fail_bind; - } }if (parent)dm_dbg ("Bound device %s to %s\n" , dev->name, parent->name);
@@ -101,8 +96,15 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,return 0 ; fail_bind: -list_del (&dev->sibling_node); +if (uclass_unbind_device (dev)) { +dm_warn ("Failed to unbind dev '%s' on error path\n" , + dev->name); + } +fail_uclass_bind: +if (parent) +list_del (&dev->sibling_node);free (dev); +return ret; }
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 5/26 dm: core: Tidy up error handling in device_bind()
Quoted 5 lines · Simon Glass
Make the error handling more standard to make it easier to build on top of it. Also correct a bug in the error path where there is no parent.
Signed-off-by Simon Glass <[email protected]>Reviewed-by Masahiro Yamada <[email protected]>
Quoted 7 lines
---
Changes in v3: None
Changes in v2: Nonedrivers/core/device.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
Applied to -u-boot-dm
PATCH v3 6/26 dm: core: Allocate platform data when binding a device
In reply to Simon GlassWhen using allocated platform data, allocate it when we bind the device. This makes it possible to fill in this information before the device is probed.
This fits with the platform data model (when not using device tree), since platform data exists at bind-time.
---
Changes in v3:
- Fix stale comment in device_probe_child()
Changes in v2: None
drivers/core/device-remove.c | 8 ++++---- drivers/core/device.c | 22 +++++++++++++--------- test/dm/test-fdt.c | 4 ++-- 3 files changed, 19 insertions(+), 15 deletions(-)
drivers/core/device-remove.c +4 -4
@@ -88,6 +88,10 @@ int device_unbind(struct udevice *dev)if (ret)return ret; +if (dev->flags &DM_FLAG_ALLOC_PDATA ) { +free (dev->platdata); + dev->platdata =NULL ; + } ret =uclass_unbind_device (dev);if (ret)return ret;
@@ -111,10 +115,6 @@ void device_free(struct udevice *dev)free (dev->priv); dev->priv =NULL ; } -if (dev->flags &DM_FLAG_ALLOC_PDATA ) { -free (dev->platdata); - dev->platdata =NULL ; - } size = dev->uclass->uc_drv->per_device_auto_alloc_size;if (size) {free (dev->uclass_priv);
drivers/core/device.c +13 -9
@@ -72,8 +72,14 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,#else dev->req_seq =-1 ;#endif -if (!dev->platdata && drv->platdata_auto_alloc_size) +if (!dev->platdata && drv->platdata_auto_alloc_size) { dev->flags |=DM_FLAG_ALLOC_PDATA ; + dev->platdata =calloc (1 , drv->platdata_auto_alloc_size); +if (!dev->platdata) { + ret = -ENOMEM ; + goto fail_alloc1; + } + }/* put dev into parent's successor list */ if (parent)
@@ -103,6 +109,11 @@ fail_bind: fail_uclass_bind:if (parent)list_del (&dev->sibling_node); +if (dev->flags &DM_FLAG_ALLOC_PDATA ) { +free (dev->platdata); + dev->platdata =NULL ; + } +fail_alloc1:free (dev);return ret;
@@ -139,7 +150,7 @@ int device_probe_child(struct udevice *dev, void *parent_priv) drv = dev->driver;assert (drv); -/* Allocate private data and platdata if requested */ +/* Allocate private data if requested */ if (drv->priv_auto_alloc_size) { dev->priv =calloc (1 , drv->priv_auto_alloc_size);if (!dev->priv) {
@@ -148,13 +159,6 @@ int device_probe_child(struct udevice *dev, void *parent_priv) } }/* Allocate private data if requested */ -if (dev->flags &DM_FLAG_ALLOC_PDATA ) { - dev->platdata =calloc (1 , drv->platdata_auto_alloc_size); -if (!dev->platdata) { - ret = -ENOMEM ; - goto fail; - } - } size = dev->uclass->uc_drv->per_device_auto_alloc_size;if (size) { dev->uclass_priv =calloc (1 , size);
test/dm/test-fdt.c +2 -2
@@ -143,12 +143,12 @@ static int dm_test_fdt(struct dm_test_state *dms)/* These are num_devices compatible root-level device tree nodes */ ut_asserteq (num_devices,list_count_items (&uc->dev_head)); -/* Each should have no platdata / priv */ +/* Each should have platform data but no private data */ for (i =0 ; i < num_devices; i++) { ret =uclass_find_device (UCLASS_TEST_FDT , i, &dev);ut_assert (!ret);ut_assert (!dev_get_priv (dev)); -ut_assert (!dev->platdata); +ut_assert (dev->platdata); }ut_assertok (dm_check_devices (dms, num_devices));
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 6/26 dm: core: Allocate platform data when binding a device
Quoted 7 lines · On Sun, 25 Jan 2015 08:27:00 -0700 Simon Glass <[email protected]> wrote:
When using allocated platform data, allocate it when we bind the device. This makes it possible to fill in this information before the device is probed.
This fits with the platform data model (when not using device tree), since platform data exists at bind-time.
Quoted 7 lines
Signed-off-by Simon Glass <[email protected]>---
Changes in v3:
- Fix stale comment indevice_probe_child()Changes in v2: None
PATCH v3 6/26 dm: core: Allocate platform data when binding a device
Quoted 14 lines · Masahiro Yamada
Quoted 10 lines · On Sun, 25 Jan 2015 08:27:00 -0700 Simon Glass <[email protected]> wrote:
When using allocated platform data, allocate it when we bind the device. This makes it possible to fill in this information before the device is probed.
This fits with the platform data model (when not using device tree), since platform data exists at bind-time.
Signed-off-by Simon Glass <[email protected]>---
Quoted 9 lines
Quoted 4 lines
Changes in v3:
- Fix stale comment indevice_probe_child()Changes in v2: None
Reviewed-by Masahiro Yamada <[email protected]>
Applied to -u-boot-dm
PATCH v3 7/26 dm: core: Allow parents to have platform data for their children
In reply to Simon GlassFor buses it is common for parents to need to know the address of the child on the bus, the bus speed to use for that child, and other information. This can be provided in platform data attached to each child.
Add driver model support for this, including auto-allocation which can be requested using a new property to specify the size of the data.
---
Changes in v3:
- Remove unnecessary check that dev->parent_platdata is NULL
Changes in v2: None
drivers/core/device-remove.c | 4 +++ drivers/core/device.c | 30 ++++++++++++++-- include/dm/device.h | 19 +++++++++++ test/dm/bus.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 2 deletions(-)
drivers/core/device-remove.c +4 -0
@@ -92,6 +92,10 @@ int device_unbind(struct udevice *dev)free (dev->platdata); dev->platdata =NULL ; } +if (dev->flags &DM_FLAG_ALLOC_PARENT_PDATA ) { +free (dev->parent_platdata); + dev->parent_platdata =NULL ; + } ret =uclass_unbind_device (dev);if (ret)return ret;
drivers/core/device.c +28 -2
@@ -80,6 +80,18 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name, goto fail_alloc1; } } +if (parent) { +int size = parent->driver->per_child_platdata_auto_alloc_size; + +if (size) { + dev->flags |=DM_FLAG_ALLOC_PARENT_PDATA ; + dev->parent_platdata =calloc (1 , size); +if (!dev->parent_platdata) { + ret = -ENOMEM ; + goto fail_alloc2; + } + } + }/* put dev into parent's successor list */ if (parent)
@@ -107,8 +119,12 @@ fail_bind: dev->name); } fail_uclass_bind: -if (parent) -list_del (&dev->sibling_node); +list_del (&dev->sibling_node); +if (dev->flags &DM_FLAG_ALLOC_PARENT_PDATA ) { +free (dev->parent_platdata); + dev->parent_platdata =NULL ; + } +fail_alloc2:if (dev->flags &DM_FLAG_ALLOC_PDATA ) {free (dev->platdata); dev->platdata =NULL ;
@@ -247,6 +263,16 @@ void *dev_get_platdata(struct udevice *dev)return dev->platdata; } +void *dev_get_parent_platdata (struct udevice *dev) +{ +if (!dev) { +dm_warn ("%s: null device" , __func__); +return NULL ; + } + +return dev->parent_platdata; +} +void *dev_get_priv (struct udevice *dev) {if (!dev) {
include/dm/device.h +19 -0
@@ -26,6 +26,9 @@ struct driver_info;/* DM should init this device prior to relocation */ #define DM_FLAG_PRE_RELOC (1 << 2) +/* DM is responsible for allocating and freeing parent_platdata */ +#define DM_FLAG_ALLOC_PARENT_PDATA (1 << 3) +/** * struct udevice - An instance of a driver *
@@ -46,6 +49,7 @@ struct driver_info;* @driver: The driver used by this device * @name: Name of device, typically the FDT node name * @platdata: Configuration data for this device +* @parent_platdata: The parent bus's configuration data for this device * @of_offset: Device tree node offset for this device (- for none) * @of_id: Pointer to the udevice_id structure which created the device * @parent: Parent of this device, or NULL for the top level device
@@ -65,6 +69,7 @@ struct udevice {struct driver *driver;const char *name;void *platdata; +void *parent_platdata;int of_offset;const struct udevice_id *of_id;struct udevice *parent;
@@ -146,6 +151,9 @@ struct udevice_id {* device_probe_child() pass it in. So far the use case for allocating it * is SPI, but I found that unsatisfactory. Since it is here I will leave it * until things are clearer. +* @per_child_platdata_auto_alloc_size: A bus likes to store information about +* its children. If non-zero this is the size of this data, to be allocated +* in the child's parent_platdata pointer. * @ops: Driver-specific operations. This is typically a list of function * pointers defined by the driver, to implement driver functions required by * the uclass.
@@ -165,6 +173,7 @@ struct driver {int priv_auto_alloc_size;int platdata_auto_alloc_size;int per_child_auto_alloc_size; +int per_child_platdata_auto_alloc_size;const void *ops;/* driver-specific operations */ uint32_t flags; };
@@ -184,6 +193,16 @@ struct driver {void *dev_get_platdata (struct udevice *dev);/** +* dev_get_parent_platdata() - Get the parent platform data for a device +* +* This checks that dev is not NULL, but no other checks for now +* +* @dev Device to check +* @return parent's platform data, or NULL if none +*/ +void *dev_get_parent_platdata (struct udevice *dev); + +/** * dev_get_parentdata() - Get the parent data for a device * * The parent data is data stored in the device but owned by the parent.
test/dm/bus.c +81 -0
101 lines not on this page · raw message
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 7/26 dm: core: Allow parents to have platform data for their children
Quoted 8 lines · On Sun, 25 Jan 2015 08:27:01 -0700 Simon Glass <[email protected]> wrote:
For buses it is common for parents to need to know the address of the child on the bus, the bus speed to use for that child, and other information. This can be provided in platform data attached to each child.
Add driver model support for this, including auto-allocation which can be requested using a new property to specify the size of the data.
Signed-off-by Simon Glass <[email protected]>
PATCH v3 7/26 dm: core: Allow parents to have platform data for their children
Quoted 8 lines · Masahiro Yamada
Quoted 4 lines · On Sun, 25 Jan 2015 08:27:01 -0700 Simon Glass <[email protected]> wrote:
For buses it is common for parents to need to know the address of the child on the bus, the bus speed to use for that child, and other information. This can be provided in platform data attached to each child.
Quoted 9 lines
Quoted 4 lines
Add driver model support for this, including auto-allocation which can be requested using a new property to specify the size of the data.
Signed-off-by Simon Glass <[email protected]>Reviewed-by Masahiro Yamada <[email protected]>
Applied to -u-boot-dm
PATCH v3 8/26 dm: core: Allow uclasses to specify platdata for a device's children
In reply to Simon GlassIn many cases the child platform data for a device's children is defined by the uclass rather than the individual devices. For example, a SPI bus needs to know the chip select and speed for each of its children. It makes sense to allow this information to be defined the SPI uclass rather than each individual driver.
If the device provides a size value for its child platdata, then use it. Failng that, fall back to that provided by the uclass.
---
Changes in v3:
- Fix typo in commit subject
Changes in v2: None
drivers/core/device.c | 4 ++++ include/dm/uclass.h | 5 +++++ test/dm/bus.c | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-)
drivers/core/device.c +4 -0
@@ -83,6 +83,10 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,if (parent) {int size = parent->driver->per_child_platdata_auto_alloc_size; +if (!size) { + size = parent->uclass->uc_drv-> + per_child_platdata_auto_alloc_size; + }if (size) { dev->flags |=DM_FLAG_ALLOC_PARENT_PDATA ; dev->parent_platdata =calloc (1 , size);
include/dm/uclass.h +5 -0
@@ -60,6 +60,10 @@ struct udevice;* @per_device_auto_alloc_size: Each device can hold private data owned * by the uclass. If required this will be automatically allocated if this * value is non-zero. +* @per_child_platdata_auto_alloc_size: A bus likes to store information about +* its children. If non-zero this is the size of this data, to be allocated +* in the child device's parent_platdata pointer. This value is only used as +* a falback if this member is 0 in the driver. * @ops: Uclass operations, providing the consistent interface to devices * within the uclass. */
@@ -74,6 +78,7 @@ struct uclass_driver {int (*destroy)(struct uclass *class);int priv_auto_alloc_size;int per_device_auto_alloc_size; +int per_child_platdata_auto_alloc_size;const void *ops; };
test/dm/bus.c +30 -2
@@ -279,8 +279,7 @@ static int dm_test_bus_parent_ops(struct dm_test_state *dms) }DM_TEST (dm_test_bus_parent_ops,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT ); -/* Test that the bus can store platform data about each child */ -static int dm_test_bus_parent_platdata (struct dm_test_state *dms) +static int test_bus_parent_platdata (struct dm_test_state *dms) {struct dm_test_parent_platdata *plat;struct udevice *bus, *dev;
@@ -351,4 +350,33 @@ static int dm_test_bus_parent_platdata(struct dm_test_state *dms)return 0 ; } + +/* Test that the bus can store platform data about each child */ +static int dm_test_bus_parent_platdata (struct dm_test_state *dms) +{ +return test_bus_parent_platdata (dms); +}DM_TEST (dm_test_bus_parent_platdata,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT ); + +/* As above but the size is controlled by the uclass */ +static int dm_test_bus_parent_platdata_uclass (struct dm_test_state *dms) +{ +struct udevice *bus; +int size; +int ret; + +/* Set the driver size to 0 so that the uclass size is used */ +ut_assertok (uclass_find_device (UCLASS_TEST_BUS ,0 , &bus)); + size = bus->driver->per_child_platdata_auto_alloc_size; + bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = size; + bus->driver->per_child_platdata_auto_alloc_size =0 ; + ret =test_bus_parent_platdata (dms); +if (ret) +return ret; + bus->uclass->uc_drv->per_child_platdata_auto_alloc_size =0 ; + bus->driver->per_child_platdata_auto_alloc_size = size; + +return 0 ; +} +DM_TEST (dm_test_bus_parent_platdata_uclass, +DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT );
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 8/26 dm: core: Allow uclasses to specify platdata for a device's children
Quoted 11 lines · Simon Glass
In many cases the child platform data for a device's children is defined by the uclass rather than the individual devices. For example, a SPI bus needs to know the chip select and speed for each of its children. It makes sense to allow this information to be defined the SPI uclass rather than each individual driver.
If the device provides a size value for its child platdata, then use it. Failng that, fall back to that provided by the uclass.
Reviewed-by Masahiro Yamada <[email protected]>Signed-off-by Simon Glass <[email protected]>
Applied to -u-boot-dm
PATCH v3 9/26 dm: core: Add a post_bind method for parents
In reply to Simon GlassAllow parent drivers to be called when a new child is bound to them. This allows a bus to set up information it needs for that child.
---
Changes in v3: None
Changes in v2: None
drivers/core/device.c | 12 ++++++++++++ include/dm/device.h | 2 ++ test/dm/bus.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+)
drivers/core/device.c +12 -0
@@ -111,12 +111,24 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,if (ret) goto fail_bind; } +if (parent && parent->driver->child_post_bind) { + ret = parent->driver->child_post_bind (dev); +if (ret) + goto fail_child_post_bind; + } +if (parent)dm_dbg ("Bound device %s to %s\n" , dev->name, parent->name); *devp = dev;return 0 ; +fail_child_post_bind: +if (drv->unbind && drv->unbind (dev)) { +dm_warn ("unbind() method failed on dev '%s' on error path\n" , + dev->name); + } + fail_bind:if (uclass_unbind_device (dev)) { dm_warn("Failed to unbind dev '%s' on error path\n",
include/dm/device.h +2 -0
@@ -132,6 +132,7 @@ struct udevice_id {* @remove: Called to remove a device, i.e. de-activate it * @unbind: Called to unbind a device from its driver * @ofdata_to_platdata: Called before probe to decode device tree data +* @child_post_bind: Called after a new child has been bound * @child_pre_probe: Called before a child device is probed. The device has * memory allocated but it has not yet been probed. * @child_post_remove: Called after a child device is removed. The device
@@ -168,6 +169,7 @@ struct driver {int (*remove)(struct udevice *dev);int (*unbind)(struct udevice *dev);int (*ofdata_to_platdata)(struct udevice *dev); +int (*child_post_bind)(struct udevice *dev);int (*child_pre_probe)(struct udevice *dev);int (*child_post_remove)(struct udevice *dev);int priv_auto_alloc_size;
test/dm/bus.c +35 -0
@@ -17,6 +17,7 @@ DECLARE_GLOBAL_DATA_PTR;struct dm_test_parent_platdata {int count; +int bind_flag; };enum {
@@ -31,6 +32,16 @@ static int testbus_drv_probe(struct udevice *dev)return dm_scan_fdt_node (dev, gd->fdt_blob, dev->of_offset, false); } +static int testbus_child_post_bind (struct udevice *dev) +{ +struct dm_test_parent_platdata *plat; + + plat =dev_get_parent_platdata (dev); + plat->bind_flag =1 ; + +return 0 ; +} +static int testbus_child_pre_probe (struct udevice *dev) {struct dm_test_parent_data *parent_data =dev_get_parentdata (dev);
@@ -64,6 +75,7 @@ U_BOOT_DRIVER(testbus_drv) = { .of_match = testbus_ids, .id = UCLASS_TEST_BUS, .probe = testbus_drv_probe, + .child_post_bind = testbus_child_post_bind, .priv_auto_alloc_size = sizeof(struct dm_test_priv), .platdata_auto_alloc_size = sizeof(struct dm_test_pdata), .per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
@@ -380,3 +392,26 @@ static int dm_test_bus_parent_platdata_uclass(struct dm_test_state *dms) }DM_TEST (dm_test_bus_parent_platdata_uclass,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT ); + +/* Test that the child post_bind method is called */ +static int dm_test_bus_child_post_bind (struct dm_test_state *dms) +{ +struct dm_test_parent_platdata *plat; +struct udevice *bus, *dev; +int child_count; + +ut_assertok (uclass_get_device (UCLASS_TEST_BUS ,0 , &bus)); +for (device_find_first_child (bus, &dev), child_count =0 ; + dev; +device_find_next_child (&dev)) { +/* Check that platform data is allocated */ + plat =dev_get_parent_platdata (dev); +ut_assert (plat !=NULL ); +ut_asserteq (1 , plat->bind_flag); + child_count++; + } +ut_asserteq (3 , child_count); + +return 0 ; +} +DM_TEST (dm_test_bus_child_post_bind,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT );
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 9/26 dm: core: Add a post_bind method for parents
Quoted 7 lines · Simon Glass
Allow parent drivers to be called when a new child is bound to them. This allows a bus to set up information it needs for that child.
Signed-off-by Simon Glass <[email protected]>Reviewed-by Masahiro Yamada <[email protected]>---
Quoted 7 lines
Changes in v3: None
Changes in v2: Nonedrivers/core/device.c | 12 ++++++++++++ include/dm/device.h | 2 ++ test/dm/bus.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+)
Applied to -u-boot-dm
PATCH v3 10/26 dm: core: Add a function to get a device's uclass ID
In reply to Simon GlassThis is useful to check which uclass a device is in.
---
Changes in v3: None
Changes in v2: None
drivers/core/device.c | 5 +++++ include/dm/device.h | 8 ++++++++ test/dm/core.c | 11 +++++++++++ 3 files changed, 24 insertions(+)
drivers/core/device.c +5 -0
@@ -438,3 +438,8 @@ ulong dev_get_of_data(struct udevice *dev) {return dev->of_id->data; } + +enum uclass_id device_get_uclass_id (struct udevice *dev) +{ +return dev->uclass->uc_drv->id; +}
include/dm/device.h +8 -0
@@ -245,6 +245,14 @@ struct udevice *dev_get_parent(struct udevice *child);*/ ulong dev_get_of_data (struct udevice *dev); +/* +* device_get_uclass_id() - return the uclass ID of a device +* +* @dev: Device to check +* @return uclass ID for the device +*/ +enum uclass_id device_get_uclass_id (struct udevice *dev); +/** * device_get_child() - Get the child of a device by index *
test/dm/core.c +11 -0
@@ -598,3 +598,14 @@ static int dm_test_uclass_before_ready(struct dm_test_state *dms) }DM_TEST (dm_test_uclass_before_ready,0 ); + +static int dm_test_device_get_uclass_id (struct dm_test_state *dms) +{ +struct udevice *dev; + +ut_assertok (uclass_get_device (UCLASS_TEST ,0 , &dev)); +ut_asserteq (UCLASS_TEST ,device_get_uclass_id (dev)); + +return 0 ; +} +DM_TEST (dm_test_device_get_uclass_id,DM_TESTF_SCAN_PDATA );
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 10/26 dm: core: Add a function to get a device's uclass ID
Quoted 3 lines · On Sun, 25 Jan 2015 08:27:04 -0700 Simon Glass <[email protected]> wrote:
This is useful to check which uclass a device is in.
Signed-off-by Simon Glass <[email protected]>
PATCH v3 10/26 dm: core: Add a function to get a device's uclass ID
Quoted 11 lines · Masahiro Yamada
Quoted 3 lines · On Sun, 25 Jan 2015 08:27:04 -0700 Simon Glass <[email protected]> wrote:
This is useful to check which uclass a device is in.
Signed-off-by Simon Glass <[email protected]>Reviewed-by Masahiro Yamada <[email protected]>
Applied to -u-boot-dm
PATCH v3 11/26 dm: core: Add a flag to control sequence numbering
In reply to Simon GlassAt present we try to use the 'reg' property and device tree aliases to give devices a sequence number. The 'reg' property is often actually a memory address, so the sequence numbers thus-obtained are not useful. It would be better if the devices were just sequentially numbered in that case. In fact neither I2C nor SPI use this feature, so drop it.
Some devices need us to look up an alias to number them within the uclass. Add a flag to control this, so it is not done unless it is needed.
Adjust the tests to test this new behaviour.
---
Changes in v3:
- Fix comment to say 'node references' instead of 'phandles'
Changes in v2: None
doc/driver-model/README.txt | 51 +++++++++++------------------------------- drivers/core/device.c | 28 +++++++++++------------ drivers/i2c/i2c-uclass.c | 1 + drivers/serial/serial-uclass.c | 1 + drivers/spi/spi-uclass.c | 1 + include/dm/uclass.h | 5 +++++ test/dm/bus.c | 3 ++- test/dm/test-fdt.c | 9 ++++---- test/dm/test.dts | 16 +++++++++++++ 9 files changed, 57 insertions(+), 58 deletions(-)
doc/driver-model/README.txt +13 -38
@@ -388,12 +388,12 @@ Device Sequence Numbers U-Boot numbers devices from 0 in many situations, such as in the command line for I2C and SPI buses, and the device names for serial ports (serial0, serial1, ...). Driver model supports this numbering and permits devices -to be locating by their 'sequence'. This numbering unique identifies a +to be locating by their 'sequence'. This numbering uniquely identifies a device in its uclass, so no two devices within a particular uclass can have the same sequence number. Sequence numbers start from 0 but gaps are permitted. For example, a board -may have I2C buses 0, 1, 4, 5 but no 2 or 3. The choice of how devices are +may have I2C buses 1, 4, 5 but no 0, 2 or 3. The choice of how devices are numbered is up to a particular board, and may be set by the SoC in some cases. While it might be tempting to automatically renumber the devices where there are gaps in the sequence, this can lead to confusion and is
@@ -403,7 +403,7 @@ Each device can request a sequence number. If none is required then the device will be automatically allocated the next available sequence number. To specify the sequence number in the device tree an alias is typically -used. +used. Make sure that the uclass has the DM_UC_FLAG_SEQ_ALIAS flag set. aliases { serial2 = "/serial at 22230000";
@@ -413,43 +413,18 @@ This indicates that in the uclass called "serial", the named node ("/serial at 22230000") will be given sequence number 2. Any command or driver which requests serial device 2 will obtain this device. -Some devices represent buses where the devices on the bus are numbered or -addressed. For example, SPI typically numbers its slaves from 0, and I2C -uses a 7-bit address. In these cases the 'reg' property of the subnode is -used, for example: +More commonly you can use node references, which expand to the full path: -{ - aliases { - spi2 = "/spi at 22300000"; - }; - - spi at 22300000 { - #address-cells = <1>; - #size-cells = <1>; - spi-flash at 0 { - reg = <0>; - ... - } - eeprom at 1 { - reg = <1>; - }; - }; - -In this case we have a SPI bus with two slaves at 0 and 1. The SPI bus -itself is numbered 2. So we might access the SPI flash with: - - sf probe 2:0 - -and the eeprom with - - sspi 2:1 32 ef - -These commands simply need to look up the 2nd device in the SPI uclass to -find the right SPI bus. Then, they look at the children of that bus for the -right sequence number (0 or 1 in this case). +aliases { + serial2 = &serial_2; +}; +... +serial_2: serial at 22230000 { +... +}; -Typically the alias method is used for top-level nodes and the 'reg' method -is used only for buses. +The alias resolves to the same string in this case, but this version is +easier to read. Device sequence numbers are resolved when a device is probed. Before then the sequence number is only a request which may or may not be honoured,
drivers/core/device.c +13 -15
@@ -53,24 +53,22 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name, dev->driver = drv; dev->uclass = uc; -/* -* For some devices, such as a SPI or I2C bus, the 'reg' property -* is a reasonable indicator of the sequence number. But if there is -* an alias, we use that in preference. In any case, this is just -* a 'requested' sequence, and will be resolved (and ->seq updated) -* when the device is probed. -*/ dev->seq =-1 ; + dev->req_seq =-1 ;#ifdef CONFIG_OF_CONTROL - dev->req_seq =fdtdec_get_int (gd->fdt_blob, of_offset,"reg" ,-1 ); -if (!IS_ERR_VALUE (dev->req_seq)) - dev->req_seq &=INT_MAX ; -if (uc->uc_drv->name && of_offset !=-1 ) { -fdtdec_get_alias_seq (gd->fdt_blob, uc->uc_drv->name, of_offset, - &dev->req_seq); +/* +* Some devices, such as a SPI bus, I2C bus and serial ports are +* numbered using aliases. +* +* This is just a 'requested' sequence, and will be +* resolved (and ->seq updated) when the device is probed. +*/ +if (uc->uc_drv->flags &DM_UC_FLAG_SEQ_ALIAS ) { +if (uc->uc_drv->name && of_offset !=-1 ) { +fdtdec_get_alias_seq (gd->fdt_blob, uc->uc_drv->name, + of_offset, &dev->req_seq); + } } -#else - dev->req_seq =-1 ;#endif if (!dev->platdata && drv->platdata_auto_alloc_size) { dev->flags |=DM_FLAG_ALLOC_PDATA ;
drivers/i2c/i2c-uclass.c +1 -0
@@ -453,6 +453,7 @@ int i2c_post_bind(struct udevice *dev)UCLASS_DRIVER (i2c) = { .id =UCLASS_I2C , .name ="i2c" , + .flags =DM_UC_FLAG_SEQ_ALIAS , .per_device_auto_alloc_size =sizeof (struct dm_i2c_bus ), .post_bind = i2c_post_bind, .post_probe = i2c_post_probe,
drivers/serial/serial-uclass.c +1 -0
@@ -297,6 +297,7 @@ static int serial_pre_remove(struct udevice *dev)UCLASS_DRIVER (serial) = { .id =UCLASS_SERIAL , .name ="serial" , + .flags =DM_UC_FLAG_SEQ_ALIAS , .post_probe = serial_post_probe, .pre_remove = serial_pre_remove, .per_device_auto_alloc_size =sizeof (struct serial_dev_priv ),
drivers/spi/spi-uclass.c +1 -0
@@ -344,6 +344,7 @@ int spi_ofdata_to_platdata(const void *blob, int node,UCLASS_DRIVER (spi) = { .id =UCLASS_SPI , .name ="spi" , + .flags =DM_UC_FLAG_SEQ_ALIAS , .post_bind = spi_post_bind, .post_probe = spi_post_probe, .per_device_auto_alloc_size =sizeof (struct dm_spi_bus ),
include/dm/uclass.h +5 -0
@@ -40,6 +40,9 @@ struct uclass {struct udevice ; +/* Members of this uclass sequence themselves with aliases */ +#define DM_UC_FLAG_SEQ_ALIAS (1 << 0) +/** * struct uclass_driver - Driver for the uclass *
@@ -66,6 +69,7 @@ struct udevice;* a falback if this member is 0 in the driver. * @ops: Uclass operations, providing the consistent interface to devices * within the uclass. +* @flags: Flags for this uclass (DM_UC_...) */ struct uclass_driver {const char *name;
@@ -80,6 +84,7 @@ struct uclass_driver {int per_device_auto_alloc_size;int per_child_platdata_auto_alloc_size;const void *ops; +uint32_t flags; };/* Declare a new uclass_driver */
test/dm/bus.c +2 -1
@@ -88,12 +88,13 @@ U_BOOT_DRIVER(testbus_drv) = {UCLASS_DRIVER (testbus) = { .name ="testbus" , .id =UCLASS_TEST_BUS , + .flags =DM_UC_FLAG_SEQ_ALIAS , };/* Test that we can probe for children */ static int dm_test_bus_children (struct dm_test_state *dms) { -int num_devices =4 ; +int num_devices =6 ;struct udevice *bus;struct uclass *uc;
test/dm/test-fdt.c +5 -4
@@ -89,6 +89,7 @@ int testfdt_ping(struct udevice *dev, int pingval, int *pingret)UCLASS_DRIVER (testfdt) = { .name ="testfdt" , .id =UCLASS_TEST_FDT , + .flags =DM_UC_FLAG_SEQ_ALIAS , };int dm_check_devices (struct dm_test_state *dms,int num_devices)
@@ -128,7 +129,7 @@ int dm_check_devices(struct dm_test_state *dms, int num_devices)/* Test that FDT-based binding works correctly */ static int dm_test_fdt (struct dm_test_state *dms) { -const int num_devices =4 ; +const int num_devices =6 ;struct udevice *dev;struct uclass *uc;int ret;
@@ -184,7 +185,7 @@ static int dm_test_fdt_uclass_seq(struct dm_test_state *dms)ut_assertok (uclass_find_device_by_seq (UCLASS_TEST_FDT ,3 , true, &dev));ut_asserteq_str ("b-test" , dev->name); -ut_assertok (uclass_find_device_by_seq (UCLASS_TEST_FDT ,0 , true, &dev)); +ut_assertok (uclass_find_device_by_seq (UCLASS_TEST_FDT ,8 , true, &dev));ut_asserteq_str ("a-test" , dev->name); ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 5,
@@ -220,11 +221,11 @@ static int dm_test_fdt_uclass_seq(struct dm_test_state *dms)ut_asserteq (-ENODEV ,uclass_get_device_by_seq (UCLASS_TEST_FDT ,1 , &dev));ut_assertok (uclass_get_device (UCLASS_TEST_FDT ,0 , &dev)); -ut_assertok (uclass_get_device (UCLASS_TEST_FDT ,1 , &dev)); +ut_assertok (uclass_get_device (UCLASS_TEST_FDT ,4 , &dev));/* But now that it is probed, we can find it */ ut_assertok (uclass_get_device_by_seq (UCLASS_TEST_FDT ,1 , &dev)); -ut_asserteq_str ("a-test" , dev->name); +ut_asserteq_str ("f-test" , dev->name);return 0 ; }
test/dm/test.dts +16 -0
@@ -8,7 +8,15 @@ aliases { console = &uart0; + i2c0 = "/i2c at 0"; + spi0 = "/spi at 0"; testfdt6 = "/e-test"; + testbus3 = "/some-bus"; + testfdt0 = "/some-bus/c-test at 0"; + testfdt1 = "/some-bus/c-test at 1"; + testfdt3 = "/b-test"; + testfdt5 = "/some-bus/c-test at 5"; + testfdt8 = "/a-test"; }; uart0: serial {
@@ -86,6 +94,14 @@ compatible = "google,another-fdt-test"; }; + f-test { + compatible = "denx,u-boot-fdt-test"; + }; + + g-test { + compatible = "denx,u-boot-fdt-test"; + }; + gpio_a: base-gpios { compatible = "sandbox,gpio"; gpio-controller;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 11/26 dm: core: Add a flag to control sequence numbering
Quoted 6 lines · Simon Glass
At present we try to use the 'reg' property and device tree aliases to give devices a sequence number. The 'reg' property is often actually a memory address, so the sequence numbers thus-obtained are not useful. It would be better if the devices were just sequentially numbered in that case. In fact neither I2C nor SPI use this feature, so drop it.
Quoted 7 lines
Some devices need us to look up an alias to number them within the uclass. Add a flag to control this, so it is not done unless it is needed.
Adjust the tests to test this new behaviour.
Signed-off-by Simon Glass <[email protected]>Reviewed-by Masahiro Yamada <[email protected]>
Applied to -u-boot-dm
PATCH v3 12/26 dm: core: Allow uclasses to specify private data for a device's children
In reply to Simon GlassIn many cases the per-child private data for a device's children is defined by the uclass rather than the individual driver. For example, a SPI bus needs to store information about each of its children, but all SPI drivers store the same information. It makes sense to allow the uclass to define this data.
If the driver provides a size value for its per-child private data, then use it. Failng that, fall back to that provided by the uclass.
---
Changes in v3:
- Fix typo in commit subject
Changes in v2: None
drivers/core/device-remove.c | 4 ++++ drivers/core/device.c | 4 ++++ include/dm/uclass.h | 4 ++++ test/dm/bus.c | 31 +++++++++++++++++++++++++++++-- 4 files changed, 41 insertions(+), 2 deletions(-)
drivers/core/device-remove.c +4 -0
@@ -126,6 +126,10 @@ void device_free(struct udevice *dev) }if (dev->parent) { size = dev->parent->driver->per_child_auto_alloc_size; +if (!size) { + size = dev->parent->uclass->uc_drv-> + per_child_auto_alloc_size; + }if (size) {free (dev->parent_priv); dev->parent_priv =NULL ;
drivers/core/device.c +4 -0
@@ -201,6 +201,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv)/* Ensure all parents are probed */ if (dev->parent) { size = dev->parent->driver->per_child_auto_alloc_size; +if (!size) { + size = dev->parent->uclass->uc_drv-> + per_child_auto_alloc_size; + }if (size) { dev->parent_priv =calloc (1 , size);if (!dev->parent_priv) {
include/dm/uclass.h +4 -0
@@ -63,6 +63,9 @@ struct udevice;* @per_device_auto_alloc_size: Each device can hold private data owned * by the uclass. If required this will be automatically allocated if this * value is non-zero. +* @per_child_auto_alloc_size: Each child device (of a parent in this +* uclass) can hold parent data for the device/uclass. This value is only +* used as a falback if this member is 0 in the driver. * @per_child_platdata_auto_alloc_size: A bus likes to store information about * its children. If non-zero this is the size of this data, to be allocated * in the child device's parent_platdata pointer. This value is only used as
@@ -82,6 +85,7 @@ struct uclass_driver {int (*destroy)(struct uclass *class);int priv_auto_alloc_size;int per_device_auto_alloc_size; +int per_child_auto_alloc_size;int per_child_platdata_auto_alloc_size;const void *ops;uint32_t flags;
test/dm/bus.c +29 -2
@@ -192,7 +192,7 @@ DM_TEST(dm_test_bus_children_iterators, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);/* Test that the bus can store data about each child */ -static int dm_test_bus_parent_data (struct dm_test_state *dms) +static int test_bus_parent_data (struct dm_test_state *dms) {struct dm_test_parent_data *parent_data;struct udevice *bus, *dev;
@@ -251,9 +251,36 @@ static int dm_test_bus_parent_data(struct dm_test_state *dms)return 0 ; } - +/* Test that the bus can store data about each child */ +static int dm_test_bus_parent_data (struct dm_test_state *dms) +{ +return test_bus_parent_data (dms); +}DM_TEST (dm_test_bus_parent_data,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT ); +/* As above but the size is controlled by the uclass */ +static int dm_test_bus_parent_data_uclass (struct dm_test_state *dms) +{ +struct udevice *bus; +int size; +int ret; + +/* Set the driver size to 0 so that the uclass size is used */ +ut_assertok (uclass_find_device (UCLASS_TEST_BUS ,0 , &bus)); + size = bus->driver->per_child_auto_alloc_size; + bus->uclass->uc_drv->per_child_auto_alloc_size = size; + bus->driver->per_child_auto_alloc_size =0 ; + ret =test_bus_parent_data (dms); +if (ret) +return ret; + bus->uclass->uc_drv->per_child_auto_alloc_size =0 ; + bus->driver->per_child_auto_alloc_size = size; + +return 0 ; +} +DM_TEST (dm_test_bus_parent_data_uclass, +DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT ); +/* Test that the bus ops are called when a child is probed/removed */ static int dm_test_bus_parent_ops (struct dm_test_state *dms) {
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 12/26 dm: core: Allow uclasses to specify private data for a device's children
Quoted 9 lines · On Sun, 25 Jan 2015 08:27:06 -0700 Simon Glass <[email protected]> wrote:
In many cases the per-child private data for a device's children is defined by the uclass rather than the individual driver. For example, a SPI bus needs to store information about each of its children, but all SPI drivers store the same information. It makes sense to allow the uclass to define this data.
If the driver provides a size value for its per-child private data, then use it. Failng that, fall back to that provided by the uclass.
Quoted 7 lines
Signed-off-by Simon Glass <[email protected]>---
Changes in v3:
- Fix typo in commit subjectChanges in v2: None
PATCH v3 12/26 dm: core: Allow uclasses to specify private data for a device's children
Quoted 16 lines · Masahiro Yamada
Quoted 12 lines · On Sun, 25 Jan 2015 08:27:06 -0700 Simon Glass <[email protected]> wrote:
In many cases the per-child private data for a device's children is defined by the uclass rather than the individual driver. For example, a SPI bus needs to store information about each of its children, but all SPI drivers store the same information. It makes sense to allow the uclass to define this data.
If the driver provides a size value for its per-child private data, then use it. Failng that, fall back to that provided by the uclass.
Signed-off-by Simon Glass <[email protected]>---
Quoted 9 lines
Quoted 4 lines
Changes in v3:
- Fix typo in commit subjectChanges in v2: None
Reviewed-by Masahiro Yamada <[email protected]>
Applied to -u-boot-dm
PATCH v3 13/26 dm: spi: Move the per-child data size to the uclass
In reply to Simon GlassThis is common to all SPI drivers and specifies a structure used by the uclass. It makes more sense to define it in the uclass.
---
Changes in v3: None
Changes in v2: None
drivers/spi/cadence_qspi.c | 1 - drivers/spi/designware_spi.c | 1 - drivers/spi/exynos_spi.c | 1 - drivers/spi/sandbox_spi.c | 1 - drivers/spi/soft_spi.c | 1 - drivers/spi/spi-uclass.c | 1 + drivers/spi/tegra114_spi.c | 1 - drivers/spi/tegra20_sflash.c | 1 - drivers/spi/tegra20_slink.c | 1 - 9 files changed, 1 insertion(+), 8 deletions(-)
drivers/spi/cadence_qspi.c +0 -1
@@ -340,6 +340,5 @@ U_BOOT_DRIVER(cadence_spi) = { .ofdata_to_platdata = cadence_spi_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct cadence_spi_platdata), .priv_auto_alloc_size = sizeof(struct cadence_spi_priv), - .per_child_auto_alloc_size = sizeof(struct spi_slave), .probe = cadence_spi_probe, };
drivers/spi/designware_spi.c +0 -1
@@ -421,6 +421,5 @@ U_BOOT_DRIVER(dw_spi) = { .ofdata_to_platdata = dw_spi_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct dw_spi_platdata), .priv_auto_alloc_size = sizeof(struct dw_spi_priv), - .per_child_auto_alloc_size = sizeof(struct spi_slave), .probe = dw_spi_probe, };
drivers/spi/exynos_spi.c +0 -1
@@ -425,6 +425,5 @@ U_BOOT_DRIVER(exynos_spi) = { .ofdata_to_platdata = exynos_spi_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata), .priv_auto_alloc_size = sizeof(struct exynos_spi_priv), - .per_child_auto_alloc_size = sizeof(struct spi_slave), .probe = exynos_spi_probe, };
drivers/spi/sandbox_spi.c +0 -1
@@ -160,6 +160,5 @@ U_BOOT_DRIVER(spi_sandbox) = { .name = "spi_sandbox", .id = UCLASS_SPI, .of_match = sandbox_spi_ids, - .per_child_auto_alloc_size = sizeof(struct spi_slave), .ops = &sandbox_spi_ops, };
drivers/spi/soft_spi.c +0 -1
@@ -240,7 +240,6 @@ U_BOOT_DRIVER(soft_spi) = { .ofdata_to_platdata = soft_spi_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct soft_spi_platdata), .priv_auto_alloc_size = sizeof(struct soft_spi_priv), - .per_child_auto_alloc_size = sizeof(struct spi_slave), .probe = soft_spi_probe, .child_pre_probe = soft_spi_child_pre_probe, };
drivers/spi/spi-uclass.c +1 -0
@@ -348,6 +348,7 @@ UCLASS_DRIVER(spi) = { .post_bind = spi_post_bind, .post_probe = spi_post_probe, .per_device_auto_alloc_size = sizeof(struct dm_spi_bus), + .per_child_auto_alloc_size = sizeof(struct spi_slave), };UCLASS_DRIVER (spi_generic) = {
drivers/spi/tegra114_spi.c +0 -1
@@ -407,6 +407,5 @@ U_BOOT_DRIVER(tegra114_spi) = { .ofdata_to_platdata = tegra114_spi_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata), .priv_auto_alloc_size = sizeof(struct tegra114_spi_priv), - .per_child_auto_alloc_size = sizeof(struct spi_slave), .probe = tegra114_spi_probe, };
drivers/spi/tegra20_sflash.c +0 -1
@@ -348,6 +348,5 @@ U_BOOT_DRIVER(tegra20_sflash) = { .ofdata_to_platdata = tegra20_sflash_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata), .priv_auto_alloc_size = sizeof(struct tegra20_sflash_priv), - .per_child_auto_alloc_size = sizeof(struct spi_slave), .probe = tegra20_sflash_probe, };
drivers/spi/tegra20_slink.c +0 -1
@@ -361,6 +361,5 @@ U_BOOT_DRIVER(tegra30_spi) = { .ofdata_to_platdata = tegra30_spi_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata), .priv_auto_alloc_size = sizeof(struct tegra30_spi_priv), - .per_child_auto_alloc_size = sizeof(struct spi_slave), .probe = tegra30_spi_probe, };
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 13/26 dm: spi: Move the per-child data size to the uclass
Quoted 10 lines · Simon Glass
This is common to all SPI drivers and specifies a structure used by the uclass. It makes more sense to define it in the uclass.
Reviewed-by Masahiro Yamada <[email protected]>Signed-off-by Simon Glass <[email protected]>---
Changes in v3: None
Changes in v2: None
Quoted 10 lines
drivers/spi/cadence_qspi.c | 1 - drivers/spi/designware_spi.c | 1 - drivers/spi/exynos_spi.c | 1 - drivers/spi/sandbox_spi.c | 1 - drivers/spi/soft_spi.c | 1 - drivers/spi/spi-uclass.c | 1 + drivers/spi/tegra114_spi.c | 1 - drivers/spi/tegra20_sflash.c | 1 - drivers/spi/tegra20_slink.c | 1 - 9 files changed, 1 insertion(+), 8 deletions(-)
Applied to -u-boot-dm
PATCH v3 14/26 dm: core: Allow the uclass to set up a device's child after binding
In reply to Simon GlassFor buses, after a child is bound, allow the uclass to perform some processing. This can be used to figure out the address of the child (e.g. the chip select for SPI slaves) so that it is ready to be probed.
This avoids bus drivers having to repeat the same process, which really should be done by the uclass, since it is common.
---
Changes in v3:
- Change variable name from parent_drv to uc_drv
Changes in v2: None
drivers/core/uclass.c | 21 ++++++++++++++++----- include/dm/uclass.h | 2 ++ test/dm/bus.c | 26 ++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-)
drivers/core/uclass.c +16 -5
@@ -319,18 +319,29 @@ int uclass_bind_device(struct udevice *dev)int ret; uc = dev->uclass; -list_add_tail (&dev->uclass_node, &uc->dev_head); +if (dev->parent) { +struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv; + +if (uc_drv->child_post_bind) { + ret = uc_drv->child_post_bind (dev); +if (ret) + goto err; + } + }if (uc->uc_drv->post_bind) { ret = uc->uc_drv->post_bind (dev); -if (ret) { -list_del (&dev->uclass_node); -return ret; - } +if (ret) + goto err; }return 0 ; +err: +/* There is no need to undo the parent's post_bind call */ +list_del (&dev->uclass_node); + +return ret; }int uclass_unbind_device (struct udevice *dev)
include/dm/uclass.h +2 -0
@@ -55,6 +55,7 @@ struct udevice;* @pre_unbind: Called before a device is unbound from this uclass * @post_probe: Called after a new device is probed * @pre_remove: Called before a device is removed +* @child_post_bind: Called after a child is bound to a device in this uclass * @init: Called to set up the uclass * @destroy: Called to destroy the uclass * @priv_auto_alloc_size: If non-zero this is the size of the private data
@@ -81,6 +82,7 @@ struct uclass_driver {int (*pre_unbind)(struct udevice *dev);int (*post_probe)(struct udevice *dev);int (*pre_remove)(struct udevice *dev); +int (*child_post_bind)(struct udevice *dev);int (*init)(struct uclass *class);int (*destroy)(struct uclass *class);int priv_auto_alloc_size;
test/dm/bus.c +26 -0
@@ -18,6 +18,7 @@ DECLARE_GLOBAL_DATA_PTR;struct dm_test_parent_platdata {int count;int bind_flag; +int uclass_bind_flag; };enum {
@@ -38,6 +39,7 @@ static int testbus_child_post_bind(struct udevice *dev) plat =dev_get_parent_platdata (dev); plat->bind_flag =1 ; + plat->uclass_bind_flag =2 ;return 0 ; }
@@ -443,3 +445,27 @@ static int dm_test_bus_child_post_bind(struct dm_test_state *dms)return 0 ; }DM_TEST (dm_test_bus_child_post_bind,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT ); + +/* Test that the child post_bind method is called */ +static int dm_test_bus_child_post_bind_uclass (struct dm_test_state *dms) +{ +struct dm_test_parent_platdata *plat; +struct udevice *bus, *dev; +int child_count; + +ut_assertok (uclass_get_device (UCLASS_TEST_BUS ,0 , &bus)); +for (device_find_first_child (bus, &dev), child_count =0 ; + dev; +device_find_next_child (&dev)) { +/* Check that platform data is allocated */ + plat =dev_get_parent_platdata (dev); +ut_assert (plat !=NULL ); +ut_asserteq (2 , plat->uclass_bind_flag); + child_count++; + } +ut_asserteq (3 , child_count); + +return 0 ; +} +DM_TEST (dm_test_bus_child_post_bind_uclass, +DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT );
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 14/26 dm: core: Allow the uclass to set up a device's child after binding
Quoted 14 lines · Simon Glass
For buses, after a child is bound, allow the uclass to perform some processing. This can be used to figure out the address of the child (e.g. the chip select for SPI slaves) so that it is ready to be probed.
This avoids bus drivers having to repeat the same process, which really should be done by the uclass, since it is common.
Signed-off-by Simon Glass <[email protected]>Reviewed-by Masahiro Yamada <[email protected]>---
Changes in v3:
- Change variable name fromparent_drvtouc_drv
Quoted 6 lines
Changes in v2: None
drivers/core/uclass.c | 21 ++++++++++++++++----- include/dm/uclass.h | 2 ++ test/dm/bus.c | 26 ++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-)
Applied to -u-boot-dm
PATCH v3 15/26 dm: sandbox: sf: Tidy up the error handling in sandbox_sf_probe()
In reply to Simon GlassUse a single exit point when we have an error and add debugging there.
---
Changes in v3: None
Changes in v2: None
drivers/mtd/spi/sandbox.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/mtd/spi/sandbox.c +5 -2
@@ -141,8 +141,10 @@ static int sandbox_sf_probe(struct udevice *dev)assert (bus->seq !=-1 );if (bus->seq <CONFIG_SANDBOX_SPI_MAX_BUS ) spec = state->spi[bus->seq][cs].spec; -if (!spec) -return -ENOENT ; +if (!spec) { + ret = -ENOENT ; + goto error; + } file =strchr (spec,':' );if (!file) {
@@ -196,6 +198,7 @@ static int sandbox_sf_probe(struct udevice *dev)return 0 ; error: +debug ("%s: Got error %d\n" , __func__, ret);return ret; }
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 15/26 dm: sandbox: sf: Tidy up the error handling in sandbox_sf_probe()
Quoted 10 lines · Simon Glass
Use a single exit point when we have an error and add debugging there.
Signed-off-by Simon Glass <[email protected]>---
Changes in v3: None
Changes in v2: Nonedrivers/mtd/spi/sandbox.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
Applied to -u-boot-dm
PATCH v3 16/26 dm: core: Allow uclass to set up a device's child before it is probed
In reply to Simon GlassSome buses need to set up their devices before they can be used. This setup may well be common to all buses in a particular uclass. Support a common pre-probe method for the uclass, called before any bus devices are probed.
---
Changes in v3: None
Changes in v2: None
drivers/core/device.c | 4 ++++ drivers/core/uclass.c | 13 +++++++++++++ include/dm/test.h | 3 +++ include/dm/uclass-internal.h | 11 +++++++++++ include/dm/uclass.h | 1 + test/dm/bus.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ test/dm/test-fdt.c | 7 +++++++ 7 files changed, 85 insertions(+)
drivers/core/device.c +4 -0
@@ -227,6 +227,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv) } dev->seq = seq; + ret =uclass_pre_probe_child (dev); +if (ret) + goto fail; +if (dev->parent && dev->parent->driver->child_pre_probe) { ret = dev->parent->driver->child_pre_probe (dev);if (ret)
drivers/core/uclass.c +13 -0
@@ -391,6 +391,19 @@ int uclass_resolve_seq(struct udevice *dev)return seq; } +int uclass_pre_probe_child (struct udevice *dev) +{ +struct uclass_driver *uc_drv; + +if (!dev->parent) +return 0 ; + uc_drv = dev->parent->uclass->uc_drv; +if (uc_drv->child_pre_probe) +return uc_drv->child_pre_probe (dev); + +return 0 ; +} +int uclass_post_probe_device (struct udevice *dev) {struct uclass_driver *uc_drv = dev->uclass->uc_drv;
include/dm/test.h +3 -0
@@ -67,6 +67,8 @@ enum {struct dm_test_priv {int ping_total;int op_count[DM_TEST_OP_COUNT ]; +int uclass_flag; +int uclass_total; };/**
@@ -88,6 +90,7 @@ struct dm_test_uclass_priv {* * @sum: Test value used to check parent data works correctly * @flag: Used to track calling of parent operations +* @uclass_flag: Used to track calling of parent operations by uclass */ struct dm_test_parent_data {int sum;
include/dm/uclass-internal.h +11 -0
@@ -44,6 +44,17 @@ int uclass_bind_device(struct udevice *dev);int uclass_unbind_device (struct udevice *dev);/** +* uclass_pre_probe_child() - Deal with a child that is about to be probed +* +* Perform any pre-processing that is needed by the uclass before it can be +* probed. +* +* @dev: Pointer to the device +* #return 0 on success, -ve on error +*/ +int uclass_pre_probe_child (struct udevice *dev); + +/** * uclass_post_probe_device() - Deal with a device that has just been probed * * Perform any post-processing of a probed device that is needed by the
include/dm/uclass.h +1 -0
@@ -83,6 +83,7 @@ struct uclass_driver {int (*post_probe)(struct udevice *dev);int (*pre_remove)(struct udevice *dev);int (*child_post_bind)(struct udevice *dev); +int (*child_pre_probe)(struct udevice *dev);int (*init)(struct uclass *class);int (*destroy)(struct uclass *class);int priv_auto_alloc_size;
test/dm/bus.c +46 -0
61 lines not on this page · raw message
test/dm/test-fdt.c +7 -0
@@ -51,6 +51,13 @@ static int testfdt_drv_probe(struct udevice *dev) priv->ping_total +=DM_TEST_START_TOTAL ; +/* +* If this device is on a bus, the uclass_flag will be set before +* calling this function. This is used by +* dm_test_bus_child_pre_probe_uclass(). +*/ + priv->uclass_total += priv->uclass_flag; +return 0 ; }
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 16/26 dm: core: Allow uclass to set up a device's child before it is probed
Quoted 6 lines · Simon Glass
Some buses need to set up their devices before they can be used. This setup may well be common to all buses in a particular uclass. Support a common pre-probe method for the uclass, called before any bus devices are probed.
Signed-off-by Simon Glass <[email protected]>Reviewed-by Masahiro Yamada <[email protected]>
Applied to -u-boot-dm
PATCH v3 17/26 dm: spi: Set up the spi_slave device pointer in child_pre_probe()
In reply to Simon GlassAt present we use struct spi_slave as our device pointer in a lot of places to avoid changing the old SPI API. At some point this will go away.
But for now, it is better if the SPI uclass sets up this pointer, rather than relying on passing it into the device when it is probed. We can use the new uclass child_pre_probe() method to do this.
---
Changes in v3: None
Changes in v2: None
drivers/spi/spi-uclass.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/spi/spi-uclass.c +10 -0
@@ -108,6 +108,15 @@ int spi_post_probe(struct udevice *dev)return 0 ; } +int spi_child_pre_probe (struct udevice *dev) +{ +struct spi_slave *slave =dev_get_parentdata (dev); + + slave->dev = dev; + +return 0 ; +} +int spi_chip_select (struct udevice *dev) {struct spi_slave *slave =dev_get_parentdata (dev);
@@ -347,6 +356,7 @@ UCLASS_DRIVER(spi) = { .flags = DM_UC_FLAG_SEQ_ALIAS, .post_bind = spi_post_bind, .post_probe = spi_post_probe, + .child_pre_probe = spi_child_pre_probe, .per_device_auto_alloc_size = sizeof(struct dm_spi_bus), .per_child_auto_alloc_size = sizeof(struct spi_slave), };
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 17/26 dm: spi: Set up the spi_slave device pointer in child_pre_probe()
Quoted 8 lines · Simon Glass
At present we use struct
spi_slaveas our device pointer in a lot of places to avoid changing the old SPI API. At some point this will go away.But for now, it is better if the SPI uclass sets up this pointer, rather than relying on passing it into the device when it is probed. We can use the new uclass
child_pre_probe()method to do this.Signed-off-by Simon Glass <[email protected]>
Applied to -u-boot-dm
PATCH v3 18/26 dm: spi: Move slave details to child platdata
In reply to Simon GlassAt present we go through various contortions to store the SPI slave's chip select in its private data. This only exists when the slave is active so must be set up when it is probed. Until the device is probed we don't actually know what chip select it will appear on.
However, now that we can support per-child platform data, we can use that instead. This allows us to set up the chip select when the child is bound, and avoid the messy contortions.
Unfortunately this is a fairly large change and it seems to be difficult to break it down further.
---
Changes in v3: None
Changes in v2:
- Add a TODO to remove struct dm_spi_bus
- Add additional comments to spi.h
- Copy max_hz and mode from platdata to spi_slave when probing
- Tidy up soft_spi driver also
drivers/misc/cros_ec_spi.c | 19 ----------- drivers/mtd/spi/sandbox.c | 5 +++ drivers/mtd/spi/sf_probe.c | 3 +- drivers/spi/soft_spi.c | 9 ----- drivers/spi/spi-uclass.c | 83 +++++++++++++++++++++++++++------------------- include/spi.h | 42 +++++++++++++++++------ test/dm/spi.c | 6 ++-- 7 files changed, 91 insertions(+), 76 deletions(-)
drivers/misc/cros_ec_spi.c +0 -19
@@ -202,25 +202,6 @@ int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)#ifdef CONFIG_DM_CROS_EC int cros_ec_probe (struct udevice *dev) { -struct spi_slave *slave =dev_get_parentdata (dev); -int ret; - -/* -* TODO(sjg at chromium.org) -* -* This is really horrible at present. It is an artifact of removing -* the child_pre_probe() method for SPI. Everything here could go in -* an automatic function, except that spi_get_bus_and_cs() wants to -* set it up manually and call device_probe_child(). -* -* The solution may be to re-enable the child_pre_probe() method for -* SPI and have it do nothing if the child is already passed in via -* device_probe_child(). -*/ - slave->dev = dev; - ret =spi_ofdata_to_platdata (gd->fdt_blob, dev->of_offset, slave); -if (ret) -return ret;return cros_ec_register (dev); }
drivers/mtd/spi/sandbox.c +5 -0
@@ -590,6 +590,11 @@ int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs,void sandbox_sf_unbind_emul (struct sandbox_state *state,int busnum,int cs) { +struct udevice *dev; + + dev = state->spi[busnum][cs].emul; +device_remove (dev); +device_unbind (dev); state->spi[busnum][cs].emul =NULL ; }
drivers/mtd/spi/sf_probe.c +2 -1
@@ -481,11 +481,12 @@ int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)int spi_flash_std_probe (struct udevice *dev) {struct spi_slave *slave =dev_get_parentdata (dev); +struct dm_spi_slave_platdata *plat =dev_get_parent_platdata (dev);struct spi_flash *flash; flash = dev->uclass_priv; flash->dev = dev; -debug ("%s: slave=%p, cs=%d\n" , __func__, slave, slave->cs); +debug ("%s: slave=%p, cs=%d\n" , __func__, slave, plat->cs);return spi_flash_probe_slave (slave, flash); }
drivers/spi/soft_spi.c +0 -9
@@ -179,14 +179,6 @@ static int soft_spi_set_mode(struct udevice *dev, unsigned int mode)return 0 ; } -static int soft_spi_child_pre_probe (struct udevice *dev) -{ -struct spi_slave *slave =dev_get_parentdata (dev); - - slave->dev = dev; -return spi_ofdata_to_platdata (gd->fdt_blob, dev->of_offset, slave); -} -static const struct dm_spi_ops soft_spi_ops = { .claim_bus = soft_spi_claim_bus, .release_bus = soft_spi_release_bus,
@@ -241,5 +233,4 @@ U_BOOT_DRIVER(soft_spi) = { .platdata_auto_alloc_size = sizeof(struct soft_spi_platdata), .priv_auto_alloc_size = sizeof(struct soft_spi_priv), .probe = soft_spi_probe, - .child_pre_probe = soft_spi_child_pre_probe, };
drivers/spi/spi-uclass.c +49 -34
168 lines not on this page · raw message
include/spi.h +32 -10
76 lines not on this page · raw message
test/dm/spi.c +3 -3
@@ -36,7 +36,6 @@ static int dm_test_spi_find(struct dm_test_state *dms)ut_asserteq (0 ,uclass_get_device_by_seq (UCLASS_SPI , busnum, &bus));ut_assertok (spi_cs_info (bus, cs, &info)); of_offset = info.dev->of_offset; -sandbox_sf_unbind_emul (state_get_current (), busnum, cs);device_remove (info.dev);device_unbind (info.dev);
@@ -45,7 +44,7 @@ static int dm_test_spi_find(struct dm_test_state *dms)* reports that CS 0 is present */ ut_assertok (spi_cs_info (bus, cs, &info)); -ut_asserteq_ptr (info.dev,NULL ); +ut_asserteq_ptr (NULL , info.dev);/* This finds nothing because we removed the device */ ut_asserteq (-ENODEV ,spi_find_bus_and_cs (busnum, cs, &bus, &dev));
@@ -62,8 +61,9 @@ static int dm_test_spi_find(struct dm_test_state *dms)ut_asserteq (-ENOENT ,spi_get_bus_and_cs (busnum, cs, speed, mode,"spi_flash_std" ,"name" , &bus, &slave)); +sandbox_sf_unbind_emul (state_get_current (), busnum, cs);ut_assertok (spi_cs_info (bus, cs, &info)); -ut_asserteq_ptr (info.dev,NULL ); +ut_asserteq_ptr (NULL , info.dev);/* Add the emulation and try again */ ut_assertok(sandbox_sf_bind_emul(state, busnum, cs, bus, of_offset,
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 18/26 dm: spi: Move slave details to child platdata
Quoted 5 lines · Simon Glass
At present we go through various contortions to store the SPI slave's chip select in its private data. This only exists when the slave is active so must be set up when it is probed. Until the device is probed we don't actually know what chip select it will appear on.
Quoted 8 lines
However, now that we can support per-child platform data, we can use that instead. This allows us to set up the chip select when the child is bound, and avoid the messy contortions.
Unfortunately this is a fairly large change and it seems to be difficult to break it down further.
Signed-off-by Simon Glass <[email protected]>
Applied to -u-boot-dm
PATCH v3 19/26 dm: i2c: Move slave details to child platdata
In reply to Simon GlassAt present we go through various contortions to store the I2C's chip address in its private data. This only exists when the chip is active so must be set up when it is probed. Until the device is probed we don't actually record what address it will appear on.
However, now that we can support per-child platform data, we can use that instead. This allows us to set up the address when the child is bound, and avoid the messy contortions.
Unfortunately this is a fairly large change and it seems to be difficult to break it down further.
---
Changes in v3:
- Add missing 'static' to two functions
- Remove unnecessary per_child_auto_alloc_size value
Changes in v2: None
drivers/i2c/i2c-uclass-compat.c | 2 +- drivers/i2c/i2c-uclass.c | 54 ++++++++++++++++++++++++----------------- drivers/i2c/i2c-uniphier-f.c | 12 --------- drivers/i2c/i2c-uniphier.c | 12 --------- drivers/i2c/s3c24x0_i2c.c | 12 --------- drivers/i2c/sandbox_i2c.c | 28 +++++---------------- drivers/i2c/tegra_i2c.c | 18 -------------- include/i2c.h | 4 +-- 8 files changed, 41 insertions(+), 101 deletions(-)
drivers/i2c/i2c-uclass-compat.c +1 -1
@@ -20,7 +20,7 @@ static int i2c_compat_get_device(uint chip_addr, int alen, ret =i2c_get_chip_for_busnum (cur_busnum, chip_addr, devp);if (ret)return ret; - chip =dev_get_parentdata (*devp); + chip =dev_get_parent_platdata (*devp);if (chip->offset_len != alen) {printf ("Requested alen %d does not match chip offset_len %d\n" , alen, chip->offset_len);
drivers/i2c/i2c-uclass.c +32 -22
139 lines not on this page · raw message
drivers/i2c/i2c-uniphier-f.c +0 -12
@@ -145,16 +145,6 @@ static int uniphier_fi2c_remove(struct udevice *dev)return 0 ; } -static int uniphier_fi2c_child_pre_probe (struct udevice *dev) -{ -struct dm_i2c_chip *i2c_chip =dev_get_parentdata (dev); - -if (dev->of_offset ==-1 ) -return 0 ; -return i2c_chip_ofdata_to_platdata (gd->fdt_blob, dev->of_offset, - i2c_chip); -} -static int wait_for_irq (struct uniphier_fi2c_dev *dev,u32 flags,bool *stop) {
@@ -372,8 +362,6 @@ U_BOOT_DRIVER(uniphier_fi2c) = { .of_match = uniphier_fi2c_of_match, .probe = uniphier_fi2c_probe, .remove = uniphier_fi2c_remove, - .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), - .child_pre_probe = uniphier_fi2c_child_pre_probe, .priv_auto_alloc_size = sizeof(struct uniphier_fi2c_dev), .ops = &uniphier_fi2c_ops, };
drivers/i2c/i2c-uniphier.c +0 -12
@@ -75,16 +75,6 @@ static int uniphier_i2c_remove(struct udevice *dev)return 0 ; } -static int uniphier_i2c_child_pre_probe (struct udevice *dev) -{ -struct dm_i2c_chip *i2c_chip =dev_get_parentdata (dev); - -if (dev->of_offset ==-1 ) -return 0 ; -return i2c_chip_ofdata_to_platdata (gd->fdt_blob, dev->of_offset, - i2c_chip); -} -static int send_and_recv_byte (struct uniphier_i2c_dev *dev,u32 dtrm) {writel (dtrm, &dev->regs->dtrm);
@@ -232,8 +222,6 @@ U_BOOT_DRIVER(uniphier_i2c) = { .of_match = uniphier_i2c_of_match, .probe = uniphier_i2c_probe, .remove = uniphier_i2c_remove, - .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), - .child_pre_probe = uniphier_i2c_child_pre_probe, .priv_auto_alloc_size = sizeof(struct uniphier_i2c_dev), .ops = &uniphier_i2c_ops, };
drivers/i2c/s3c24x0_i2c.c +0 -12
@@ -1404,16 +1404,6 @@ static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)return 0 ; } -static int s3c_i2c_child_pre_probe (struct udevice *dev) -{ -struct dm_i2c_chip *i2c_chip =dev_get_parentdata (dev); - -if (dev->of_offset ==-1 ) -return 0 ; -return i2c_chip_ofdata_to_platdata (gd->fdt_blob, dev->of_offset, - i2c_chip); -} -static const struct dm_i2c_ops s3c_i2c_ops = { .xfer = s3c24x0_i2c_xfer, .probe_chip = s3c24x0_i2c_probe,
@@ -1431,8 +1421,6 @@ U_BOOT_DRIVER(i2c_s3c) = { .id = UCLASS_I2C, .of_match = s3c_i2c_ids, .ofdata_to_platdata = s3c_i2c_ofdata_to_platdata, - .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), - .child_pre_probe = s3c_i2c_child_pre_probe, .priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus), .ops = &s3c_i2c_ops, };
drivers/i2c/sandbox_i2c.c +6 -22
@@ -25,24 +25,24 @@ struct dm_sandbox_i2c_emul_priv {static int get_emul (struct udevice *dev,struct udevice **devp,struct dm_i2c_ops **opsp) { -struct dm_i2c_chip *priv; +struct dm_i2c_chip *plat;int ret; *devp =NULL ; *opsp =NULL ; - priv =dev_get_parentdata (dev); -if (!priv->emul) { + plat =dev_get_parent_platdata (dev); +if (!plat->emul) { ret =dm_scan_fdt_node (dev, gd->fdt_blob, dev->of_offset, false);if (ret)return ret; - ret =device_get_child (dev,0 , &priv->emul); + ret =device_get_child (dev,0 , &plat->emul);if (ret)return ret; } - *devp = priv->emul; - *opsp =i2c_get_ops (priv->emul); + *devp = plat->emul; + *opsp =i2c_get_ops (plat->emul);return 0 ; }
@@ -82,20 +82,6 @@ static const struct dm_i2c_ops sandbox_i2c_ops = { .xfer = sandbox_i2c_xfer, }; -static int sandbox_i2c_child_pre_probe (struct udevice *dev) -{ -struct dm_i2c_chip *i2c_chip =dev_get_parentdata (dev); - -/* Ignore our test address */ -if (i2c_chip->chip_addr ==SANDBOX_I2C_TEST_ADDR ) -return 0 ; -if (dev->of_offset ==-1 ) -return 0 ; - -return i2c_chip_ofdata_to_platdata (gd->fdt_blob, dev->of_offset, - i2c_chip); -} -static const struct udevice_id sandbox_i2c_ids[] = { { .compatible ="sandbox,i2c" }, { }
@@ -105,7 +91,5 @@ U_BOOT_DRIVER(i2c_sandbox) = { .name = "i2c_sandbox", .id = UCLASS_I2C, .of_match = sandbox_i2c_ids, - .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), - .child_pre_probe = sandbox_i2c_child_pre_probe, .ops = &sandbox_i2c_ops, };
drivers/i2c/tegra_i2c.c +0 -18
@@ -484,21 +484,6 @@ static const struct dm_i2c_ops tegra_i2c_ops = { .set_bus_speed = tegra_i2c_set_bus_speed, }; -static int tegra_i2c_child_pre_probe (struct udevice *dev) -{ -struct dm_i2c_chip *i2c_chip =dev_get_parentdata (dev); - -if (dev->of_offset ==-1 ) -return 0 ; -return i2c_chip_ofdata_to_platdata (gd->fdt_blob, dev->of_offset, - i2c_chip); -} - -static int tegra_i2c_ofdata_to_platdata (struct udevice *dev) -{ -return 0 ; -} -static const struct udevice_id tegra_i2c_ids[] = { { .compatible ="nvidia,tegra114-i2c" , .data =TYPE_114 }, { .compatible ="nvidia,tegra20-i2c" , .data =TYPE_STD },
@@ -510,10 +495,7 @@ U_BOOT_DRIVER(i2c_tegra) = { .name = "i2c_tegra", .id = UCLASS_I2C, .of_match = tegra_i2c_ids, - .ofdata_to_platdata = tegra_i2c_ofdata_to_platdata, .probe = tegra_i2c_probe, - .per_child_auto_alloc_size = sizeof(struct dm_i2c_chip), - .child_pre_probe = tegra_i2c_child_pre_probe, .priv_auto_alloc_size = sizeof(struct i2c_bus), .ops = &tegra_i2c_ops, };
include/i2c.h +2 -2
@@ -39,8 +39,8 @@ enum dm_i2c_chip_flags {* An I2C chip is a device on the I2C bus. It sits at a particular address * and normally supports 7-bit or 10-bit addressing. * -* To obtain this structure, use dev_get_parentdata(dev) where dev is the -* chip to examine. +* To obtain this structure, use dev_get_parent_platdata(dev) where dev is +* the chip to examine. * * @chip_addr: Chip address on bus * @offset_len: Length of offset in bytes. A single byte offset can
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 19/26 dm: i2c: Move slave details to child platdata
Quoted 12 lines · On Sun, 25 Jan 2015 08:27:13 -0700 Simon Glass <[email protected]> wrote:
At present we go through various contortions to store the I2C's chip address in its private data. This only exists when the chip is active so must be set up when it is probed. Until the device is probed we don't actually record what address it will appear on.
However, now that we can support per-child platform data, we can use that instead. This allows us to set up the address when the child is bound, and avoid the messy contortions.
Unfortunately this is a fairly large change and it seems to be difficult to break it down further.
Quoted 6 lines
Signed-off-by Simon Glass <[email protected]>---
Changes in v3:
- Add missing 'static' to two functions
- Remove unnecessaryper_child_auto_alloc_sizevalue
I tested this series on my board.
I am OK with the change in the UniPhier I2C driver area.
PATCH v3 19/26 dm: i2c: Move slave details to child platdata
Quoted 24 lines · Masahiro Yamada
Quoted 12 lines · On Sun, 25 Jan 2015 08:27:13 -0700 Simon Glass <[email protected]> wrote:
At present we go through various contortions to store the I2C's chip address in its private data. This only exists when the chip is active so must be set up when it is probed. Until the device is probed we don't actually record what address it will appear on.
However, now that we can support per-child platform data, we can use that instead. This allows us to set up the address when the child is bound, and avoid the messy contortions.
Unfortunately this is a fairly large change and it seems to be difficult to break it down further.
Quoted 6 lines
Signed-off-by Simon Glass <[email protected]>---
Changes in v3:
- Add missing 'static' to two functions
- Remove unnecessaryper_child_auto_alloc_sizevalue
Quoted 6 lines
I tested this series on my board.
I am OK with the change in the UniPhier I2C driver area.Reviewed-by Masahiro Yamada <[email protected]>
Applied to -u-boot-dm
PATCH v3 20/26 dm: tegra: Drop unused COMPAT features for I2C, SPI
In reply to Simon GlassThese have moved to driver model so we don't need the fdtdec support.
---
Changes in v3: None
Changes in v2: None
include/fdtdec.h | 6 ------ lib/fdtdec.c | 6 ------ 2 files changed, 12 deletions(-)
include/fdtdec.h +0 -6
@@ -115,9 +115,6 @@ enum fdt_compat_id {COMPAT_NVIDIA_TEGRA20_USB ,/* Tegra20 USB port */ COMPAT_NVIDIA_TEGRA30_USB ,/* Tegra30 USB port */ COMPAT_NVIDIA_TEGRA114_USB ,/* Tegra114 USB port */ -COMPAT_NVIDIA_TEGRA114_I2C ,/* Tegra114 I2C w/single clock source */ -COMPAT_NVIDIA_TEGRA20_I2C ,/* Tegra20 i2c */ -COMPAT_NVIDIA_TEGRA20_DVC ,/* Tegra20 dvc (really just i2c) */ COMPAT_NVIDIA_TEGRA20_EMC ,/* Tegra20 memory controller */ COMPAT_NVIDIA_TEGRA20_EMC_TABLE ,/* Tegra20 memory timing table */ COMPAT_NVIDIA_TEGRA20_KBC, /* Tegra20 Keyboard */
@@ -127,9 +124,6 @@ enum fdt_compat_id {COMPAT_NVIDIA_TEGRA124_SDMMC ,/* Tegra124 SDMMC controller */ COMPAT_NVIDIA_TEGRA30_SDMMC ,/* Tegra30 SDMMC controller */ COMPAT_NVIDIA_TEGRA20_SDMMC ,/* Tegra20 SDMMC controller */ -COMPAT_NVIDIA_TEGRA20_SFLASH ,/* Tegra 2 SPI flash controller */ -COMPAT_NVIDIA_TEGRA20_SLINK ,/* Tegra 2 SPI SLINK controller */ -COMPAT_NVIDIA_TEGRA114_SPI ,/* Tegra 114 SPI controller */ COMPAT_NVIDIA_TEGRA124_PCIE ,/* Tegra 124 PCIe controller */ COMPAT_NVIDIA_TEGRA30_PCIE ,/* Tegra 30 PCIe controller */ COMPAT_NVIDIA_TEGRA20_PCIE, /* Tegra 20 PCIe controller */
lib/fdtdec.c +0 -6
@@ -24,9 +24,6 @@ static const char * const compat_names[COMPAT_COUNT] = {COMPAT (NVIDIA_TEGRA20_USB ,"nvidia,tegra20-ehci" ),COMPAT (NVIDIA_TEGRA30_USB ,"nvidia,tegra30-ehci" ),COMPAT (NVIDIA_TEGRA114_USB ,"nvidia,tegra114-ehci" ), -COMPAT (NVIDIA_TEGRA114_I2C ,"nvidia,tegra114-i2c" ), -COMPAT (NVIDIA_TEGRA20_I2C ,"nvidia,tegra20-i2c" ), -COMPAT (NVIDIA_TEGRA20_DVC ,"nvidia,tegra20-i2c-dvc" ),COMPAT (NVIDIA_TEGRA20_EMC ,"nvidia,tegra20-emc" ),COMPAT (NVIDIA_TEGRA20_EMC_TABLE ,"nvidia,tegra20-emc-table" ), COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
@@ -36,9 +33,6 @@ static const char * const compat_names[COMPAT_COUNT] = {COMPAT (NVIDIA_TEGRA124_SDMMC ,"nvidia,tegra124-sdhci" ),COMPAT (NVIDIA_TEGRA30_SDMMC ,"nvidia,tegra30-sdhci" ),COMPAT (NVIDIA_TEGRA20_SDMMC ,"nvidia,tegra20-sdhci" ), -COMPAT (NVIDIA_TEGRA20_SFLASH ,"nvidia,tegra20-sflash" ), -COMPAT (NVIDIA_TEGRA20_SLINK ,"nvidia,tegra20-slink" ), -COMPAT (NVIDIA_TEGRA114_SPI ,"nvidia,tegra114-spi" ),COMPAT (NVIDIA_TEGRA124_PCIE ,"nvidia,tegra124-pcie" ),COMPAT (NVIDIA_TEGRA30_PCIE ,"nvidia,tegra30-pcie" ), COMPAT(NVIDIA_TEGRA20_PCIE, "nvidia,tegra20-pcie"),
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 20/26 dm: tegra: Drop unused COMPAT features for I2C, SPI
Quoted 3 lines · Simon Glass
These have moved to driver model so we don't need the fdtdec support.
Signed-off-by Simon Glass <[email protected]>
Applied to -u-boot-dm
PATCH v3 21/26 dm: exynos: Drop unused COMPAT features for SPI
In reply to Simon GlassThis has moved to driver model so we don't need the fdtdec support.
---
Changes in v3: None
Changes in v2: None
include/fdtdec.h | 1 - lib/fdtdec.c | 1 - 2 files changed, 2 deletions(-)
include/fdtdec.h +0 -1
@@ -134,7 +134,6 @@ enum fdt_compat_id {COMPAT_SAMSUNG_S3C2440_I2C ,/* Exynos I2C Controller */ COMPAT_SAMSUNG_EXYNOS5_SOUND ,/* Exynos Sound */ COMPAT_WOLFSON_WM8994_CODEC ,/* Wolfson WM8994 Sound Codec */ -COMPAT_SAMSUNG_EXYNOS_SPI ,/* Exynos SPI */ COMPAT_GOOGLE_CROS_EC ,/* Google CROS_EC Protocol */ COMPAT_GOOGLE_CROS_EC_KEYB ,/* Google CROS_EC Keyboard */ COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */
lib/fdtdec.c +0 -1
@@ -42,7 +42,6 @@ static const char * const compat_names[COMPAT_COUNT] = {COMPAT (SAMSUNG_S3C2440_I2C ,"samsung,s3c2440-i2c" ),COMPAT (SAMSUNG_EXYNOS5_SOUND ,"samsung,exynos-sound" ),COMPAT (WOLFSON_WM8994_CODEC ,"wolfson,wm8994-codec" ), -COMPAT (SAMSUNG_EXYNOS_SPI ,"samsung,exynos-spi" ),COMPAT (GOOGLE_CROS_EC ,"google,cros-ec" ),COMPAT (GOOGLE_CROS_EC_KEYB ,"google,cros-ec-keyb" ), COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 21/26 dm: exynos: Drop unused COMPAT features for SPI
Quoted 30 lines · Simon Glass
This has moved to driver model so we don't need the fdtdec support.
Signed-off-by Simon Glass <[email protected]>---
Changes in v3: None
Changes in v2: Noneinclude/fdtdec.h | 1 - lib/fdtdec.c | 1 - 2 files changed, 2 deletions(-)include/fdtdec.h +0
-1@@ -134,7 +134,6 @@ enum fdt_compat_id {COMPAT_SAMSUNG_S3C2440_I2C ,/* Exynos I2C Controller */ COMPAT_SAMSUNG_EXYNOS5_SOUND ,/* Exynos Sound */ COMPAT_WOLFSON_WM8994_CODEC ,/* Wolfson WM8994 Sound Codec */ -COMPAT_SAMSUNG_EXYNOS_SPI ,/* Exynos SPI */ COMPAT_GOOGLE_CROS_EC ,/* Google CROS_EC Protocol */ COMPAT_GOOGLE_CROS_EC_KEYB ,/* Google CROS_EC Keyboard */ COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */lib/fdtdec.c +0
-0
lib/fdtdec.c static const char * const compat_names[COMPAT_COUNT] = { · line 47
Quoted 7 lines
lib/fdtdec.c +0
-1@@ -42,7 +42,6 @@ static const char * const compat_names[COMPAT_COUNT] = {COMPAT (SAMSUNG_S3C2440_I2C ,"samsung,s3c2440-i2c" ),COMPAT (SAMSUNG_EXYNOS5_SOUND ,"samsung,exynos-sound" ),COMPAT (WOLFSON_WM8994_CODEC ,"wolfson,wm8994-codec" ), -COMPAT (SAMSUNG_EXYNOS_SPI ,"samsung,exynos-spi" ),COMPAT (GOOGLE_CROS_EC ,"google,cros-ec" ),COMPAT (GOOGLE_CROS_EC_KEYB ,"google,cros-ec-keyb" ), COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
Thanks,
Minkyu Kang.
PATCH v3 21/26 dm: exynos: Drop unused COMPAT features for SPI
Quoted 32 lines · Minkyu Kang
Quoted 31 lines · Simon Glass
This has moved to driver model so we don't need the fdtdec support.
Signed-off-by Simon Glass <[email protected]>---
Changes in v3: None
Changes in v2: Noneinclude/fdtdec.h | 1 - lib/fdtdec.c | 1 - 2 files changed, 2 deletions(-)include/fdtdec.h +0
-1@@ -134,7 +134,6 @@ enum fdt_compat_id {COMPAT_SAMSUNG_S3C2440_I2C ,/* Exynos I2C Controller */ COMPAT_SAMSUNG_EXYNOS5_SOUND ,/* Exynos Sound */ COMPAT_WOLFSON_WM8994_CODEC ,/* Wolfson WM8994 Sound Codec */ -COMPAT_SAMSUNG_EXYNOS_SPI ,/* Exynos SPI */ COMPAT_GOOGLE_CROS_EC ,/* Google CROS_EC Protocol */ COMPAT_GOOGLE_CROS_EC_KEYB ,/* Google CROS_EC Keyboard */ COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */lib/fdtdec.c +0
-0@@ -42,7 +42,6 @@ static const char * const compat_names[COMPAT_COUNT] = {COMPAT (SAMSUNG_S3C2440_I2C ,"samsung,s3c2440-i2c" ), COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
Quoted 8 lines
lib/fdtdec.c static const char * const compat_names[COMPAT_COUNT] = { · line 47
Quoted 6 lines
lib/fdtdec.c +0
-1COMPAT (WOLFSON_WM8994_CODEC ,"wolfson,wm8994-codec" ), -COMPAT (SAMSUNG_EXYNOS_SPI ,"samsung,exynos-spi" ),COMPAT (GOOGLE_CROS_EC ,"google,cros-ec" ),COMPAT (GOOGLE_CROS_EC_KEYB ,"google,cros-ec-keyb" ), COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),Acked-by Minkyu Kang <[email protected]>
Applied to -u-boot-dm
PATCH v3 22/26 dm: core: Ignore disabled devices when binding
In reply to Simon GlassWe don't want to bind devices which should never be used.
---
Changes in v3: None
Changes in v2:
- Add patches to tidy up cros_ec using new I2C/SPI features
drivers/core/root.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/core/root.c +5 -0
@@ -9,6 +9,7 @@#include <common.h> #include <errno.h> +#include <fdtdec.h> #include <malloc.h> #include <libfdt.h> #include <dm/device.h>
@@ -92,6 +93,10 @@ int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,if (pre_reloc_only && !fdt_getprop (blob, offset,"u-boot,dm-pre-reloc" ,NULL ))continue ; +if (!fdtdec_get_is_enabled (blob, offset)) { +dm_dbg (" - ignoring disabled device\n" ); +continue ; + } err =lists_bind_fdt (parent, blob, offset,NULL );if (err && !ret) ret = err;
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 22/26 dm: core: Ignore disabled devices when binding
Quoted 4 lines · Simon Glass
We don't want to bind devices which should never be used.
Signed-off-by Simon Glass <[email protected]>Reviewed-by Masahiro Yamada <[email protected]>
Quoted 8 lines
---
Changes in v3: None
Changes in v2:
- Add patches to tidy upcros_ecusing new I2C/SPI featuresdrivers/core/root.c | 5 +++++ 1 file changed, 5 insertions(+)
Applied to -u-boot-dm
PATCH v3 23/26 dm: cros_ec: Don't require protocol 3 support
In reply to Simon GlassI2C is now deprecated on ARM platforms and there are no devices that use it with the v3 protocol. We can't require v3 support if we want to support I2C. Adjust the error handling to suit.
---
Changes in v3: None
Changes in v2:
- Add patches to tidy up cros_ec using new I2C/SPI features
drivers/misc/cros_ec.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/misc/cros_ec.c +6 -4
@@ -154,7 +154,9 @@ static int prepare_proto3_response_buffer(struct cros_ec_dev *dev, int din_len)* @param dev CROS-EC device * @param dinp Returns pointer to response data * @param din_len Maximum size of response in bytes -* @return number of bytes of response data, or <0 if error +* @return number of bytes of response data, or <0 if error. Note that error +* codes can be from errno.h or -ve EC_RES_INVALID_CHECKSUM values (and they +* overlap!) */ static int handle_proto3_response (struct cros_ec_dev *dev,uint8_t **dinp,int din_len)
@@ -228,7 +230,7 @@ static int send_command_proto3(struct cros_ec_dev *dev,#ifdef CONFIG_DM_CROS_EC ops =dm_cros_ec_get_ops (dev->dev); - rv = ops->packet (dev->dev, out_bytes, in_bytes); + rv = ops->packet ? ops->packet (dev->dev, out_bytes, in_bytes) : -ENOSYS ;#else switch (dev->interface) {#ifdef CONFIG_CROS_EC_SPI
@@ -320,7 +322,7 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,* If not NULL, it will be updated to point to the data * and will always be double word aligned (64-bits) * @param din_len Maximum size of response in bytes -* @return number of bytes in response, or -1 on error +* @return number of bytes in response, or -ve on error */ static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, const void *dout, int dout_len, uint8_t **dinp,
@@ -387,7 +389,7 @@ static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,* It not NULL, it is a place for ec_command() to copy the * data to. * @param din_len Maximum size of response in bytes -* @return number of bytes in response, or -1 on error +* @return number of bytes in response, or -ve on error */ static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, const void *dout, int dout_len,
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 23/26 dm: cros_ec: Don't require protocol 3 support
Quoted 5 lines · Simon Glass
I2C is now deprecated on ARM platforms and there are no devices that use it with the v3 protocol. We can't require v3 support if we want to support I2C. Adjust the error handling to suit.
Signed-off-by Simon Glass <[email protected]>
Quoted 8 lines
---
Changes in v3: None
Changes in v2:
- Add patches to tidy upcros_ecusing new I2C/SPI featuresdrivers/misc/cros_ec.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
Applied to -u-boot-dm
PATCH v3 24/26 dm: cros_ec: Move cros_ec_i2c over to driver model
In reply to Simon GlassUpdate the driver model support, and remove the old code. Change snow to use this new support.
---
Changes in v3: None
Changes in v2:
- Add patches to tidy up cros_ec using new I2C/SPI features
drivers/misc/cros_ec_i2c.c | 107 +++++++++++++++++---------------------------- include/configs/snow.h | 5 +++ 2 files changed, 45 insertions(+), 67 deletions(-)
drivers/misc/cros_ec_i2c.c +40 -67
@@ -14,20 +14,16 @@*/ #include <common.h> +#include <dm.h> +#include <errno.h> #include <i2c.h> #include <cros_ec.h> -#ifdef DEBUG_TRACE -#define debug_trace(fmt, b...) debug(fmt, #b) -#else -#define debug_trace(fmt, b...) -#endif - -int cros_ec_i2c_command (struct cros_ec_dev *dev,uint8_t cmd,int cmd_version, +int cros_ec_i2c_command (struct udevice *udev,uint8_t cmd,int cmd_version,const uint8_t *dout,int dout_len,uint8_t **dinp,int din_len) { -int old_bus =0 ; +struct cros_ec_dev *dev = udev->uclass_priv;/* version8, cmd8, arglen8, out8[dout_len], csum8 */ int out_bytes = dout_len +4 ;/* response8, arglen8, in8[din_len], checksum8 */
@@ -37,19 +33,17 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,uint8_t *in_ptr;int len, csum, ret; - old_bus =i2c_get_bus_num (); -/* * Sanity-check I/O sizes given transaction overhead in internal * buffers. */ if (out_bytes >sizeof (dev->dout)) {debug ("%s: Cannot send %d bytes\n" , __func__, dout_len); -return -1 ; +return -ENOSPC ; }if (in_bytes >sizeof (dev->din)) {debug ("%s: Cannot receive %d bytes\n" , __func__, din_len); -return -1 ; +return -ENOSPC ; }assert (dout_len >=0 );assert (dinp);
@@ -72,7 +66,7 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,/* Something we don't support */ debug ("%s: Protocol version %d unsupported\n" , __func__, dev->protocol_version); -return -1 ; +return -EPROTONOSUPPORT ; } *ptr++ =EC_CMD_VERSION0 + cmd_version;
@@ -86,36 +80,18 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, *ptr++ = (uint8_t )cros_ec_calc_checksum (dev->dout, dout_len +3 ); -/* Set to the proper i2c bus */ -if (i2c_set_bus_num (dev->bus_num)) { -debug ("%s: Cannot change to I2C bus %d\n" , __func__, - dev->bus_num); -return -1 ; - } -/* Send output data */ cros_ec_dump_data ("out" ,-1 , dev->dout, out_bytes); - ret =i2c_write (dev->addr,0 ,0 , dev->dout, out_bytes); -if (ret) { -debug ("%s: Cannot complete I2C write to 0x%x\n" , - __func__, dev->addr); - ret =-1 ; - } + ret =dm_i2c_write (udev,0 , dev->dout, out_bytes); +if (ret) +debug ("%s: Cannot complete I2C write\n" , udev->name);if (!ret) { - ret =i2c_read (dev->addr,0 ,0 , in_ptr, in_bytes); -if (ret) { -debug ("%s: Cannot complete I2C read from 0x%x\n" , - __func__, dev->addr); - ret =-1 ; - } + ret =dm_i2c_read (udev,0 , in_ptr, in_bytes); +if (ret) +debug ("%s: Cannot complete I2C read\n" , udev->name); } -/* Return to original bus number */ -i2c_set_bus_num (old_bus); -if (ret) -return ret; -if (*in_ptr !=EC_RES_SUCCESS ) {debug ("%s: Received bad result code %d\n" , __func__, *in_ptr);return -(int )*in_ptr;
@@ -125,13 +101,13 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,if (len +3 >sizeof (dev->din)) {debug ("%s: Received length %#02x too large\n" , __func__, len); -return -1 ; +return -ENOSPC ; } csum =cros_ec_calc_checksum (in_ptr,2 + len);if (csum != in_ptr[2 + len]) {debug ("%s: Invalid checksum rx %#02x, calced %#02x\n" , __func__, in_ptr[2 + din_len], csum); -return -1 ; +return -EBADMSG ; } din_len =min (din_len, len);cros_ec_dump_data ("in" ,-1 , in_ptr, din_len +3 );
@@ -142,35 +118,32 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,return din_len; } -int cros_ec_i2c_decode_fdt (struct cros_ec_dev *dev,const void *blob) +static int cros_ec_probe (struct udevice *dev) { -/* Decode interface-specific FDT params */ - dev->max_frequency =fdtdec_get_int (blob, dev->node, -"i2c-max-frequency" ,100000 ); - dev->bus_num =i2c_get_bus_num_fdt (dev->parent_node); -if (dev->bus_num ==-1 ) { -debug ("%s: Failed to read bus number\n" , __func__); -return -1 ; - } - dev->addr =fdtdec_get_int (blob, dev->node,"reg" ,-1 ); -if (dev->addr ==-1 ) { -debug ("%s: Failed to read device address\n" , __func__); -return -1 ; - } +struct dm_i2c_chip *plat =dev_get_parent_platdata (dev); -return 0 ; +/* +* The EC does not use register offsets. This might be better done +* with a device tree property, like "i2c-offset-len = <0>" but for +* now this works. +*/ + plat->offset_len =0 ; +return cros_ec_register (dev); } -/** -* Initialize I2C protocol. -* -* @param dev CROS_EC device -* @param blob Device tree blob -* @return 0 if ok, -1 on error -*/ -int cros_ec_i2c_init (struct cros_ec_dev *dev,const void *blob) -{ -i2c_init (dev->max_frequency, dev->addr); - -return 0 ; -} +static struct dm_cros_ec_ops cros_ec_ops = { + .command = cros_ec_i2c_command, +}; + +static const struct udevice_id cros_ec_ids[] = { + { .compatible ="google,cros-ec" }, + { } +}; + +U_BOOT_DRIVER (cros_ec_i2c) = { + .name ="cros_ec" , + .id =UCLASS_CROS_EC , + .of_match = cros_ec_ids, + .probe = cros_ec_probe, + .ops = &cros_ec_ops, +};
include/configs/snow.h +5 -0
@@ -16,12 +16,17 @@#define CONFIG_ENV_OFFSET (FLASH_SIZE - CONFIG_BL2_SIZE)#define CONFIG_SPI_BOOTING +#define CONFIG_DM_I2C +#include <configs/exynos5250-common.h> #include <configs/exynos5-dt-common.h> #define CONFIG_CROS_EC_I2C /* Support CROS_EC over I2C */ #define CONFIG_POWER_TPS65090_I2C +#define CONFIG_DM_CROS_EC +#define CONFIG_DM_I2C_COMPAT +#undef CONFIG_SYS_I2C#define CONFIG_BOARD_COMMON #define CONFIG_ARCH_EARLY_INIT_R
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 24/26 dm: cros_ec: Move cros_ec_i2c over to driver model
Quoted 6 lines · Simon Glass
Update the driver model support, and remove the old code. Change snow to use this new support.
Signed-off-by Simon Glass <[email protected]>---
Quoted 7 lines
Changes in v3: None
Changes in v2:
- Add patches to tidy upcros_ecusing new I2C/SPI featuresdrivers/misc/cros_ec_i2c.c | 107 +++++++++++++++++---------------------------- include/configs/snow.h | 5 +++ 2 files changed, 45 insertions(+), 67 deletions(-)
Applied to -u-boot-dm
PATCH v3 24/26 dm: cros_ec: Move cros_ec_i2c over to driver model
Quoted 11 lines · Simon Glass
Quoted 10 lines · Simon Glass
Update the driver model support, and remove the old code. Change snow to use this new support.
Signed-off-by Simon Glass <[email protected]>---
Changes in v3: None
Changes in v2:
- Add patches to tidy upcros_ecusing new I2C/SPI features
Quoted 5 lines
Quoted 3 lines
drivers/misc/cros_ec_i2c.c | 107 +++++++++++++++++---------------------------- include/configs/snow.h | 5 +++ 2 files changed, 45 insertions(+), 67 deletions(-)Applied to -u-boot-dm
Sorry, I'm getting ahead of myself. I cannot apply this until the Samsung I2C driver is applied. So I'm leaving this patch out for now and will revisit hopefully later in the week.
- Simon
PATCH v3 25/26 dm: cros_ec_spi: Remove old pre-driver-model code
In reply to Simon GlassThis is no-longer needed since all platforms use SPI for cros_ec.
---
Changes in v3: None
Changes in v2:
- Add patches to tidy up cros_ec using new I2C/SPI features
drivers/misc/cros_ec_spi.c | 51 ++-------------------------------------------- 1 file changed, 2 insertions(+), 49 deletions(-)
drivers/misc/cros_ec_spi.c +2 -49
@@ -21,14 +21,9 @@DECLARE_GLOBAL_DATA_PTR ; -#ifdef CONFIG_DM_CROS_EC int cros_ec_spi_packet (struct udevice *udev,int out_bytes,int in_bytes) {struct cros_ec_dev *dev = udev->uclass_priv; -#else -int cros_ec_spi_packet (struct cros_ec_dev *dev,int out_bytes,int in_bytes) -{ -#endif struct spi_slave *slave =dev_get_parentdata (dev->dev);int rv;
@@ -67,18 +62,11 @@ int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)* @param din_len Maximum size of response in bytes * @return number of bytes in response, or -1 on error */ -#ifdef CONFIG_DM_CROS_EC int cros_ec_spi_command (struct udevice *udev,uint8_t cmd,int cmd_version,const uint8_t *dout,int dout_len,uint8_t **dinp,int din_len) {struct cros_ec_dev *dev = udev->uclass_priv; -#else -int cros_ec_spi_command (struct cros_ec_dev *dev,uint8_t cmd,int cmd_version, -const uint8_t *dout,int dout_len, -uint8_t **dinp,int din_len) -{ -#endif struct spi_slave *slave =dev_get_parentdata (dev->dev);int in_bytes = din_len +4 ;/* status, length, checksum, trailer */ uint8_t *out;
@@ -166,46 +154,12 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,return len; } -#ifndef CONFIG_DM_CROS_EC -int cros_ec_spi_decode_fdt (struct cros_ec_dev *dev,const void *blob) -{ -/* Decode interface-specific FDT params */ - dev->max_frequency =fdtdec_get_int (blob, dev->node, -"spi-max-frequency" ,500000 ); - dev->cs =fdtdec_get_int (blob, dev->node,"reg" ,0 ); - -return 0 ; -} - -/** -* Initialize SPI protocol. -* -* @param dev CROS_EC device -* @param blob Device tree blob -* @return 0 if ok, -1 on error -*/ -int cros_ec_spi_init (struct cros_ec_dev *dev,const void *blob) -{ -int ret; - - ret =spi_setup_slave_fdt (blob, dev->node, dev->parent_node, - &slave); -if (ret) { -debug ("%s: Could not setup SPI slave\n" , __func__); -return ret; - } - -return 0 ; -} -#endif - -#ifdef CONFIG_DM_CROS_EC -int cros_ec_probe (struct udevice *dev) +static int cros_ec_probe (struct udevice *dev) {return cros_ec_register (dev); } -struct dm_cros_ec_ops cros_ec_ops = { +static struct dm_cros_ec_ops cros_ec_ops = { .packet = cros_ec_spi_packet, .command = cros_ec_spi_command, };
@@ -222,4 +176,3 @@ U_BOOT_DRIVER(cros_ec_spi) = { .probe = cros_ec_probe, .ops = &cros_ec_ops, }; -#endif
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 25/26 dm: cros_ec_spi: Remove old pre-driver-model code
Quoted 11 lines · Simon Glass
This is no-longer needed since all platforms use SPI for
cros_ec.Signed-off-by Simon Glass <[email protected]>---
Changes in v3: None
Changes in v2:
- Add patches to tidy upcros_ecusing new I2C/SPI featuresdrivers/misc/cros_ec_spi.c | 51 ++-------------------------------------------- 1 file changed, 2 insertions(+), 49 deletions(-)
Applied to -u-boot-dm
PATCH v3 26/26 dm: Update documentation for new bus features
In reply to Simon GlassNow that we have new bus features, update README.txt and the SPI docs to explain these.
---
Changes in v3: None
Changes in v2:
- Drop RFC prefix since this series has been properly tested now
- Update commit message to describe immuatable platform data
- Update the spi-howto docs
doc/driver-model/README.txt | 36 ++++++++++++++++++++++++++---------- doc/driver-model/spi-howto.txt | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 13 deletions(-)
doc/driver-model/README.txt +26 -10
@@ -441,11 +441,18 @@ access to other devices. Example of buses include SPI and I2C. Typically the bus provides some sort of transport or translation that makes it possible to talk to the devices on the bus. -Driver model provides a few useful features to help with implementing -buses. Firstly, a bus can request that its children store some 'parent -data' which can be used to keep track of child state. Secondly, the bus can -define methods which are called when a child is probed or removed. This is -similar to the methods the uclass driver provides. +Driver model provides some useful features to help with implementing buses. +Firstly, a bus can request that its children store some 'parent data' which +can be used to keep track of child state. Secondly, the bus can define +methods which are called when a child is probed or removed. This is similar +to the methods the uclass driver provides. Thirdly, per-child platform data +can be provided to specify things like the child's address on the bus. This +persists across child probe()/remove() cycles. + +For consistency and ease of implementation, the bus uclass can specify the +per-child platform data, so that it can be the same for all children of buses +in that uclass. There are also uclass methods which can be called when +children are bound and probed. Here an explanation of how a bus fits with a uclass may be useful. Consider a USB bus with several devices attached to it, each from a different (made
@@ -460,15 +467,23 @@ Each of the devices is connected to a different address on the USB bus. The bus device wants to store this address and some other information such as the bus speed for each device. -To achieve this, the bus device can use dev->parent_priv in each of its -three children. This can be auto-allocated if the bus driver has a non-zero -value for per_child_auto_alloc_size. If not, then the bus device can -allocate the space itself before the child device is probed. +To achieve this, the bus device can use dev->parent_platdata in each of its +three children. This can be auto-allocated if the bus driver (or bus uclass) +has a non-zero value for per_child_platdata_auto_alloc_size. If not, then +the bus device or uclass can allocate the space itself before the child +device is probed. Also the bus driver can define the child_pre_probe() and child_post_remove() methods to allow it to do some processing before the child is activated or after it is deactivated. +Similarly the bus uclass can define the child_post_bind() method to obtain +the per-child platform data from the device tree and set it up for the child. +The bus uclass can also provide a child_pre_probe() method. Very often it is +the bus uclass that controls these features, since it avoids each driver +having to do the same processing. Of course the driver can still tweak and +override these activities. + Note that the information that controls this behaviour is in the bus's driver, not the child's. In fact it is possible that child has no knowledge that it is connected to a bus. The same child device may even be used on two
@@ -495,7 +510,8 @@ bus device, regardless of its own views on the matter. The uclass for the device can also contain data private to that uclass. But note that each device on the bus may be a memeber of a different uclass, and this data has nothing to do with the child data for each child -on the bus. +on the bus. It is the bus' uclass that controls the child with respect to +the bus. Driver Lifecycle
doc/driver-model/spi-howto.txt +37 -3
@@ -3,7 +3,8 @@ How to port a SPI driver to driver model Here is a rough step-by-step guide. It is based around converting the exynos SPI driver to driver model (DM) and the example code is based -around U-Boot v2014.10-rc2 (commit be9f643). +around U-Boot v2014.10-rc2 (commit be9f643). This has been updated for +v2015.04. It is quite long since it includes actual code examples.
@@ -262,8 +263,8 @@ U_BOOT_DEVICE(board_spi0) = { .platdata = &platdata_spi0, }; -You will unfortunately need to put the struct into a header file in this -case so that your board file can use it. +You will unfortunately need to put the struct definition into a header file +in this case so that your board file can use it. 9. Add the device private data
@@ -592,3 +593,36 @@ board. You can use 'tools/patman/patman' to prepare, check and send patches for your work. See the README for details. + +20. A little note about SPI uclass features: + +The SPI uclass keeps some information about each device 'dev' on the bus: + + struct dm_spi_slave_platdata - this is device_get_parent_platdata(dev) + This is where the chip select number is stored, along with + the default bus speed and mode. It is automatically read + from the device tree in spi_child_post_bind(). It must not + be changed at run-time after being set up because platform + data is supposed to be immutable at run-time. + struct spi_slave - this is device_get_parentdata(dev) + Already mentioned above. It holds run-time information about + the device. + +There are also some SPI uclass methods that get called behind the scenes: + + spi_post_bind() - called when a new bus is bound + This scans the device tree for devices on the bus, and binds + each one. This in turn causes spi_child_post_bind() to be + called for each, which reads the device tree information + into the parent (per-child) platform data. + spi_child_post_bind() - called when a new child is bound + As mentioned above this reads the device tree information + into the per-child platform data + spi_child_pre_probe() - called before a new child is probed + This sets up the mode and speed in struct spi_slave by + copying it from the parent's platform data for this child. + It also sets the 'dev' pointer, needed to permit passing + 'struct spi_slave' around the place without needing a + separate 'struct udevice' pointer. + +The above housekeeping makes it easier to write your SPI driver.
Signature · 1 line
2.2.0.rc0.207.ga3a616c
PATCH v3 26/26 dm: Update documentation for new bus features
Quoted 11 lines · Simon Glass
Now that we have new bus features, update README.txt and the SPI docs to explain these.
Signed-off-by Simon Glass <[email protected]>---
Changes in v3: None
Changes in v2:
- Drop RFC prefix since this series has been properly tested now
- Update commit message to describe immuatable platform data
- Update the spi-howto docs
Quoted 3 lines
doc/driver-model/README.txt | 36 ++++++++++++++++++++++++++---------- doc/driver-model/spi-howto.txt | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 13 deletions(-)
Applied to -u-boot-dm
v3 cover dm: Add additional bus functionality
In reply to Simon GlassHi Simon,
Quoted 48 lines · On Sun, 25 Jan 2015 08:26:54 -0700 Simon Glass <[email protected]> wrote:
The current bus implementation is simple but leaves some things to drivers which are better handled in the uclass.
At present uclasses cannot provide a common way of dealing with children (i.e. devices on the bus), so we have duplication in the drivers. The same code is repeated in each driver when it would be better to put it in the uclass.
Secondly, we don't have the concept of per-child platform data for devices on the bus. Instead the per-child data can only exist when the child is actually probed. This is not really suitable. Examples of things we want to know before a child is probed are:
- chip address (for I2C)
- chip select (for SPI)
- device address (for PCI)These things are static and do not change when the device is probed and removed. In some cases (such as SPI mode and maximum speed), the data may be copied to run-time data when the device is probed. It may then be changed while the driver is active, but the original platform data is never changed by drivers once it is set up.
To address these issues, additional functions are added:
- per-child platform data, which can be defined by the uclass and (if necessary) overriden by the bus driver. This allows the bus's uclass to provide some consistency here
- per-child post-bind and pre-probe methods in the uclass. These allow the bus uclass to set up the per-child platform data, and also to do any last-minute adjustments before the child is probed.With these changes, some code can be removed from the existing I2C and SPI drivers and this has been done as part of this series.
With this series I2C and SPI are tested on:
- jetson-tk1 (Tegra 124)
- beaver (Tegra 30)
- seaboard (Tegra 20, I2C only)
- trimslice (Tegra 20, SPI only)
- snow (Exynos 5250)
- pit (Exynos 5420, note I2C probe is previously broken)
- link (x86)
- sandboxNote: Some of these changes were previously included in the DM PCI RFC. This series is available at u-boot-dm/i2c-working.
Quoted 8 lines
Changes in v3:
- Add missing 'static' to two functions
- Change variable name fromparent_drvtouc_drv
- Fix comment to say 'node references' instead of 'phandles'
- Fix stale comment indevice_probe_child()
- Fix typo in commit subject
- Remove unnecessary check thatdev->parent_platdatais NULL
- Remove unnecessaryper_child_auto_alloc_sizevalue
I issued my Reviewed-by to some rest of the patches.
V3 looks good enough to be applied. Thank you!
Best Regards
Masahiro Yamada