diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-04 12:33:38 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-04 12:33:38 -0800 |
| commit | 500920fa76819b4909a32081e153bce80ce74824 (patch) | |
| tree | 5a030b34c37f9ed942e01d2795dec543af279589 /drivers/reset | |
| parent | 205f1a0d188658ff3043d91c988378d8a81344c2 (diff) | |
| parent | dae9750105cf93ac1e156ef91f4beeb53bd64777 (diff) | |
| download | linux-500920fa76819b4909a32081e153bce80ce74824.tar.gz linux-500920fa76819b4909a32081e153bce80ce74824.tar.bz2 linux-500920fa76819b4909a32081e153bce80ce74824.zip | |
Merge tag 'gpio-updates-for-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
"There's one new driver, lots of various updates to existing ones, some
refactoring support for new models and misc tweaks and fixes.
The biggest new feature in GPIO core is adding support for managed,
enable-counted sharing of GPIO pins, something that - until now - was
only hacked around with the GPIOD_FLAGS_BIT_NONEXCLUSIVE request flag
which basically allowed drivers to "fight it out" for the descriptor
and provided no synchronization. It was enabled on Qualcomm platforms
(and thus is enabled on arm64 defconfig) and I plan on removing
GPIOD_FLAGS_BIT_NONEXCLUSIVE once all drivers using it are switched to
the new mechanism.
GPIO core:
- add proper support for shared GPIOs that's aiming to replace the
current sharing mechanism (which provides no synchronization ot
enable counting) and enable it for Qualcomm platforms
- improve the software node GPIO lookup by using the fwnode
representation instead of the software node's name which was prone
to bugs (GPIO controllers don't have to use the software node's
name as their kernel label)
- remove the last user of legacy-of-mm-gpiochip.h and drop the header
- move closer to removing the legacy gpio_request_one() routine
- rename some symbols for consistency
- shrink GPIO printk() helpers by reusing existing code
- remove some redundant kernel messages
- use min() instead of min_t() in GPIO ACPI code
- use system_percpu_wq instead of system_wq in GPIO character device
code
New drivers:
- add a driver for the QIXIS FPGA GPIO controller
Driver improvements:
- use modernized variants of power management macros across a wide
array of drivers in order to avoid having to use the __maybe_unused
attribute
- convert gpio-elkhartlake and reset-gpio to using the auxiliary bus
instead of the platform bus as they are not really described in
firmware
- use lock guards and update symbol prefixes in gpio-mmio
- support the bryx radio interface kit in gpio-mpsse + refactor the
driver
- use software nodes for configuring the reset-gpio driver, including
setting up the reference to the shared "reset" pin
- check and propagate the return value of gpiod_set_value() to
user-space in gpio-virtuser (this was previously not possible as
this function returned void)
- extend the gpio-regmap helper with more features (bypass cache for
aliased inputs, force writes for aliased data registers, add a new
configuration parameter)
- remove unneeded includes from gpio-aspeed and gpio-latch
- add support for Tegra410 to gpio-tegra186
- replace PCI-specific PM with generic device-level PM in gpio-bt8xx
- use dynamic GPIO range allocation in gpio-loongson-64bit
- improve handling of level-triggered interrupts in gpio-pca953x
- add suspend/resume support to gpio-fxl6408
- add support for more models to gpio-menz127
- optimize gpio-mvebu interrupt handling by avoiding unnecessary
calls to mvebu_gpio_irq_handler()
- make locking more consistent in gpio-grgpio
Device-tree bindings:
- document new NXP and Microchip models
Documentation:
- add a comprehensive compatibility and feature list for
gpio-pca953x, which is a great addition as it's probably the most
commonly used GPIO expander driver
- kernel-doc tweaks
Late fixes:
- use BYTE_CTRL_MODE for 2K2000/3000 models in gpio-loongson"
* tag 'gpio-updates-for-v6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (80 commits)
gpio: loongson: Switch 2K2000/3000 GPIO to BYTE_CTRL_MODE
gpio: regmap: fix kernel-doc notation
gpio: shared: fix a deadlock
gpio: shared-proxy: set suppress_bind_attrs
gpio: shared: ignore GPIO hogs when traversing the device tree
gpio: shared: ignore special __symbols__ node when traversing device tree
gpio: shared: handle the reset-gpios corner case
gpio: zynq: Use modern PM macros
gpio: xilinx: Use modern PM macros
gpio: xgene: Use modern PM macros
gpio: uniphier: Use modern PM macros
gpio: tqmx86: Use modern PM macros
gpio: pch: Use modern PM macros
gpio: omap: Use modern PM macros
gpio: msc313: Use modern PM macros
gpio: mlxbf2: Use modern PM macros
gpio: ml-ioh: Use modern PM macros
gpio: pl061: Use modern PM macros
gpio: htc-egpio: Use modern PM macros
gpio: brcmstb: Use modern PM macros
...
Diffstat (limited to 'drivers/reset')
| -rw-r--r-- | drivers/reset/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/reset/core.c | 138 | ||||
| -rw-r--r-- | drivers/reset/reset-gpio.c | 19 |
3 files changed, 91 insertions, 67 deletions
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 78b7078478d4..30659115de55 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -89,6 +89,7 @@ config RESET_EYEQ config RESET_GPIO tristate "GPIO reset controller" depends on GPIOLIB + select AUXILIARY_BUS help This enables a generic reset controller for resets attached via GPIOs. Typically for OF platforms this driver expects "reset-gpios" diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 22f67fc77ae5..843cffc93909 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -4,20 +4,22 @@ * * Copyright 2013 Philipp Zabel, Pengutronix */ + +#include <linux/acpi.h> #include <linux/atomic.h> +#include <linux/auxiliary_bus.h> #include <linux/cleanup.h> #include <linux/device.h> #include <linux/err.h> #include <linux/export.h> -#include <linux/kernel.h> -#include <linux/kref.h> #include <linux/gpio/driver.h> #include <linux/gpio/machine.h> +#include <linux/gpio/property.h> #include <linux/idr.h> +#include <linux/kernel.h> +#include <linux/kref.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/acpi.h> -#include <linux/platform_device.h> #include <linux/reset.h> #include <linux/reset-controller.h> #include <linux/slab.h> @@ -76,10 +78,12 @@ struct reset_control_array { /** * struct reset_gpio_lookup - lookup key for ad-hoc created reset-gpio devices * @of_args: phandle to the reset controller with all the args like GPIO number + * @swnode: Software node containing the reference to the GPIO provider * @list: list entry for the reset_gpio_lookup_list */ struct reset_gpio_lookup { struct of_phandle_args of_args; + struct fwnode_handle *swnode; struct list_head list; }; @@ -848,56 +852,45 @@ static void __reset_control_put_internal(struct reset_control *rstc) kref_put(&rstc->refcnt, __reset_control_release); } -static int __reset_add_reset_gpio_lookup(int id, struct device_node *np, - unsigned int gpio, - unsigned int of_flags) +static void reset_gpio_aux_device_release(struct device *dev) { - const struct fwnode_handle *fwnode = of_fwnode_handle(np); - unsigned int lookup_flags; - const char *label_tmp; + struct auxiliary_device *adev = to_auxiliary_dev(dev); - /* - * Later we map GPIO flags between OF and Linux, however not all - * constants from include/dt-bindings/gpio/gpio.h and - * include/linux/gpio/machine.h match each other. - */ - if (of_flags > GPIO_ACTIVE_LOW) { - pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n", - of_flags, gpio); - return -EINVAL; - } - - struct gpio_device *gdev __free(gpio_device_put) = gpio_device_find_by_fwnode(fwnode); - if (!gdev) - return -EPROBE_DEFER; - - label_tmp = gpio_device_get_label(gdev); - if (!label_tmp) - return -EINVAL; + kfree(adev); +} - char *label __free(kfree) = kstrdup(label_tmp, GFP_KERNEL); - if (!label) - return -ENOMEM; +static int reset_add_gpio_aux_device(struct device *parent, + struct fwnode_handle *swnode, + int id, void *pdata) +{ + struct auxiliary_device *adev; + int ret; - /* Size: one lookup entry plus sentinel */ - struct gpiod_lookup_table *lookup __free(kfree) = kzalloc(struct_size(lookup, table, 2), - GFP_KERNEL); - if (!lookup) + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) return -ENOMEM; - lookup->dev_id = kasprintf(GFP_KERNEL, "reset-gpio.%d", id); - if (!lookup->dev_id) - return -ENOMEM; + adev->id = id; + adev->name = "gpio"; + adev->dev.parent = parent; + adev->dev.platform_data = pdata; + adev->dev.release = reset_gpio_aux_device_release; + device_set_node(&adev->dev, swnode); - lookup_flags = GPIO_PERSISTENT; - lookup_flags |= of_flags & GPIO_ACTIVE_LOW; - lookup->table[0] = GPIO_LOOKUP(no_free_ptr(label), gpio, "reset", - lookup_flags); + ret = auxiliary_device_init(adev); + if (ret) { + kfree(adev); + return ret; + } - /* Not freed on success, because it is persisent subsystem data. */ - gpiod_add_lookup_table(no_free_ptr(lookup)); + ret = __auxiliary_device_add(adev, "reset"); + if (ret) { + auxiliary_device_uninit(adev); + kfree(adev); + return ret; + } - return 0; + return ret; } /* @@ -905,8 +898,10 @@ static int __reset_add_reset_gpio_lookup(int id, struct device_node *np, */ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) { + struct property_entry properties[2] = { }; + unsigned int offset, of_flags, lflags; struct reset_gpio_lookup *rgpio_dev; - struct platform_device *pdev; + struct device *parent; int id, ret; /* @@ -925,6 +920,28 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) */ lockdep_assert_not_held(&reset_list_mutex); + offset = args->args[0]; + of_flags = args->args[1]; + + /* + * Later we map GPIO flags between OF and Linux, however not all + * constants from include/dt-bindings/gpio/gpio.h and + * include/linux/gpio/machine.h match each other. + * + * FIXME: Find a better way of translating OF flags to GPIO lookup + * flags. + */ + if (of_flags > GPIO_ACTIVE_LOW) { + pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n", + of_flags, offset); + return -EINVAL; + } + + struct gpio_device *gdev __free(gpio_device_put) = + gpio_device_find_by_fwnode(of_fwnode_handle(args->np)); + if (!gdev) + return -EPROBE_DEFER; + guard(mutex)(&reset_gpio_lookup_mutex); list_for_each_entry(rgpio_dev, &reset_gpio_lookup_list, list) { @@ -934,6 +951,10 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) } } + lflags = GPIO_PERSISTENT | (of_flags & GPIO_ACTIVE_LOW); + parent = gpio_device_to_device(gdev); + properties[0] = PROPERTY_ENTRY_GPIO("reset-gpios", parent->fwnode, offset, lflags); + id = ida_alloc(&reset_gpio_ida, GFP_KERNEL); if (id < 0) return id; @@ -945,11 +966,6 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) goto err_ida_free; } - ret = __reset_add_reset_gpio_lookup(id, args->np, args->args[0], - args->args[1]); - if (ret < 0) - goto err_kfree; - rgpio_dev->of_args = *args; /* * We keep the device_node reference, but of_args.np is put at the end @@ -957,20 +973,26 @@ static int __reset_add_reset_gpio_device(const struct of_phandle_args *args) * Hold reference as long as rgpio_dev memory is valid. */ of_node_get(rgpio_dev->of_args.np); - pdev = platform_device_register_data(NULL, "reset-gpio", id, - &rgpio_dev->of_args, - sizeof(rgpio_dev->of_args)); - ret = PTR_ERR_OR_ZERO(pdev); + + rgpio_dev->swnode = fwnode_create_software_node(properties, NULL); + if (IS_ERR(rgpio_dev->swnode)) { + ret = PTR_ERR(rgpio_dev->swnode); + goto err_put_of_node; + } + + ret = reset_add_gpio_aux_device(parent, rgpio_dev->swnode, id, + &rgpio_dev->of_args); if (ret) - goto err_put; + goto err_del_swnode; list_add(&rgpio_dev->list, &reset_gpio_lookup_list); return 0; -err_put: +err_del_swnode: + fwnode_remove_software_node(rgpio_dev->swnode); +err_put_of_node: of_node_put(rgpio_dev->of_args.np); -err_kfree: kfree(rgpio_dev); err_ida_free: ida_free(&reset_gpio_ida, id); diff --git a/drivers/reset/reset-gpio.c b/drivers/reset/reset-gpio.c index 2290b25b6703..e5512b3b596b 100644 --- a/drivers/reset/reset-gpio.c +++ b/drivers/reset/reset-gpio.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 +#include <linux/auxiliary_bus.h> #include <linux/gpio/consumer.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/platform_device.h> #include <linux/reset-controller.h> struct reset_gpio_priv { @@ -61,9 +61,10 @@ static void reset_gpio_of_node_put(void *data) of_node_put(data); } -static int reset_gpio_probe(struct platform_device *pdev) +static int reset_gpio_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) { - struct device *dev = &pdev->dev; + struct device *dev = &adev->dev; struct of_phandle_args *platdata = dev_get_platdata(dev); struct reset_gpio_priv *priv; int ret; @@ -75,7 +76,7 @@ static int reset_gpio_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - platform_set_drvdata(pdev, &priv->rc); + auxiliary_set_drvdata(adev, &priv->rc); priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(priv->reset)) @@ -99,20 +100,20 @@ static int reset_gpio_probe(struct platform_device *pdev) return devm_reset_controller_register(dev, &priv->rc); } -static const struct platform_device_id reset_gpio_ids[] = { - { .name = "reset-gpio", }, +static const struct auxiliary_device_id reset_gpio_ids[] = { + { .name = "reset.gpio" }, {} }; -MODULE_DEVICE_TABLE(platform, reset_gpio_ids); +MODULE_DEVICE_TABLE(auxiliary, reset_gpio_ids); -static struct platform_driver reset_gpio_driver = { +static struct auxiliary_driver reset_gpio_driver = { .probe = reset_gpio_probe, .id_table = reset_gpio_ids, .driver = { .name = "reset-gpio", }, }; -module_platform_driver(reset_gpio_driver); +module_auxiliary_driver(reset_gpio_driver); MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>"); MODULE_DESCRIPTION("Generic GPIO reset driver"); |
