
Dear Simon Glass,
[...]
+What is going on? +-----------------
+Let's start at the top. The demo command is in common/cmd_demo.c. It does +the usual command procesing and then:
- struct device *demo_dev;
- ret = uclass_get_device(UCLASS_DEMO, &demo_dev);
Which device will this assign into demo_dev if there are multiple devices registered with the demo uclass ?
+UCLASS_DEMO means the class of devices which implement 'demo'. Other +classes might be MMC, or GPIO, hashing or serial. The idea is that the +devices in the class all share a particular way of working. The class +presents a unified view of all these devices to U-Boot.
[...]
+Declaring Drivers +-----------------
+A driver declaration looks something like this (see +drivers/demo/demo-shape.c):
+static const struct demo_ops simple_ops = {
- .hello = shape_hello,
- .status = shape_status,
+};
+U_BOOT_DRIVER(demo_shape_drv) = {
- .name = "demo_shape_drv",
- .id = UCLASS_DEMO,
- .ops = &simple_ops,
- .priv_data_size = sizeof(struct shape_data),
+};
We are not discussing relocation here yet, right ?
+This driver has two methods (hello and status) and requires a bit +of private data (accessible through dev->priv once the driver has +been probed). It is a member of UCLASS_DEMO so will register itself +there.
+In U_BOOT_DRIVER it is also possible to specify special methods for probe, +and bind, and these are called at appropriate times. For many drivers +it is hoped that only 'probe' and 'remove' will be needed.
+The U_BOOT_DRIVER macro creates a data structure accessible from C, +so driver model can find the drivers that are available.
+Platform Data +-------------
+Where does the platform data come from? See demo-pdata.c which +sets up a table of driver names and their associated platform data. +The data can be interpreted by the drivers however they like - it is +basically a communication scheme between the board-specific code and +the generic drivers, which are intended to work on any board.
+Drivers can acceess their data via dev->info->platform_data. Here is +the declaration for the platform data, which would normally appear +in the board file.
- static const struct dm_demo_cdata red_square = {
.colour = "red",
.sides = 4.
- };
- static const struct driver_info info[] = {
{
.name = "demo_shape_drv",
.platform_data = &red_square,
},
- };
- demo1 = driver_bind(root, &info[0]);
We need dev_get_platdata() call or something, otherwise someone will shoot himself in the face with a NULL pointer.
+Device Tree +-----------
+While platform_data is useful, a more flexible way of providing device data is +by using device tree. With device tree we replace the above code with the +following device treefragment:
- red-square {
compatible = "demo-shape";
colour = "red";
sides = <4>;
- };
+The easiest way to make this work it to add a platform_data_size member to +the driver:
- .platform_data_auto_alloc_size = sizeof(struct dm_test_pdata),
+This will be allocated and zeroed before the driver's probe method is called. +The driver can then read the information out of the device tree and put it +in dev->priv, typically using a ..._parse_dt() function.
Can the driver maybe implement some ofdata_to_pdata() callback?
+Declaring Uclasses +------------------
+The demo uclass is declared like this:
+U_BOOT_CLASS(demo) = {
- .id = UCLASS_DEMO,
+};
+It is also possible to specify special methods for probe, etc. The uclass +numbering comes from include/dm/uclass.h. To add a new uclass, add to the +end of the enum there, then declare your uclass as above.
I wonder if we cannot even automate the numbering here ;-)
[...]