diff mbox

[U-Boot,V2,1/2] dm: allow setting driver_data before/during bind

Message ID 1463001985-4039-1-git-send-email-swarren@wwwdotorg.org
State Accepted
Commit daac3bfee57247013cb8373683e9babb191abd75
Delegated to: Simon Glass
Headers show

Commit Message

Stephen Warren May 11, 2016, 9:26 p.m. UTC
From: Stephen Warren <swarren@nvidia.com>

This will allow a driver's bind function to use the driver data. One
example is the Tegra186 GPIO driver, which instantiates child devices
for each of its GPIO ports, yet supports two different HW instances each
with a different set of ports, and identified by the udevice_id .data
field.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
v2:
* Introduce a separate function for the new functionality, rather than
modifying device_bind().

This patch is a dependency for the upcoming Tegra186 GPIO driver too.
---
 doc/driver-model/README.txt  | 23 ++++++++++++++---------
 drivers/core/device.c        | 25 ++++++++++++++++++++++---
 drivers/core/lists.c         |  4 ++--
 include/dm/device-internal.h | 24 ++++++++++++++++++++++++
 4 files changed, 62 insertions(+), 14 deletions(-)

Comments

Simon Glass May 12, 2016, 5:43 p.m. UTC | #1
On 11 May 2016 at 15:26, Stephen Warren <swarren@wwwdotorg.org> wrote:
> From: Stephen Warren <swarren@nvidia.com>
>
> This will allow a driver's bind function to use the driver data. One
> example is the Tegra186 GPIO driver, which instantiates child devices
> for each of its GPIO ports, yet supports two different HW instances each
> with a different set of ports, and identified by the udevice_id .data
> field.
>
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> ---
> v2:
> * Introduce a separate function for the new functionality, rather than
> modifying device_bind().
>
> This patch is a dependency for the upcoming Tegra186 GPIO driver too.
> ---
>  doc/driver-model/README.txt  | 23 ++++++++++++++---------
>  drivers/core/device.c        | 25 ++++++++++++++++++++++---
>  drivers/core/lists.c         |  4 ++--
>  include/dm/device-internal.h | 24 ++++++++++++++++++++++++
>  4 files changed, 62 insertions(+), 14 deletions(-)

Thanks.

Acked-by: Simon Glass <sjg@chromium.org>
Simon Glass May 23, 2016, 3:38 p.m. UTC | #2
On 12 May 2016 at 11:43, Simon Glass <sjg@chromium.org> wrote:
> On 11 May 2016 at 15:26, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> From: Stephen Warren <swarren@nvidia.com>
>>
>> This will allow a driver's bind function to use the driver data. One
>> example is the Tegra186 GPIO driver, which instantiates child devices
>> for each of its GPIO ports, yet supports two different HW instances each
>> with a different set of ports, and identified by the udevice_id .data
>> field.
>>
>> Signed-off-by: Stephen Warren <swarren@nvidia.com>
>> ---
>> v2:
>> * Introduce a separate function for the new functionality, rather than
>> modifying device_bind().
>>
>> This patch is a dependency for the upcoming Tegra186 GPIO driver too.
>> ---
>>  doc/driver-model/README.txt  | 23 ++++++++++++++---------
>>  drivers/core/device.c        | 25 ++++++++++++++++++++++---
>>  drivers/core/lists.c         |  4 ++--
>>  include/dm/device-internal.h | 24 ++++++++++++++++++++++++
>>  4 files changed, 62 insertions(+), 14 deletions(-)
>
> Thanks.
>
> Acked-by: Simon Glass <sjg@chromium.org>

Applied to u-boot-dm, thanks!
diff mbox

Patch

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index 7a24552560d5..1b5ccec4b2e5 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -606,19 +606,24 @@  methods actually defined.
 
 1. Bind stage
 
-A device and its driver are bound using one of these two methods:
+U-Boot discovers devices using one of these two methods:
 
-   - Scan the U_BOOT_DEVICE() definitions. U-Boot It looks up the
-name specified by each, to find the appropriate driver. It then calls
-device_bind() to create a new device and bind' it to its driver. This will
-call the device's bind() method.
+   - Scan the U_BOOT_DEVICE() definitions. U-Boot looks up the name specified
+by each, to find the appropriate U_BOOT_DRIVER() definition. In this case,
+there is no path by which driver_data may be provided, but the U_BOOT_DEVICE()
+may provide platdata.
 
    - Scan through the device tree definitions. U-Boot looks at top-level
 nodes in the the device tree. It looks at the compatible string in each node
