Description
Introduction
This RFC looks into defining and classifying struct devices from within the device drivers by device class (which API they implement) and presenting them to the application by class agnostic from the devicetree.
Problem description
Consider the following devicetree snippet:
&i2c1 {
status = "okay";
clock-frequency = <I2C_BITRATE_STANDARD>;
mcp7940n@25 {
compatible = "microchip,mcp7940n";
reg = <0x25>;
status = "okay";
int-gpios = <&gpioa 1>;
rtc0: rtc {
compatible = "microchip,mcp7940n-rtc";
status = "okay";
};
bbram0: bbram {
compatible = "microchip,mcp7940n-bbram";
status = "okay";
};
};
};
The bbram
and rtc
nodes are endpoints, which don't have any capabilities useful to the devicetree. Yet, with the current devicetree model, we have to create a node for them here to make it available to the application.
Proposed change
The solution proposed in this RFC will allow us to create the child nodes within the device drivers, removing the need for these superfluous nodes in the devicetree, which will reduce the devicetree snippet to the following (just like the Linux devicetree :))
&i2c1 {
status = "okay";
clock-frequency = <I2C_BITRATE_STANDARD>;
mcp7940n@25 {
compatible = "microchip,mcp7940n";
reg = <0x25>;
status = "okay";
int-gpios = <&gpioa 1>;
};
};
This results in less boilerplate devicetree code, removes the need for additional devicetree compatibles for the child nodes, and removes the need for using devicetree aliases like bbram0, rtc0, ... from the application. To get the nodes from the application, we will do this instead:
BUILD_ASSERT(DEVICE_CLASS_HAS_ANY(rtc), "application requires an RTC");
BUILD_ASSERT(DEVICE_CLASS_HAS_ANY(bbram), "application requires BBRAM");
const struct device *rtc = DEVICE_CLASS_GET(rtc, 0);
const struct device *bbram DEVICE_CLASS_GET(bbram, 0);
This is possible using sections in elf files, which will find all struct device defined using DEVICE_DEFINE, and which API type the devices implements (their class). From this, we can create macros to find and iterate through struct devices by class agnostic from the devicetree.
Its essentially Linux SYSFS but static and using macros :)
Dependencies
Applications will now be encouraged to use the new class based macros to identify and use devices, instead of devicetree nodes. Subsystems like shells would also be built at the application level, or at their own level between drivers and the application to use the DEVICE_CLASS macros.
Devicetree nodes will still work as before, the drivers and kernel need to know the actual devicetree layout.
Concerns and Unresolved Questions
- Is it practical?
- How much does it break?
- Is a device class based approach (like Linux sysfs) something we want on an embedded platform given its abstraction from the devicetree?
- Can we, and should we, guarantee the enumeration of devices is consistent across builds? CAN0 will always be CAN0 for a particular board for example.
- Can this be expanded to other subsystems like network devices? something like NET_IFACE_GET(ppp, 0);
Alternatives
Create runtime functions instead of macros to sort through all devices by types, this is slower than macros, and we can't check struct devices exist at compile time DEVICE_CLASS_HAS_ANY(...)
, but it's simple C code with no elf_parser magic, which is faster than looking through strings which we do for bindings now. It will also allow for users to create struct devices in the application, which would not be possible with the macro solution.