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 "name" must match the controller's 40 "label".** The gpiolib core uses this name to find the corresponding 41 struct gpio_chip at runtime. 42 This software node has to be registered, but need not be attached to the 43 device representing the GPIO controller that is providing the GPIO in 44 question. It may be left as a "free floating" node. 45 462. **The GPIO property must be a reference.** The ``PROPERTY_ENTRY_GPIO()`` 47 macro handles this as it is an alias for ``PROPERTY_ENTRY_REF()``. 48 493. **The reference must have exactly two arguments:** 50 51 - The first argument is the GPIO offset within the controller. 52 - The second argument is the flags for the GPIO line (e.g., 53 GPIO_ACTIVE_HIGH, GPIO_ACTIVE_LOW). 54 55The ``PROPERTY_ENTRY_GPIO()`` macro is the preferred way of defining GPIO 56properties in software nodes. 57 58Conversion Example 59------------------ 60 61Let's walk through an example of converting a board file that defines a GPIO- 62connected LED and a button. 63 64Before: Using Platform Data 65~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 66 67A typical legacy board file might look like this: 68 69.. code-block:: c 70 71 #include <linux/platform_device.h> 72 #include <linux/leds.h> 73 #include <linux/gpio_keys.h> 74 #include <linux/gpio/machine.h> 75 76 #define MYBOARD_GPIO_CONTROLLER "gpio-foo" 77 78 /* LED setup */ 79 static const struct gpio_led myboard_leds[] = { 80 { 81 .name = "myboard:green:status", 82 .default_trigger = "heartbeat", 83 }, 84 }; 85 86 static const struct gpio_led_platform_data myboard_leds_pdata = { 87 .num_leds = ARRAY_SIZE(myboard_leds), 88 .leds = myboard_leds, 89 }; 90 91 static struct gpiod_lookup_table myboard_leds_gpios = { 92 .dev_id = "leds-gpio", 93 .table = { 94 GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 42, NULL, 0, GPIO_ACTIVE_HIGH), 95 { }, 96 }, 97 }; 98 99 /* Button setup */ 100 static struct gpio_keys_button myboard_buttons[] = { 101 { 102 .code = KEY_WPS_BUTTON, 103 .desc = "WPS Button", 104 .active_low = 1, 105 }, 106 }; 107 108 static const struct gpio_keys_platform_data myboard_buttons_pdata = { 109 .buttons = myboard_buttons, 110 .nbuttons = ARRAY_SIZE(myboard_buttons), 111 }; 112 113 static struct gpiod_lookup_table myboard_buttons_gpios = { 114 .dev_id = "gpio-keys", 115 .table = { 116 GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 15, NULL, 0, GPIO_ACTIVE_LOW), 117 { }, 118 }, 119 }; 120 121 /* Device registration */ 122 static int __init myboard_init(void) 123 { 124 gpiod_add_lookup_table(&myboard_leds_gpios); 125 gpiod_add_lookup_table(&myboard_buttons_gpios); 126 127 platform_device_register_data(NULL, "leds-gpio", -1, 128 &myboard_leds_pdata, sizeof(myboard_leds_pdata)); 129 platform_device_register_data(NULL, "gpio-keys", -1, 130 &myboard_buttons_pdata, sizeof(myboard_buttons_pdata)); 131 132 return 0; 133 } 134 135After: Using Software Nodes 136~~~~~~~~~~~~~~~~~~~~~~~~~~~ 137 138Here is how the same configuration can be expressed using software nodes. 139 140Step 1: Define the GPIO Controller Node 141*************************************** 142 143First, define a software node that represents the GPIO controller that the 144LEDs and buttons are connected to. The ``name`` of this node must match the 145name of the driver for the GPIO controller (e.g., "gpio-foo"). 146 147.. code-block:: c 148 149 #include <linux/property.h> 150 #include <linux/gpio/property.h> 151 152 #define MYBOARD_GPIO_CONTROLLER "gpio-foo" 153 154 static const struct software_node myboard_gpio_controller_node = { 155 .name = MYBOARD_GPIO_CONTROLLER, 156 }; 157 158Step 2: Define Consumer Device Nodes and Properties 159*************************************************** 160 161Next, define the software nodes for the consumer devices (the LEDs and buttons). 162This involves creating a parent node for each device type and child nodes for 163each individual LED or button. 164 165.. code-block:: c 166 167 /* LED setup */ 168 static const struct software_node myboard_leds_node = { 169 .name = "myboard-leds", 170 }; 171 172 static const struct property_entry myboard_status_led_props[] = { 173 PROPERTY_ENTRY_STRING("label", "myboard:green:status"), 174 PROPERTY_ENTRY_STRING("linux,default-trigger", "heartbeat"), 175 PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 42, GPIO_ACTIVE_HIGH), 176 { } 177 }; 178 179 static const struct software_node myboard_status_led_swnode = { 180 .name = "status-led", 181 .parent = &myboard_leds_node, 182 .properties = myboard_status_led_props, 183 }; 184 185 /* Button setup */ 186 static const struct software_node myboard_keys_node = { 187 .name = "myboard-keys", 188 }; 189 190 static const struct property_entry myboard_wps_button_props[] = { 191 PROPERTY_ENTRY_STRING("label", "WPS Button"), 192 PROPERTY_ENTRY_U32("linux,code", KEY_WPS_BUTTON), 193 PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 15, GPIO_ACTIVE_LOW), 194 { } 195 }; 196 197 static const struct software_node myboard_wps_button_swnode = { 198 .name = "wps-button", 199 .parent = &myboard_keys_node, 200 .properties = myboard_wps_button_props, 201 }; 202 203 204 205Step 3: Group and Register the Nodes 206************************************ 207 208For maintainability, it is often beneficial to group all software nodes into a 209single array and register them with one call. 210 211.. code-block:: c 212 213 static const struct software_node * const myboard_swnodes[] = { 214 &myboard_gpio_controller_node, 215 &myboard_leds_node, 216 &myboard_status_led_swnode, 217 &myboard_keys_node, 218 &myboard_wps_button_swnode, 219 NULL 220 }; 221 222 static int __init myboard_init(void) 223 { 224 int error; 225 226 error = software_node_register_node_group(myboard_swnodes); 227 if (error) { 228 pr_err("Failed to register software nodes: %d\n", error); 229 return error; 230 } 231 232 // ... platform device registration follows 233 } 234 235.. note:: 236 When splitting registration of nodes by devices that they represent, it is 237 essential that the software node representing the GPIO controller itself 238 is registered first, before any of the nodes that reference it. 239 240Step 4: Register Platform Devices with Software Nodes 241***************************************************** 242 243Finally, register the platform devices and associate them with their respective 244software nodes using the ``fwnode`` field in struct platform_device_info. 245 246.. code-block:: c 247 248 static struct platform_device *leds_pdev; 249 static struct platform_device *keys_pdev; 250 251 static int __init myboard_init(void) 252 { 253 struct platform_device_info pdev_info; 254 int error; 255 256 error = software_node_register_node_group(myboard_swnodes); 257 if (error) 258 return error; 259 260 memset(&pdev_info, 0, sizeof(pdev_info)); 261 pdev_info.name = "leds-gpio"; 262 pdev_info.id = PLATFORM_DEVID_NONE; 263 pdev_info.fwnode = software_node_fwnode(&myboard_leds_node); 264 leds_pdev = platform_device_register_full(&pdev_info); 265 if (IS_ERR(leds_pdev)) { 266 error = PTR_ERR(leds_pdev); 267 goto err_unregister_nodes; 268 } 269 270 memset(&pdev_info, 0, sizeof(pdev_info)); 271 pdev_info.name = "gpio-keys"; 272 pdev_info.id = PLATFORM_DEVID_NONE; 273 pdev_info.fwnode = software_node_fwnode(&myboard_keys_node); 274 keys_pdev = platform_device_register_full(&pdev_info); 275 if (IS_ERR(keys_pdev)) { 276 error = PTR_ERR(keys_pdev); 277 platform_device_unregister(leds_pdev); 278 goto err_unregister_nodes; 279 } 280 281 return 0; 282 283 err_unregister_nodes: 284 software_node_unregister_node_group(myboard_swnodes); 285 return error; 286 } 287 288 static void __exit myboard_exit(void) 289 { 290 platform_device_unregister(keys_pdev); 291 platform_device_unregister(leds_pdev); 292 software_node_unregister_node_group(myboard_swnodes); 293 } 294 295With these changes, the generic ``leds-gpio`` and ``gpio-keys`` drivers will 296be able to probe successfully and get their configuration from the properties 297defined in the software nodes, removing the need for board-specific platform 298data. 299