-and uses the of_match part of the U_BOOT_DRIVER() structure to find the
-right driver for each node. It then calls device_bind() to bind the
-newly-created device to its driver (thereby creating a device structure).
-This will also call the device's bind() method.
+and uses the of_match table of the U_BOOT_DRIVER() structure to find the
+right driver for each node. In this case, the of_match table may provide a
+driver_data value, but platdata cannot be provided until later.
+
+For each device that is discovered, U-Boot then calls device_bind() to create a
+new device, initializes various core fields of the device object such as name,
+uclass & driver, initializes any optional fields of the device object that are
+applicable such as of_offset, driver_data & platdata, and finally calls the
+driver's bind() method if one is defined.
 
 At this point all the devices are known, and bound to their drivers. There
 is a 'struct udevice' allocated for all devices. However, nothing has been
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 2b12ce7835f0..a8f2380e4676 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -26,9 +26,10 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
-int device_bind(struct udevice *parent, const struct driver *drv,
-		const char *name, void *platdata, int of_offset,
-		struct udevice **devp)
+static int device_bind_common(struct udevice *parent, const struct driver *drv,
+			      const char *name, void *platdata,
+			      ulong driver_data, int of_offset,
+			      struct udevice **devp)
 {
 	struct udevice *dev;
 	struct uclass *uc;
@@ -56,6 +57,7 @@  int device_bind(struct udevice *parent, const struct driver *drv,
 	INIT_LIST_HEAD(&dev->devres_head);
 #endif
 	dev->platdata = platdata;
+	dev->driver_data = driver_data;
 	dev->name = name;
 	dev->of_offset = of_offset;
 	dev->parent = parent;
@@ -193,6 +195,23 @@  fail_alloc1:
 	return ret;
 }
 
+int device_bind_with_driver_data(struct udevice *parent,
+				 const struct driver *drv, const char *name,
+				 ulong driver_data, int of_offset,
+				 struct udevice **devp)
+{
+	return device_bind_common(parent, drv, name, NULL, driver_data,
+				  of_offset, devp);
+}
+
+int device_bind(struct udevice *parent, const struct driver *drv,
+		const char *name, void *platdata, int of_offset,
+		struct udevice **devp)
+{
+	return device_bind_common(parent, drv, name, platdata, 0, of_offset,
+				  devp);
+}
+
 int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
 			const struct driver_info *info, struct udevice **devp)
 {
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index a72db13a119a..0c2771779096 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -170,7 +170,8 @@  int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
 		}
 
 		dm_dbg("   - found match at '%s'\n", entry->name);
-		ret = device_bind(parent, entry, name, NULL, offset, &dev);
+		ret = device_bind_with_driver_data(parent, entry, name,
+						   id->data, offset, &dev);
 		if (ret == -ENODEV) {
 			dm_dbg("Driver '%s' refuses to bind\n", entry->name);
 			continue;
@@ -180,7 +181,6 @@  int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
 				ret);
 			return ret;
 		} else {
-			dev->driver_data = id->data;
 			found = true;
 			if (devp)
 				*devp = dev;
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index b348ad5231bd..0bf8707493a9 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -39,6 +39,30 @@  int device_bind(struct udevice *parent, const struct driver *drv,
 		struct udevice **devp);
 
 /**
+ * device_bind_with_driver_data() - Create a device and bind it to a driver
+ *
+ * Called to set up a new device attached to a driver, in the case where the
+ * driver was matched to the device by means of a match table that provides
+ * driver_data.
+ *
+ * Once bound a device exists but is not yet active until device_probe() is
+ * called.
+ *
+ * @parent: Pointer to device's parent, under which this driver will exist
+ * @drv: Device's driver
+ * @name: Name of device (e.g. device tree node name)
+ * @driver_data: The driver_data field from the driver's match table.
+ * @of_offset: Offset of device tree node for this device. This is -1 for
+ * devices which don't use device tree.
+ * @devp: if non-NULL, returns a pointer to the bound device
+ * @return 0 if OK, -ve on error
+ */
+int device_bind_with_driver_data(struct udevice *parent,
+				 const struct driver *drv, const char *name,
+				 ulong driver_data, int of_offset,
+				 struct udevice **devp);
+
+/**
  * device_bind_by_name: Create a device and bind it to a driver
  *
  * This is a helper function used to bind devices which do not use device