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