€•czŒ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Œ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 ”…””}”(hhÿhžhhŸNh NubhŒstrong”“”)”}”(hŒ**software nodes**”h]”hŒsoftware nodes”…””}”(hj hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhhÿubhŒ.”…””}”(hhÿhž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 ”…””}”(hj!hžhhŸNh NubhÂ)”}”(hŒ``platform_data``”h]”hŒ platform_data”…””}”(hj)hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÁhj!ubhŒ and ”…””}”(hj!hžhhŸNh NubhÂ)”}”(hŒ``gpiod_lookup_table``”h]”hŒgpiod_lookup_table”…””}”(hj;hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÁhj!ubhŒL to the modern software node approach for describing GPIO-connected devices.”…””}”(hj!hž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”…””}”(hjVhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjShž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.”…””}”(hjdhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KhjShž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.”…””}”(hjrhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KhjShž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”“”)”}”(hXn**The GPIO controller's software node "name" must match the controller's "label".** The gpiolib core uses this name to find the corresponding struct gpio_chip at runtime. This software node has to be registered, but need not be attached to the device representing the GPIO controller that is providing the GPIO in question. It may be left as a "free floating" node. ”h]”h¸)”}”(hXm**The GPIO controller's software node "name" must match the controller's "label".** The gpiolib core uses this name to find the corresponding struct gpio_chip at runtime. This software node has to be registered, but need not be attached to the device representing the GPIO controller that is providing the GPIO in question. It may be left as a "free floating" node.”h]”(j)”}”(hŒS**The GPIO controller's software node "name" must match the controller's "label".**”h]”hŒ[The GPIO controller’s software node “name†must match the controller’s “labelâ€.”…””}”(hj®hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjªubhX The gpiolib core uses this name to find the corresponding struct gpio_chip at runtime. This software node has to be registered, but need not be attached to the device representing the GPIO controller that is providing the GPIO in question. It may be left as a “free floating†node.”…””}”(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()”…””}”(hjøhž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)”}”(hjh]”hŒ.The reference must have exactly two arguments:”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h K1hjubhŒ 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) { gpiod_add_lookup_table(&myboard_leds_gpios); gpiod_add_lookup_table(&myboard_buttons_gpios); 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) { gpiod_add_lookup_table(&myboard_leds_gpios); gpiod_add_lookup_table(&myboard_buttons_gpios); 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; }”…””}”hjîsbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”Œforce”‰Œlanguage”Œc”Œhighlight_args”}”uh1jìhŸh¶h KEhjÍhžhubeh}”(h]”Œbefore-using-platform-data”ah ]”h"]”Œbefore: using platform data”ah$]”h&]”uh1h¡hj®hžhhŸh¶h KAubh¢)”}”(hhh]”(h§)”}”(hŒAfter: Using Software Nodes”h]”hŒAfter: Using Software Nodes”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj hž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.”…””}”(hjhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h KŠhj hžhubh¢)”}”(hhh]”(h§)”}”(hŒ'Step 1: Define the GPIO Controller Node”h]”hŒ'Step 1: Define the GPIO Controller Node”…””}”(hj-hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hj*hžhhŸh¶h Kubh¸)”}”(hŒÕFirst, define a software node that represents the GPIO controller that the LEDs and buttons are connected to. The ``name`` of this node must match the name of the driver for the GPIO controller (e.g., "gpio-foo").”h]”(hŒrFirst, define a software node that represents the GPIO controller that the LEDs and buttons are connected to. The ”…””}”(hj;hžhhŸNh NubhÂ)”}”(hŒ``name``”h]”hŒname”…””}”(hjChžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÁhj;ubhŒ_ of this node must match the name of the driver for the GPIO controller (e.g., “gpio-fooâ€).”…””}”(hj;hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h Khj*hž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, };”…””}”hj[sbah}”(h]”h ]”h"]”h$]”h&]”jüjýjþ‰jÿjj}”uh1jìhŸh¶h K“hj*hžhubeh}”(h]”Œ&step-1-define-the-gpio-controller-node”ah ]”h"]”Œ'step 1: define the gpio controller node”ah$]”h&]”uh1h¡hj hžhhŸh¶h Kubh¢)”}”(hhh]”(h§)”}”(hŒ3Step 2: Define Consumer Device Nodes and Properties”h]”hŒ3Step 2: Define Consumer Device Nodes and Properties”…””}”(hjuhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1h¦hjrhž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¡hjrhž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ÿjj}”uh1jìhŸh¶h K¥hjrhžhubeh}”(h]”Œ2step-2-define-consumer-device-nodes-and-properties”ah ]”h"]”Œ3step 2: define consumer device nodes and properties”ah$]”h&]”uh1h¡hj hž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ÿjj}”uh1jìhŸ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.”…””}”(hjÜhž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¡hj hž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¦hjøhž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”…””}”(hjhž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óhjøhž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 = "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); 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(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); 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 = "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); 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(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); software_node_unregister_node_group(myboard_swnodes); }”…””}”hj)sbah}”(h]”h ]”h"]”h$]”h&]”jüjýjþ‰jÿjj}”uh1jìhŸh¶h Köhjøhž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 ”…””}”(hj8hžhhŸNh NubhÂ)”}”(hŒ ``leds-gpio``”h]”hŒ leds-gpio”…””}”(hj@hžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÁhj8ubhŒ and ”…””}”(hj8hžhhŸNh NubhÂ)”}”(hŒ ``gpio-keys``”h]”hŒ gpio-keys”…””}”(hjRhžhhŸNh Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÁhj8ubhŒ® 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.”…””}”(hj8hžhhŸNh Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1h·hŸh¶h M'hjøhžhubeh}”(h]”Œ4step-4-register-platform-devices-with-software-nodes”ah ]”h"]”Œ5step 4: register platform devices with software nodes”ah$]”h&]”uh1h¡hj hž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 K;ubeh}”(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 jj|jjjwjtjojlj¥j¢jõjòjojluŒ nametypes”}”(j‡‰j«‰j£‰j‰j‰jw‰jo‰j¥‰jõ‰jo‰uh}”(j„h£j¨jSj j€j|j®jjÍjtj jlj*j¢jrjòj¨jljøuŒ 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.