xref: /linux/Documentation/driver-api/gpio/legacy-boards.rst (revision 53597deca0e38c30e6cd4ba2114fa42d2bcd85bb)
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