1Supporting Legacy Boards 2======================== 3 4Many drivers in the kernel, such as ``leds-gpio`` and ``gpio-keys``, are 5migrating away from using board-specific ``platform_data`` to a unified device 6properties interface. This interface allows drivers to be simpler and more 7generic, as they can query properties in a standardized way. 8 9On modern systems, these properties are provided via device tree. However, some 10older platforms have not been converted to device tree and instead rely on 11board files to describe their hardware configuration. To bridge this gap and 12allow these legacy boards to work with modern, generic drivers, the kernel 13provides a mechanism called **software nodes**. 14 15This document provides a guide on how to convert a legacy board file from using 16``platform_data`` and ``gpiod_lookup_table`` to the modern software node 17approach for describing GPIO-connected devices. 18 19The Core Idea: Software Nodes 20----------------------------- 21 22Software nodes allow board-specific code to construct an in-memory, 23device-tree-like structure using struct software_node and struct 24property_entry. This structure can then be associated with a platform device, 25allowing drivers to use the standard device properties API (e.g., 26device_property_read_u32(), device_property_read_string()) to query 27configuration, just as they would on an ACPI or device tree system. 28 29The gpiolib code has support for handling software nodes, so that if GPIO is 30described properly, as detailed in the section below, then regular gpiolib APIs, 31such as gpiod_get(), gpiod_get_optional(), and others will work. 32 33Requirements for GPIO Properties 34~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 35 36When using software nodes to describe GPIO connections, the following 37requirements must be met for the GPIO core to correctly resolve the reference: 38 391. **The GPIO controller's software node must be registered and attached to 40 the controller's ``struct device`` either as its primary or secondary 41 firmware node.** The gpiolib core uses the address of the firmware node to 42 find the corresponding ``struct gpio_chip`` at runtime. 43 442. **The GPIO property must be a reference.** The ``PROPERTY_ENTRY_GPIO()`` 45 macro handles this as it is an alias for ``PROPERTY_ENTRY_REF()``. 46 473. **The reference must have exactly two arguments:** 48 49 - The first argument is the GPIO offset within the controller. 50 - The second argument is the flags for the GPIO line (e.g., 51 GPIO_ACTIVE_HIGH, GPIO_ACTIVE_LOW). 52 53The ``PROPERTY_ENTRY_GPIO()`` macro is the preferred way of defining GPIO 54properties in software nodes. 55 56Conversion Example 57------------------ 58 59Let's walk through an example of converting a board file that defines a GPIO- 60connected LED and a button. 61 62Before: Using Platform Data 63~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 64 65A typical legacy board file might look like this: 66 67.. code-block:: c 68 69 #include <linux/platform_device.h> 70 #include <linux/leds.h> 71 #include <linux/gpio_keys.h> 72 #include <linux/gpio/machine.h> 73 74 #define MYBOARD_GPIO_CONTROLLER "gpio-foo" 75 76 /* LED setup */ 77 static const struct gpio_led myboard_leds[] = { 78 { 79 .name = "myboard:green:status", 80 .default_trigger = "heartbeat", 81 }, 82 }; 83 84 static const struct gpio_led_platform_data myboard_leds_pdata = { 85 .num_leds = ARRAY_SIZE(myboard_leds), 86 .leds = myboard_leds, 87 }; 88 89 static struct gpiod_lookup_table myboard_leds_gpios = { 90 .dev_id = "leds-gpio", 91 .table = { 92 GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 42, NULL, 0, GPIO_ACTIVE_HIGH), 93 { }, 94 }, 95 }; 96 97 /* Button setup */ 98 static struct gpio_keys_button myboard_buttons[] = { 99 { 100 .code = KEY_WPS_BUTTON, 101 .desc = "WPS Button", 102 .active_low = 1, 103 }, 104 }; 105 106 static const struct gpio_keys_platform_data myboard_buttons_pdata = { 107 .buttons = myboard_buttons, 108 .nbuttons = ARRAY_SIZE(myboard_buttons), 109 }; 110 111 static struct gpiod_lookup_table myboard_buttons_gpios = { 112 .dev_id = "gpio-keys", 113 .table = { 114 GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 15, NULL, 0, GPIO_ACTIVE_LOW), 115 { }, 116 }, 117 }; 118 119 /* Device registration */ 120 static int __init myboard_init(void) 121 { 122 struct platform_device_info pdev_info = { 123 .name = MYBOARD_GPIO_CONTROLLER, 124 .id = PLATFORM_DEVID_NONE, 125 .swnode = &gpio_controller_node 126 }; 127 128 gpiod_add_lookup_table(&myboard_leds_gpios); 129 gpiod_add_lookup_table(&myboard_buttons_gpios); 130 131 platform_device_register_full(&pdev_info); 132 platform_device_register_data(NULL, "leds-gpio", -1, 133 &myboard_leds_pdata, sizeof(myboard_leds_pdata)); 134 platform_device_register_data(NULL, "gpio-keys", -1, 135 &myboard_buttons_pdata, 136 sizeof(myboard_buttons_pdata)); 137 138 return 0; 139 } 140 141After: Using Software Nodes 142~~~~~~~~~~~~~~~~~~~~~~~~~~~ 143 144Here is how the same configuration can be expressed using software nodes. 145 146Step 1: Define the GPIO Controller Node 147*************************************** 148 149First, define a software node that represents the GPIO controller that the 150LEDs and buttons are connected to. The ``name`` of this node is optional. 151 152.. code-block:: c 153 154 #include <linux/property.h> 155 #include <linux/gpio/property.h> 156 157 #define MYBOARD_GPIO_CONTROLLER "gpio-foo" 158 159 static const struct software_node myboard_gpio_controller_node = { 160 .name = MYBOARD_GPIO_CONTROLLER, 161 }; 162 163Step 2: Define Consumer Device Nodes and Properties 164*************************************************** 165 166Next, define the software nodes for the consumer devices (the LEDs and buttons). 167This involves creating a parent node for each device type and child nodes for 168each individual LED or button. 169 170.. code-block:: c 171 172 /* LED setup */ 173 static const struct software_node myboard_leds_node = { 174 .name = "myboard-leds", 175 }; 176 177 static const struct property_entry myboard_status_led_props[] = { 178 PROPERTY_ENTRY_STRING("label", "myboard:green:status"), 179 PROPERTY_ENTRY_STRING("linux,default-trigger", "heartbeat"), 180 PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 42, GPIO_ACTIVE_HIGH), 181 { } 182 }; 183 184 static const struct software_node myboard_status_led_swnode = { 185 .name = "status-led", 186 .parent = &myboard_leds_node, 187 .properties = myboard_status_led_props, 188 }; 189 190 /* Button setup */ 191 static const struct software_node myboard_keys_node = { 192 .name = "myboard-keys", 193 }; 194 195 static const struct property_entry myboard_wps_button_props[] = { 196 PROPERTY_ENTRY_STRING("label", "WPS Button"), 197 PROPERTY_ENTRY_U32("linux,code", KEY_WPS_BUTTON), 198 PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 15, GPIO_ACTIVE_LOW), 199 { } 200 }; 201 202 static const struct software_node myboard_wps_button_swnode = { 203 .name = "wps-button", 204 .parent = &myboard_keys_node, 205 .properties = myboard_wps_button_props, 206 }; 207 208 209 210Step 3: Group and Register the Nodes 211************************************ 212 213For maintainability, it is often beneficial to group all software nodes into a 214single array and register them with one call. 215 216.. code-block:: c 217 218 static const struct software_node * const myboard_swnodes[] = { 219 &myboard_gpio_controller_node, 220 &myboard_leds_node, 221 &myboard_status_led_swnode, 222 &myboard_keys_node, 223 &myboard_wps_button_swnode, 224 NULL 225 }; 226 227 static int __init myboard_init(void) 228 { 229 int error; 230 231 error = software_node_register_node_group(myboard_swnodes); 232 if (error) { 233 pr_err("Failed to register software nodes: %d\n", error); 234 return error; 235 } 236 237 // ... platform device registration follows 238 } 239 240.. note:: 241 When splitting registration of nodes by devices that they represent, it is 242 essential that the software node representing the GPIO controller itself 243 is registered first, before any of the nodes that reference it. 244 245Step 4: Register Platform Devices with Software Nodes 246***************************************************** 247 248Finally, register the platform devices and associate them with their respective 249software nodes using the ``fwnode`` field in struct platform_device_info. 250 251.. code-block:: c 252 253 static struct platform_device *leds_pdev; 254 static struct platform_device *keys_pdev; 255 256 static int __init myboard_init(void) 257 { 258 struct platform_device_info pdev_info; 259 int error; 260 261 error = software_node_register_node_group(myboard_swnodes); 262 if (error) 263 return error; 264 265 memset(&pdev_info, 0, sizeof(pdev_info)); 266 pdev_info.name = MYBOARD_GPIO_CONTROLLER; 267 pdev_info.id = PLATFORM_DEVID_NONE; 268 pdev_info.swnode = &myboard_gpio_controller_node; 269 gpio_pdev = platform_device_register_full(&pdev_info); 270 if (IS_ERR(gpio_pdev)) { 271 error = PTR_ERR(gpio_pdev); 272 goto err_unregister_nodes; 273 } 274 275 memset(&pdev_info, 0, sizeof(pdev_info)); 276 pdev_info.name = "leds-gpio"; 277 pdev_info.id = PLATFORM_DEVID_NONE; 278 pdev_info.fwnode = software_node_fwnode(&myboard_leds_node); 279 leds_pdev = platform_device_register_full(&pdev_info); 280 if (IS_ERR(leds_pdev)) { 281 error = PTR_ERR(leds_pdev); 282 platform_device_unregister(gpio_pdev); 283 goto err_unregister_nodes; 284 } 285 286 memset(&pdev_info, 0, sizeof(pdev_info)); 287 pdev_info.name = "gpio-keys"; 288 pdev_info.id = PLATFORM_DEVID_NONE; 289 pdev_info.fwnode = software_node_fwnode(&myboard_keys_node); 290 keys_pdev = platform_device_register_full(&pdev_info); 291 if (IS_ERR(keys_pdev)) { 292 error = PTR_ERR(keys_pdev); 293 platform_device_unregister(gpio_pdev); 294 platform_device_unregister(leds_pdev); 295 goto err_unregister_nodes; 296 } 297 298 return 0; 299 300 err_unregister_nodes: 301 software_node_unregister_node_group(myboard_swnodes); 302 return error; 303 } 304 305 static void __exit myboard_exit(void) 306 { 307 platform_device_unregister(keys_pdev); 308 platform_device_unregister(leds_pdev); 309 platform_device_unregister(gpio_pdev); 310 software_node_unregister_node_group(myboard_swnodes); 311 } 312 313With these changes, the generic ``leds-gpio`` and ``gpio-keys`` drivers will 314be able to probe successfully and get their configuration from the properties 315defined in the software nodes, removing the need for board-specific platform 316data. 317