From 72ebfe86fac2ca0a0e1af9fe1eaa3a634e3e17a1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:26:59 -0700 Subject: dm: core: Tidy up error handling in device_bind() 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 Reviewed-by: Masahiro Yamada --- drivers/core/device.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/core/device.c') diff --git a/drivers/core/device.c b/drivers/core/device.c index 963b16f26f..eca8edac26 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -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; } -- cgit v1.2.1 From f8a85449ef3e0963add728815771ccc09aa99875 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:00 -0700 Subject: dm: core: Allocate platform data when binding a device 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 Reviewed-by: Masahiro Yamada --- drivers/core/device.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/core/device.c') diff --git a/drivers/core/device.c b/drivers/core/device.c index eca8edac26..366cffed89 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -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); -- cgit v1.2.1 From cdc133bde9dd221319b9cf7fd99fcb4da8ba195c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:01 -0700 Subject: dm: core: Allow parents to have platform data for their children 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 Reviewed-by: Masahiro Yamada --- drivers/core/device.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers/core/device.c') diff --git a/drivers/core/device.c b/drivers/core/device.c index 366cffed89..ee97cc84ff 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -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) { -- cgit v1.2.1 From ba8da9dc43ac8ae3351345df12dc7f9d1cd07ae0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:02 -0700 Subject: dm: core: Allow uclasses to specify platdata for a device's children 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 Signed-off-by: Simon Glass --- drivers/core/device.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/core/device.c') diff --git a/drivers/core/device.c b/drivers/core/device.c index ee97cc84ff..2f33b0e6a3 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -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); -- cgit v1.2.1 From 0118ce79577f9b0881f99a6e4f8a79cd5014cb87 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:03 -0700 Subject: dm: core: Add a post_bind method for parents 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 Reviewed-by: Masahiro Yamada --- drivers/core/device.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/core/device.c') diff --git a/drivers/core/device.c b/drivers/core/device.c index 2f33b0e6a3..365676b912 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -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", -- cgit v1.2.1 From b367053102e597eb21b0a5e86c63e8d10f368cb0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:04 -0700 Subject: dm: core: Add a function to get a device's uclass ID This is useful to check which uclass a device is in. Signed-off-by: Simon Glass Reviewed-by: Masahiro Yamada --- drivers/core/device.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/core/device.c') diff --git a/drivers/core/device.c b/drivers/core/device.c index 365676b912..2606d18717 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -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; +} -- cgit v1.2.1 From 9cc36a2b89ebe5148d69d521745c1e1d26365c3a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:05 -0700 Subject: dm: core: Add a flag to control sequence numbering 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. 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 Reviewed-by: Masahiro Yamada --- drivers/core/device.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers/core/device.c') diff --git a/drivers/core/device.c b/drivers/core/device.c index 2606d18717..f78b78a299 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -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; -- cgit v1.2.1 From dac8db2ce66944828e441cccf25703b262a256cd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:06 -0700 Subject: dm: core: Allow uclasses to specify private data for a device's children 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 Reviewed-by: Masahiro Yamada --- drivers/core/device.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/core/device.c') diff --git a/drivers/core/device.c b/drivers/core/device.c index f78b78a299..78bc460d35 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -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) { -- cgit v1.2.1 From 83c7e434c9dd3ca81f8b763e23c1881b973bcf2f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Jan 2015 08:27:10 -0700 Subject: dm: core: Allow uclass to set up a device's child before it is probed 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 Reviewed-by: Masahiro Yamada --- drivers/core/device.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/core/device.c') diff --git a/drivers/core/device.c b/drivers/core/device.c index 78bc460d35..b73d3b8961 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -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) -- cgit v1.2.1