€•¿€Œsphinx.addnodes”Œdocument”“”)”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)”}”(hhh]”(hŒ pending_xref”“”)”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…””}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ1/translations/zh_CN/driver-api/gpio/legacy-boards”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)”}”(hhh]”hŒChinese (Traditional)”…””}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/zh_TW/driver-api/gpio/legacy-boards”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒItalian”…””}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/it_IT/driver-api/gpio/legacy-boards”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒJapanese”…””}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/ja_JP/driver-api/gpio/legacy-boards”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒKorean”…””}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/ko_KR/driver-api/gpio/legacy-boards”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒPortuguese (Brazilian)”…””}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/pt_BR/driver-api/gpio/legacy-boards”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)”}”(hhh]”hŒSpanish”…””}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ1/translations/sp_SP/driver-api/gpio/legacy-boards”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒsection”“”)”}”(hhh]”(hŒtitle”“”)”}”(hŒSupporting Legacy Boards”h]”hŒSupporting Legacy Boards”…””}”(hh¼h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhh·h²hh³ŒK/var/lib/git/docbuild/linux/Documentation/driver-api/gpio/legacy-boards.rst”h´KubhŒ paragraph”“”)”}”(hXMany drivers in the kernel, such as ``leds-gpio`` and ``gpio-keys``, are migrating away from using board-specific ``platform_data`` to a unified device properties interface. This interface allows drivers to be simpler and more generic, as they can query properties in a standardized way.”h]”(hŒ$Many drivers in the kernel, such as ”…””}”(hhÍh²hh³Nh´NubhŒliteral”“”)”}”(hŒ ``leds-gpio``”h]”hŒ leds-gpio”…””}”(hh×h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhhÍubhŒ and ”…””}”(hhÍh²hh³Nh´NubhÖ)”}”(hŒ ``gpio-keys``”h]”hŒ gpio-keys”…””}”(hhéh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhhÍubhŒ/, are migrating away from using board-specific ”…””}”(hhÍh²hh³Nh´NubhÖ)”}”(hŒ``platform_data``”h]”hŒ platform_data”…””}”(hhûh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhhÍubhŒœ to a unified device properties interface. This interface allows drivers to be simpler and more generic, as they can query properties in a standardized way.”…””}”(hhÍh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khh·h²hubhÌ)”}”(hXbOn modern systems, these properties are provided via device tree. However, some older platforms have not been converted to device tree and instead rely on board files to describe their hardware configuration. To bridge this gap and allow these legacy boards to work with modern, generic drivers, the kernel provides a mechanism called **software nodes**.”h]”(hXOOn modern systems, these properties are provided via device tree. However, some older platforms have not been converted to device tree and instead rely on board files to describe their hardware configuration. To bridge this gap and allow these legacy boards to work with modern, generic drivers, the kernel provides a mechanism called ”…””}”(hjh²hh³Nh´NubhŒstrong”“”)”}”(hŒ**software nodes**”h]”hŒsoftware nodes”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubhŒ.”…””}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K hh·h²hubhÌ)”}”(hŒÈThis document provides a guide on how to convert a legacy board file from using ``platform_data`` and ``gpiod_lookup_table`` to the modern software node approach for describing GPIO-connected devices.”h]”(hŒPThis document provides a guide on how to convert a legacy board file from using ”…””}”(hj5h²hh³Nh´NubhÖ)”}”(hŒ``platform_data``”h]”hŒ platform_data”…””}”(hj=h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj5ubhŒ and ”…””}”(hj5h²hh³Nh´NubhÖ)”}”(hŒ``gpiod_lookup_table``”h]”hŒgpiod_lookup_table”…””}”(hjOh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj5ubhŒL to the modern software node approach for describing GPIO-connected devices.”…””}”(hj5h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khh·h²hubh¶)”}”(hhh]”(h»)”}”(hŒThe Core Idea: Software Nodes”h]”hŒThe Core Idea: Software Nodes”…””}”(hjjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjgh²hh³hÊh´KubhÌ)”}”(hXœSoftware nodes allow board-specific code to construct an in-memory, device-tree-like structure using struct software_node and struct property_entry. This structure can then be associated with a platform device, allowing drivers to use the standard device properties API (e.g., device_property_read_u32(), device_property_read_string()) to query configuration, just as they would on an ACPI or device tree system.”h]”hXœSoftware nodes allow board-specific code to construct an in-memory, device-tree-like structure using struct software_node and struct property_entry. This structure can then be associated with a platform device, allowing drivers to use the standard device properties API (e.g., device_property_read_u32(), device_property_read_string()) to query configuration, just as they would on an ACPI or device tree system.”…””}”(hjxh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khjgh²hubhÌ)”}”(hŒÞThe gpiolib code has support for handling software nodes, so that if GPIO is described properly, as detailed in the section below, then regular gpiolib APIs, such as gpiod_get(), gpiod_get_optional(), and others will work.”h]”hŒÞThe gpiolib code has support for handling software nodes, so that if GPIO is described properly, as detailed in the section below, then regular gpiolib APIs, such as gpiod_get(), gpiod_get_optional(), and others will work.”…””}”(hj†h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khjgh²hubh¶)”}”(hhh]”(h»)”}”(hŒ Requirements for GPIO Properties”h]”hŒ Requirements for GPIO Properties”…””}”(hj—h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj”h²hh³hÊh´K"ubhÌ)”}”(hŒ”When using software nodes to describe GPIO connections, the following requirements must be met for the GPIO core to correctly resolve the reference:”h]”hŒ”When using software nodes to describe GPIO connections, the following requirements must be met for the GPIO core to correctly resolve the reference:”…””}”(hj¥h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K$hj”h²hubhŒenumerated_list”“”)”}”(hhh]”(hŒ list_item”“”)”}”(hX**The GPIO controller's software node must be registered and attached to the controller's ``struct device`` either as its primary or secondary firmware node.** The gpiolib core uses the address of the firmware node to find the corresponding ``struct gpio_chip`` at runtime. ”h]”hÌ)”}”(hX**The GPIO controller's software node must be registered and attached to the controller's ``struct device`` either as its primary or secondary firmware node.** The gpiolib core uses the address of the firmware node to find the corresponding ``struct gpio_chip`` at runtime.”h]”(j)”}”(hŒŸ**The GPIO controller's software node must be registered and attached to the controller's ``struct device`` either as its primary or secondary firmware node.**”h]”hŒŸThe GPIO controller’s software node must be registered and attached to the controller’s ``struct device`` either as its primary or secondary firmware node.”…””}”(hjÂh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj¾ubhŒR The gpiolib core uses the address of the firmware node to find the corresponding ”…””}”(hj¾h²hh³Nh´NubhÖ)”}”(hŒ``struct gpio_chip``”h]”hŒstruct gpio_chip”…””}”(hjÔh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj¾ubhŒ at runtime.”…””}”(hj¾h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K'hjºubah}”(h]”h ]”h"]”h$]”h&]”uh1j¸hjµh²hh³hÊh´Nubj¹)”}”(hŒŒ**The GPIO property must be a reference.** The ``PROPERTY_ENTRY_GPIO()`` macro handles this as it is an alias for ``PROPERTY_ENTRY_REF()``. ”h]”hÌ)”}”(hŒ‹**The GPIO property must be a reference.** The ``PROPERTY_ENTRY_GPIO()`` macro handles this as it is an alias for ``PROPERTY_ENTRY_REF()``.”h]”(j)”}”(hŒ***The GPIO property must be a reference.**”h]”hŒ&The GPIO property must be a reference.”…””}”(hjúh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjöubhŒ The ”…””}”(hjöh²hh³Nh´NubhÖ)”}”(hŒ``PROPERTY_ENTRY_GPIO()``”h]”hŒPROPERTY_ENTRY_GPIO()”…””}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjöubhŒ* macro handles this as it is an alias for ”…””}”(hjöh²hh³Nh´NubhÖ)”}”(hŒ``PROPERTY_ENTRY_REF()``”h]”hŒPROPERTY_ENTRY_REF()”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjöubhŒ.”…””}”(hjöh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K,hjòubah}”(h]”h ]”h"]”h$]”h&]”uh1j¸hjµh²hh³hÊh´Nubj¹)”}”(hŒÕ**The reference must have exactly two arguments:** - The first argument is the GPIO offset within the controller. - The second argument is the flags for the GPIO line (e.g., GPIO_ACTIVE_HIGH, GPIO_ACTIVE_LOW). ”h]”(hÌ)”}”(hŒ2**The reference must have exactly two arguments:**”h]”j)”}”(hjBh]”hŒ.The reference must have exactly two arguments:”…””}”(hjDh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj@ubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K/hj<ubhŒ bullet_list”“”)”}”(hhh]”(j¹)”}”(hŒ #include #include #include #define MYBOARD_GPIO_CONTROLLER "gpio-foo" /* LED setup */ static const struct gpio_led myboard_leds[] = { { .name = "myboard:green:status", .default_trigger = "heartbeat", }, }; static const struct gpio_led_platform_data myboard_leds_pdata = { .num_leds = ARRAY_SIZE(myboard_leds), .leds = myboard_leds, }; static struct gpiod_lookup_table myboard_leds_gpios = { .dev_id = "leds-gpio", .table = { GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 42, NULL, 0, GPIO_ACTIVE_HIGH), { }, }, }; /* Button setup */ static struct gpio_keys_button myboard_buttons[] = { { .code = KEY_WPS_BUTTON, .desc = "WPS Button", .active_low = 1, }, }; static const struct gpio_keys_platform_data myboard_buttons_pdata = { .buttons = myboard_buttons, .nbuttons = ARRAY_SIZE(myboard_buttons), }; static struct gpiod_lookup_table myboard_buttons_gpios = { .dev_id = "gpio-keys", .table = { GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 15, NULL, 0, GPIO_ACTIVE_LOW), { }, }, }; /* Device registration */ static int __init myboard_init(void) { struct platform_device_info pdev_info = { .name = MYBOARD_GPIO_CONTROLLER, .id = PLATFORM_DEVID_NONE, .swnode = &gpio_controller_node }; gpiod_add_lookup_table(&myboard_leds_gpios); gpiod_add_lookup_table(&myboard_buttons_gpios); platform_device_register_full(&pdev_info); platform_device_register_data(NULL, "leds-gpio", -1, &myboard_leds_pdata, sizeof(myboard_leds_pdata)); platform_device_register_data(NULL, "gpio-keys", -1, &myboard_buttons_pdata, sizeof(myboard_buttons_pdata)); return 0; }”h]”hXû#include #include #include #include #define MYBOARD_GPIO_CONTROLLER "gpio-foo" /* LED setup */ static const struct gpio_led myboard_leds[] = { { .name = "myboard:green:status", .default_trigger = "heartbeat", }, }; static const struct gpio_led_platform_data myboard_leds_pdata = { .num_leds = ARRAY_SIZE(myboard_leds), .leds = myboard_leds, }; static struct gpiod_lookup_table myboard_leds_gpios = { .dev_id = "leds-gpio", .table = { GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 42, NULL, 0, GPIO_ACTIVE_HIGH), { }, }, }; /* Button setup */ static struct gpio_keys_button myboard_buttons[] = { { .code = KEY_WPS_BUTTON, .desc = "WPS Button", .active_low = 1, }, }; static const struct gpio_keys_platform_data myboard_buttons_pdata = { .buttons = myboard_buttons, .nbuttons = ARRAY_SIZE(myboard_buttons), }; static struct gpiod_lookup_table myboard_buttons_gpios = { .dev_id = "gpio-keys", .table = { GPIO_LOOKUP_IDX(MYBOARD_GPIO_CONTROLLER, 15, NULL, 0, GPIO_ACTIVE_LOW), { }, }, }; /* Device registration */ static int __init myboard_init(void) { struct platform_device_info pdev_info = { .name = MYBOARD_GPIO_CONTROLLER, .id = PLATFORM_DEVID_NONE, .swnode = &gpio_controller_node }; gpiod_add_lookup_table(&myboard_leds_gpios); gpiod_add_lookup_table(&myboard_buttons_gpios); platform_device_register_full(&pdev_info); platform_device_register_data(NULL, "leds-gpio", -1, &myboard_leds_pdata, sizeof(myboard_leds_pdata)); platform_device_register_data(NULL, "gpio-keys", -1, &myboard_buttons_pdata, sizeof(myboard_buttons_pdata)); return 0; }”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”Œforce”‰Œlanguage”Œc”Œhighlight_args”}”uh1jh³hÊh´KChjóh²hubeh}”(h]”Œbefore-using-platform-data”ah ]”h"]”Œbefore: using platform data”ah$]”h&]”uh1hµhjÔh²hh³hÊh´K?ubh¶)”}”(hhh]”(h»)”}”(hŒAfter: Using Software Nodes”h]”hŒAfter: Using Software Nodes”…””}”(hj4h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj1h²hh³hÊh´KŽubhÌ)”}”(hŒIHere is how the same configuration can be expressed using software nodes.”h]”hŒIHere is how the same configuration can be expressed using software nodes.”…””}”(hjBh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Khj1h²hubh¶)”}”(hhh]”(h»)”}”(hŒ'Step 1: Define the GPIO Controller Node”h]”hŒ'Step 1: Define the GPIO Controller Node”…””}”(hjSh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjPh²hh³hÊh´K“ubhÌ)”}”(hŒ”First, define a software node that represents the GPIO controller that the LEDs and buttons are connected to. The ``name`` of this node is optional.”h]”(hŒrFirst, define a software node that represents the GPIO controller that the LEDs and buttons are connected to. The ”…””}”(hjah²hh³Nh´NubhÖ)”}”(hŒ``name``”h]”hŒname”…””}”(hjih²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhjaubhŒ of this node is optional.”…””}”(hjah²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K•hjPh²hubj)”}”(hŒÖ#include #include #define MYBOARD_GPIO_CONTROLLER "gpio-foo" static const struct software_node myboard_gpio_controller_node = { .name = MYBOARD_GPIO_CONTROLLER, };”h]”hŒÖ#include #include #define MYBOARD_GPIO_CONTROLLER "gpio-foo" static const struct software_node myboard_gpio_controller_node = { .name = MYBOARD_GPIO_CONTROLLER, };”…””}”hjsbah}”(h]”h ]”h"]”h$]”h&]”j"j#j$‰j%j&j'}”uh1jh³hÊh´K˜hjPh²hubeh}”(h]”Œ&step-1-define-the-gpio-controller-node”ah ]”h"]”Œ'step 1: define the gpio controller node”ah$]”h&]”uh1hµhj1h²hh³hÊh´K“ubh¶)”}”(hhh]”(h»)”}”(hŒ3Step 2: Define Consumer Device Nodes and Properties”h]”hŒ3Step 2: Define Consumer Device Nodes and Properties”…””}”(hj›h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhj˜h²hh³hÊh´K¤ubhÌ)”}”(hŒ½Next, define the software nodes for the consumer devices (the LEDs and buttons). This involves creating a parent node for each device type and child nodes for each individual LED or button.”h]”hŒ½Next, define the software nodes for the consumer devices (the LEDs and buttons). This involves creating a parent node for each device type and child nodes for each individual LED or button.”…””}”(hj©h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´K¦hj˜h²hubj)”}”(hXw/* LED setup */ static const struct software_node myboard_leds_node = { .name = "myboard-leds", }; static const struct property_entry myboard_status_led_props[] = { PROPERTY_ENTRY_STRING("label", "myboard:green:status"), PROPERTY_ENTRY_STRING("linux,default-trigger", "heartbeat"), PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 42, GPIO_ACTIVE_HIGH), { } }; static const struct software_node myboard_status_led_swnode = { .name = "status-led", .parent = &myboard_leds_node, .properties = myboard_status_led_props, }; /* Button setup */ static const struct software_node myboard_keys_node = { .name = "myboard-keys", }; static const struct property_entry myboard_wps_button_props[] = { PROPERTY_ENTRY_STRING("label", "WPS Button"), PROPERTY_ENTRY_U32("linux,code", KEY_WPS_BUTTON), PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 15, GPIO_ACTIVE_LOW), { } }; static const struct software_node myboard_wps_button_swnode = { .name = "wps-button", .parent = &myboard_keys_node, .properties = myboard_wps_button_props, };”h]”hXw/* LED setup */ static const struct software_node myboard_leds_node = { .name = "myboard-leds", }; static const struct property_entry myboard_status_led_props[] = { PROPERTY_ENTRY_STRING("label", "myboard:green:status"), PROPERTY_ENTRY_STRING("linux,default-trigger", "heartbeat"), PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 42, GPIO_ACTIVE_HIGH), { } }; static const struct software_node myboard_status_led_swnode = { .name = "status-led", .parent = &myboard_leds_node, .properties = myboard_status_led_props, }; /* Button setup */ static const struct software_node myboard_keys_node = { .name = "myboard-keys", }; static const struct property_entry myboard_wps_button_props[] = { PROPERTY_ENTRY_STRING("label", "WPS Button"), PROPERTY_ENTRY_U32("linux,code", KEY_WPS_BUTTON), PROPERTY_ENTRY_GPIO("gpios", &myboard_gpio_controller_node, 15, GPIO_ACTIVE_LOW), { } }; static const struct software_node myboard_wps_button_swnode = { .name = "wps-button", .parent = &myboard_keys_node, .properties = myboard_wps_button_props, };”…””}”hj·sbah}”(h]”h ]”h"]”h$]”h&]”j"j#j$‰j%j&j'}”uh1jh³hÊh´Kªhj˜h²hubeh}”(h]”Œ2step-2-define-consumer-device-nodes-and-properties”ah ]”h"]”Œ3step 2: define consumer device nodes and properties”ah$]”h&]”uh1hµhj1h²hh³hÊh´K¤ubh¶)”}”(hhh]”(h»)”}”(hŒ$Step 3: Group and Register the Nodes”h]”hŒ$Step 3: Group and Register the Nodes”…””}”(hjÑh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjÎh²hh³hÊh´KÓubhÌ)”}”(hŒ|For maintainability, it is often beneficial to group all software nodes into a single array and register them with one call.”h]”hŒ|For maintainability, it is often beneficial to group all software nodes into a single array and register them with one call.”…””}”(hjßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´KÕhjÎh²hubj)”}”(hXstatic const struct software_node * const myboard_swnodes[] = { &myboard_gpio_controller_node, &myboard_leds_node, &myboard_status_led_swnode, &myboard_keys_node, &myboard_wps_button_swnode, NULL }; static int __init myboard_init(void) { int error; error = software_node_register_node_group(myboard_swnodes); if (error) { pr_err("Failed to register software nodes: %d\n", error); return error; } // ... platform device registration follows }”h]”hXstatic const struct software_node * const myboard_swnodes[] = { &myboard_gpio_controller_node, &myboard_leds_node, &myboard_status_led_swnode, &myboard_keys_node, &myboard_wps_button_swnode, NULL }; static int __init myboard_init(void) { int error; error = software_node_register_node_group(myboard_swnodes); if (error) { pr_err("Failed to register software nodes: %d\n", error); return error; } // ... platform device registration follows }”…””}”hjísbah}”(h]”h ]”h"]”h$]”h&]”j"j#j$‰j%j&j'}”uh1jh³hÊh´KØhjÎh²hubhŒnote”“”)”}”(hŒÓWhen splitting registration of nodes by devices that they represent, it is essential that the software node representing the GPIO controller itself is registered first, before any of the nodes that reference it.”h]”hÌ)”}”(hŒÓWhen splitting registration of nodes by devices that they represent, it is essential that the software node representing the GPIO controller itself is registered first, before any of the nodes that reference it.”h]”hŒÓWhen splitting registration of nodes by devices that they represent, it is essential that the software node representing the GPIO controller itself is registered first, before any of the nodes that reference it.”…””}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Kñhjþubah}”(h]”h ]”h"]”h$]”h&]”uh1jühjÎh²hh³hÊh´Nubeh}”(h]”Œ#step-3-group-and-register-the-nodes”ah ]”h"]”Œ$step 3: group and register the nodes”ah$]”h&]”uh1hµhj1h²hh³hÊh´KÓubh¶)”}”(hhh]”(h»)”}”(hŒ5Step 4: Register Platform Devices with Software Nodes”h]”hŒ5Step 4: Register Platform Devices with Software Nodes”…””}”(hj!h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hºhjh²hh³hÊh´KöubhÌ)”}”(hŒ™Finally, register the platform devices and associate them with their respective software nodes using the ``fwnode`` field in struct platform_device_info.”h]”(hŒiFinally, register the platform devices and associate them with their respective software nodes using the ”…””}”(hj/h²hh³Nh´NubhÖ)”}”(hŒ ``fwnode``”h]”hŒfwnode”…””}”(hj7h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj/ubhŒ& field in struct platform_device_info.”…””}”(hj/h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´Køhjh²hubj)”}”(hXœstatic struct platform_device *leds_pdev; static struct platform_device *keys_pdev; static int __init myboard_init(void) { struct platform_device_info pdev_info; int error; error = software_node_register_node_group(myboard_swnodes); if (error) return error; memset(&pdev_info, 0, sizeof(pdev_info)); pdev_info.name = MYBOARD_GPIO_CONTROLLER; pdev_info.id = PLATFORM_DEVID_NONE; pdev_info.swnode = &myboard_gpio_controller_node; gpio_pdev = platform_device_register_full(&pdev_info); if (IS_ERR(gpio_pdev)) { error = PTR_ERR(gpio_pdev); goto err_unregister_nodes; } memset(&pdev_info, 0, sizeof(pdev_info)); pdev_info.name = "leds-gpio"; pdev_info.id = PLATFORM_DEVID_NONE; pdev_info.fwnode = software_node_fwnode(&myboard_leds_node); leds_pdev = platform_device_register_full(&pdev_info); if (IS_ERR(leds_pdev)) { error = PTR_ERR(leds_pdev); platform_device_unregister(gpio_pdev); goto err_unregister_nodes; } memset(&pdev_info, 0, sizeof(pdev_info)); pdev_info.name = "gpio-keys"; pdev_info.id = PLATFORM_DEVID_NONE; pdev_info.fwnode = software_node_fwnode(&myboard_keys_node); keys_pdev = platform_device_register_full(&pdev_info); if (IS_ERR(keys_pdev)) { error = PTR_ERR(keys_pdev); platform_device_unregister(gpio_pdev); platform_device_unregister(leds_pdev); goto err_unregister_nodes; } return 0; err_unregister_nodes: software_node_unregister_node_group(myboard_swnodes); return error; } static void __exit myboard_exit(void) { platform_device_unregister(keys_pdev); platform_device_unregister(leds_pdev); platform_device_unregister(gpio_pdev); software_node_unregister_node_group(myboard_swnodes); }”h]”hXœstatic struct platform_device *leds_pdev; static struct platform_device *keys_pdev; static int __init myboard_init(void) { struct platform_device_info pdev_info; int error; error = software_node_register_node_group(myboard_swnodes); if (error) return error; memset(&pdev_info, 0, sizeof(pdev_info)); pdev_info.name = MYBOARD_GPIO_CONTROLLER; pdev_info.id = PLATFORM_DEVID_NONE; pdev_info.swnode = &myboard_gpio_controller_node; gpio_pdev = platform_device_register_full(&pdev_info); if (IS_ERR(gpio_pdev)) { error = PTR_ERR(gpio_pdev); goto err_unregister_nodes; } memset(&pdev_info, 0, sizeof(pdev_info)); pdev_info.name = "leds-gpio"; pdev_info.id = PLATFORM_DEVID_NONE; pdev_info.fwnode = software_node_fwnode(&myboard_leds_node); leds_pdev = platform_device_register_full(&pdev_info); if (IS_ERR(leds_pdev)) { error = PTR_ERR(leds_pdev); platform_device_unregister(gpio_pdev); goto err_unregister_nodes; } memset(&pdev_info, 0, sizeof(pdev_info)); pdev_info.name = "gpio-keys"; pdev_info.id = PLATFORM_DEVID_NONE; pdev_info.fwnode = software_node_fwnode(&myboard_keys_node); keys_pdev = platform_device_register_full(&pdev_info); if (IS_ERR(keys_pdev)) { error = PTR_ERR(keys_pdev); platform_device_unregister(gpio_pdev); platform_device_unregister(leds_pdev); goto err_unregister_nodes; } return 0; err_unregister_nodes: software_node_unregister_node_group(myboard_swnodes); return error; } static void __exit myboard_exit(void) { platform_device_unregister(keys_pdev); platform_device_unregister(leds_pdev); platform_device_unregister(gpio_pdev); software_node_unregister_node_group(myboard_swnodes); }”…””}”hjOsbah}”(h]”h ]”h"]”h$]”h&]”j"j#j$‰j%j&j'}”uh1jh³hÊh´Kûhjh²hubhÌ)”}”(hŒíWith these changes, the generic ``leds-gpio`` and ``gpio-keys`` drivers will be able to probe successfully and get their configuration from the properties defined in the software nodes, removing the need for board-specific platform data.”h]”(hŒ With these changes, the generic ”…””}”(hj^h²hh³Nh´NubhÖ)”}”(hŒ ``leds-gpio``”h]”hŒ leds-gpio”…””}”(hjfh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj^ubhŒ and ”…””}”(hj^h²hh³Nh´NubhÖ)”}”(hŒ ``gpio-keys``”h]”hŒ gpio-keys”…””}”(hjxh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÕhj^ubhŒ® drivers will be able to probe successfully and get their configuration from the properties defined in the software nodes, removing the need for board-specific platform data.”…””}”(hj^h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hËh³hÊh´M9hjh²hubeh}”(h]”Œ4step-4-register-platform-devices-with-software-nodes”ah ]”h"]”Œ5step 4: register platform devices with software nodes”ah$]”h&]”uh1hµhj1h²hh³hÊh´Köubeh}”(h]”Œafter-using-software-nodes”ah ]”h"]”Œafter: using software nodes”ah$]”h&]”uh1hµhjÔh²hh³hÊh´KŽubeh}”(h]”Œconversion-example”ah ]”h"]”Œconversion example”ah$]”h&]”uh1hµhh·h²hh³hÊh´K9ubeh}”(h]”Œsupporting-legacy-boards”ah ]”h"]”Œsupporting legacy boards”ah$]”h&]”uh1hµhhh²hh³hÊh´Kubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÊuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)”}”(hºNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”jÓŒerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÊŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”Œnameids”}”(j­jªjÑjÎjÉjÆj¥j¢j.j+jjšj•j’jËjÈjjj•j’uŒ nametypes”}”(j­‰jщjɉj¥‰j.‰j‰j•‰jˉj‰j•‰uh}”(jªh·jÎjgjÆj”j¢jÔj+jójšj1j’jPjÈj˜jjÎj’juŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”Œ transformer”NŒ include_log”]”Œ decoration”Nh²hub.