mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00

GPIO core: - use more lock guards where applicable - refactor GPIO ACPI code and shrink it in the process by 8% - move GPIO ACPI quirks into a separate file - remove unneeded #ifdef - convert GPIO devres helpers to using devm_add_action() where applicable which shrinks and simplifies the code - refactor GPIO descriptor validation in GPIO consumer interfaces - don't allow setting values on input lines in the GPIO core which will take off the burden from GPIO drivers of checking this down the line - provide gpiod_is_equal() as a way of safely comparing two GPIO descriptors (the only current user is in regulator core) New drivers: - add the GPIO module for the max77759 multifunction device - add the GPIO driver for the VeriSilicon BLZP1600 GPIO controller - add the GPIO driver for the Spacemit K1 SoC Driver improvements: - convert more drivers to using the new GPIO line value setter callbacks - convert more drivers to making the irq_chip immutable as is recommended by the interrupt subsystem - extend build testing coverage by enabling more modules to be built with COMPILE_TEST=y - extend the gpio-aggregator module with a configfs interface that makes the setup easier for user-space than the existing driver-level sysfs attributes and also adds more advanced configuration features (such as referring to aggregated lines by their original names or modifying their names as exposed by the aggregated chip) - add a missing mutex_destroy() in gpio-imx-scu - add an OF polarity quirk for s5m8767 - allow building gpio-vf610 as a loadable module - make gpio-mxc not hardcode its GPIO base number with GPIO SYSFS interface disabled (another small step towards getting rid of the global GPIO numberspace) - add support for level-triggered interrupts to gpio-pca953x - don't double-check the ngpios property in gpio-ds4520 as GPIO core already does it - don't double-check the number of GPIOs in gpio-imx-scu as GPIO core already does it - remove unused callbacks from gpio-max3191x DT bindings: - add device-tree bindings for max77759, spacemit,k1 and blzp1600 (new drivers added this cycle) - document more properties for gpio-vf610 and gpio-tegra186 - document a new pca95xx variant - fix style of examples in several GPIO DT-binding documents Misc: - TODO list updates -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmg0NtQACgkQEacuoBRx 13Iolg/+P8fe1hTek+UgdKm/EAQ1Mn3oijNE1Ix15VD8Iqacu+URyB2SJMFcg27n S/tsuwogQeQmdgXPfYDJkQmiZEyln/ytWf5W2lNwYhGfGujVa8h1FueB7Wb8Zs7G PNMnobyAIGivodJfvikDEyczMuxhkOH04ZOT7UpTSPI47BSGsujX/1vgmRQLid1Z 3wFDJ0yDhVcuxit/VC+LzFpHIV0MiRzGpvHzYid5jjEaGSiRMpHixf27VJGc0gG1 IJLkhNkwZ3InisWVGvqdRg/FUNErRYKYQSARb4AjCU+/y1H0SWdB0R6sZDTZpP+e YqAc8FW31Lw1L7PWBLRTaVS3KT868tdXDCsArNzfBbb3u/WikO2GY/AXuzveZatp pHwyPA0JS9QvxaTXU9yjCpGqdNfjbrmU5OkZxTTe+Nyz84fUfiURiE8g4Rl6riy4 fNzaywRBmVZlEECWSWGzyNw9ZEYDRPZ1ZHmOA+8FWE+/XKJIsVf8w3x2QIC5b/HO hYKH4mar8oiEYJFZqoko3iQURJq+AD9wILCNpws5bSsi//VyyNT0mZV/q5hj7+Xx pqeEGDInvycN5fDWWJlkN1lj5dDyHZi4uus05mYI9Ec+eX3XNWRUHXUskbpzdgCs XepjP9kFQmMSL7y4z2d7tLd7gFup/uGny7o/KyMsIPDw7qVL5rY= =PQqp -----END PGP SIGNATURE----- Merge tag 'gpio-updates-for-v6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux Pull gpio updates from Bartosz Golaszewski: "We have three new drivers, some refactoring in the GPIO core, lots of various changes across many drivers, new configfs interface for the virtual gpio-aggregator module and DT-bindings updates. The treewide conversion of GPIO drivers to using the new value setter callbacks is ongoing with another round of GPIO drivers updated. You will also see these commits coming in from other subsystems as with the relevant changes merged into mainline last cycle, I've started converting GPIO providers located elsewhere than drivers/gpio/. GPIO core: - use more lock guards where applicable - refactor GPIO ACPI code and shrink it in the process by 8% - move GPIO ACPI quirks into a separate file - remove unneeded #ifdef - convert GPIO devres helpers to using devm_add_action() where applicable which shrinks and simplifies the code - refactor GPIO descriptor validation in GPIO consumer interfaces - don't allow setting values on input lines in the GPIO core which will take off the burden from GPIO drivers of checking this down the line - provide gpiod_is_equal() as a way of safely comparing two GPIO descriptors (the only current user is in regulator core) New drivers: - add the GPIO module for the max77759 multifunction device - add the GPIO driver for the VeriSilicon BLZP1600 GPIO controller - add the GPIO driver for the Spacemit K1 SoC Driver improvements: - convert more drivers to using the new GPIO line value setter callbacks - convert more drivers to making the irq_chip immutable as is recommended by the interrupt subsystem - extend build testing coverage by enabling more modules to be built with COMPILE_TEST=y - extend the gpio-aggregator module with a configfs interface that makes the setup easier for user-space than the existing driver-level sysfs attributes and also adds more advanced configuration features (such as referring to aggregated lines by their original names or modifying their names as exposed by the aggregated chip) - add a missing mutex_destroy() in gpio-imx-scu - add an OF polarity quirk for s5m8767 - allow building gpio-vf610 as a loadable module - make gpio-mxc not hardcode its GPIO base number with GPIO SYSFS interface disabled (another small step towards getting rid of the global GPIO numberspace) - add support for level-triggered interrupts to gpio-pca953x - don't double-check the ngpios property in gpio-ds4520 as GPIO core already does it - don't double-check the number of GPIOs in gpio-imx-scu as GPIO core already does it - remove unused callbacks from gpio-max3191x DT bindings: - add device-tree bindings for max77759, spacemit,k1 and blzp1600 (new drivers added this cycle) - document more properties for gpio-vf610 and gpio-tegra186 - document a new pca95xx variant - fix style of examples in several GPIO DT-binding documents Misc: - TODO list updates" * tag 'gpio-updates-for-v6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (123 commits) gpio: timberdale: select GPIOLIB_IRQCHIP gpio: lpc18xx: select GPIOLIB_IRQCHIP gpio: grgpio: select GPIOLIB_IRQCHIP gpio: bcm-kona: select GPIOLIB_IRQCHIP dt-bindings: gpio: vf610: add ngpios and gpio-reserved-ranges gpio: davinci: select GPIOLIB_IRQCHIP gpiolib-acpi: Update file references in the Documentation and MAINTAINERS gpiolib: acpi: Move quirks to a separate file gpiolib: acpi: Add acpi_gpio_need_run_edge_events_on_boot() getter gpiolib: acpi: Handle deferred list via new API gpiolib: acpi: Make sure we fill struct acpi_gpio_info gpiolib: acpi: Switch to use enum in acpi_gpio_in_ignore_list() gpiolib: acpi: Use temporary variable for struct acpi_gpio_info gpiolib: remove unneeded #ifdef gpio: mpc8xxx: select GPIOLIB_IRQCHIP gpio: pxa: select GPIOLIB_IRQCHIP gpio: pxa: Make irq_chip immutable gpio: timberdale: Make irq_chip immutable gpio: xgene-sb: Make irq_chip immutable gpio: davinci: Make irq_chip immutable ...
363 lines
11 KiB
C
363 lines
11 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* devres.c - managed gpio resources
|
|
* This file is based on kernel/irq/devres.c
|
|
*
|
|
* Copyright (c) 2011 John Crispin <john@phrozen.org>
|
|
*/
|
|
|
|
#include <linux/device/devres.h>
|
|
#include <linux/err.h>
|
|
#include <linux/export.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/gpio/consumer.h>
|
|
|
|
#include "gpiolib.h"
|
|
|
|
struct fwnode_handle;
|
|
struct lock_class_key;
|
|
|
|
static void devm_gpiod_release(void *desc)
|
|
{
|
|
gpiod_put(desc);
|
|
}
|
|
|
|
static void devm_gpiod_release_array(void *descs)
|
|
{
|
|
gpiod_put_array(descs);
|
|
}
|
|
|
|
/**
|
|
* devm_gpiod_get - Resource-managed gpiod_get()
|
|
* @dev: GPIO consumer
|
|
* @con_id: function within the GPIO consumer
|
|
* @flags: optional GPIO initialization flags
|
|
*
|
|
* Managed gpiod_get(). GPIO descriptors returned from this function are
|
|
* automatically disposed on driver detach. See gpiod_get() for detailed
|
|
* information about behavior and return values.
|
|
*
|
|
* Returns:
|
|
* The GPIO descriptor corresponding to the function @con_id of device
|
|
* dev, %-ENOENT if no GPIO has been assigned to the requested function, or
|
|
* another IS_ERR() code if an error occurred while trying to acquire the GPIO.
|
|
*/
|
|
struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
|
|
const char *con_id,
|
|
enum gpiod_flags flags)
|
|
{
|
|
return devm_gpiod_get_index(dev, con_id, 0, flags);
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiod_get);
|
|
|
|
/**
|
|
* devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
|
|
* @dev: GPIO consumer
|
|
* @con_id: function within the GPIO consumer
|
|
* @flags: optional GPIO initialization flags
|
|
*
|
|
* Managed gpiod_get_optional(). GPIO descriptors returned from this function
|
|
* are automatically disposed on driver detach. See gpiod_get_optional() for
|
|
* detailed information about behavior and return values.
|
|
*
|
|
* Returns:
|
|
* The GPIO descriptor corresponding to the function @con_id of device
|
|
* dev, NULL if no GPIO has been assigned to the requested function, or
|
|
* another IS_ERR() code if an error occurred while trying to acquire the GPIO.
|
|
*/
|
|
struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
|
|
const char *con_id,
|
|
enum gpiod_flags flags)
|
|
{
|
|
return devm_gpiod_get_index_optional(dev, con_id, 0, flags);
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiod_get_optional);
|
|
|
|
/**
|
|
* devm_gpiod_get_index - Resource-managed gpiod_get_index()
|
|
* @dev: GPIO consumer
|
|
* @con_id: function within the GPIO consumer
|
|
* @idx: index of the GPIO to obtain in the consumer
|
|
* @flags: optional GPIO initialization flags
|
|
*
|
|
* Managed gpiod_get_index(). GPIO descriptors returned from this function are
|
|
* automatically disposed on driver detach. See gpiod_get_index() for detailed
|
|
* information about behavior and return values.
|
|
*
|
|
* Returns:
|
|
* The GPIO descriptor corresponding to the function @con_id of device
|
|
* dev, %-ENOENT if no GPIO has been assigned to the requested function, or
|
|
* another IS_ERR() code if an error occurred while trying to acquire the GPIO.
|
|
*/
|
|
struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
|
|
const char *con_id,
|
|
unsigned int idx,
|
|
enum gpiod_flags flags)
|
|
{
|
|
struct gpio_desc *desc;
|
|
int ret;
|
|
|
|
desc = gpiod_get_index(dev, con_id, idx, flags);
|
|
if (IS_ERR(desc))
|
|
return desc;
|
|
|
|
/*
|
|
* For non-exclusive GPIO descriptors, check if this descriptor is
|
|
* already under resource management by this device.
|
|
*/
|
|
if (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
|
|
bool dres;
|
|
|
|
dres = devm_is_action_added(dev, devm_gpiod_release, desc);
|
|
if (dres)
|
|
return desc;
|
|
}
|
|
|
|
ret = devm_add_action_or_reset(dev, devm_gpiod_release, desc);
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
return desc;
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiod_get_index);
|
|
|
|
/**
|
|
* devm_fwnode_gpiod_get_index - get a GPIO descriptor from a given node
|
|
* @dev: GPIO consumer
|
|
* @fwnode: firmware node containing GPIO reference
|
|
* @con_id: function within the GPIO consumer
|
|
* @index: index of the GPIO to obtain in the consumer
|
|
* @flags: GPIO initialization flags
|
|
* @label: label to attach to the requested GPIO
|
|
*
|
|
* GPIO descriptors returned from this function are automatically disposed on
|
|
* driver detach.
|
|
*
|
|
* Returns:
|
|
* The GPIO descriptor corresponding to the function @con_id of device
|
|
* dev, %-ENOENT if no GPIO has been assigned to the requested function, or
|
|
* another IS_ERR() code if an error occurred while trying to acquire the GPIO.
|
|
*/
|
|
struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev,
|
|
struct fwnode_handle *fwnode,
|
|
const char *con_id, int index,
|
|
enum gpiod_flags flags,
|
|
const char *label)
|
|
{
|
|
struct gpio_desc *desc;
|
|
int ret;
|
|
|
|
desc = gpiod_find_and_request(dev, fwnode, con_id, index, flags, label, false);
|
|
if (IS_ERR(desc))
|
|
return desc;
|
|
|
|
ret = devm_add_action_or_reset(dev, devm_gpiod_release, desc);
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
return desc;
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_fwnode_gpiod_get_index);
|
|
|
|
/**
|
|
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
|
|
* @dev: GPIO consumer
|
|
* @con_id: function within the GPIO consumer
|
|
* @index: index of the GPIO to obtain in the consumer
|
|
* @flags: optional GPIO initialization flags
|
|
*
|
|
* Managed gpiod_get_index_optional(). GPIO descriptors returned from this
|
|
* function are automatically disposed on driver detach. See
|
|
* gpiod_get_index_optional() for detailed information about behavior and
|
|
* return values.
|
|
*
|
|
* Returns:
|
|
* The GPIO descriptor corresponding to the function @con_id of device
|
|
* dev, %NULL if no GPIO has been assigned to the requested function, or
|
|
* another IS_ERR() code if an error occurred while trying to acquire the GPIO.
|
|
*/
|
|
struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
|
|
const char *con_id,
|
|
unsigned int index,
|
|
enum gpiod_flags flags)
|
|
{
|
|
struct gpio_desc *desc;
|
|
|
|
desc = devm_gpiod_get_index(dev, con_id, index, flags);
|
|
if (gpiod_not_found(desc))
|
|
return NULL;
|
|
|
|
return desc;
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiod_get_index_optional);
|
|
|
|
/**
|
|
* devm_gpiod_get_array - Resource-managed gpiod_get_array()
|
|
* @dev: GPIO consumer
|
|
* @con_id: function within the GPIO consumer
|
|
* @flags: optional GPIO initialization flags
|
|
*
|
|
* Managed gpiod_get_array(). GPIO descriptors returned from this function are
|
|
* automatically disposed on driver detach. See gpiod_get_array() for detailed
|
|
* information about behavior and return values.
|
|
*
|
|
* Returns:
|
|
* The GPIO descriptors corresponding to the function @con_id of device
|
|
* dev, %-ENOENT if no GPIO has been assigned to the requested function,
|
|
* or another IS_ERR() code if an error occurred while trying to acquire
|
|
* the GPIOs.
|
|
*/
|
|
struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
|
|
const char *con_id,
|
|
enum gpiod_flags flags)
|
|
{
|
|
struct gpio_descs *descs;
|
|
int ret;
|
|
|
|
descs = gpiod_get_array(dev, con_id, flags);
|
|
if (IS_ERR(descs))
|
|
return descs;
|
|
|
|
ret = devm_add_action_or_reset(dev, devm_gpiod_release_array, descs);
|
|
if (ret)
|
|
return ERR_PTR(ret);
|
|
|
|
return descs;
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiod_get_array);
|
|
|
|
/**
|
|
* devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional()
|
|
* @dev: GPIO consumer
|
|
* @con_id: function within the GPIO consumer
|
|
* @flags: optional GPIO initialization flags
|
|
*
|
|
* Managed gpiod_get_array_optional(). GPIO descriptors returned from this
|
|
* function are automatically disposed on driver detach.
|
|
* See gpiod_get_array_optional() for detailed information about behavior and
|
|
* return values.
|
|
*
|
|
* Returns:
|
|
* The GPIO descriptors corresponding to the function @con_id of device
|
|
* dev, %NULL if no GPIO has been assigned to the requested function,
|
|
* or another IS_ERR() code if an error occurred while trying to acquire
|
|
* the GPIOs.
|
|
*/
|
|
struct gpio_descs *__must_check
|
|
devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
|
|
enum gpiod_flags flags)
|
|
{
|
|
struct gpio_descs *descs;
|
|
|
|
descs = devm_gpiod_get_array(dev, con_id, flags);
|
|
if (gpiod_not_found(descs))
|
|
return NULL;
|
|
|
|
return descs;
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiod_get_array_optional);
|
|
|
|
/**
|
|
* devm_gpiod_put - Resource-managed gpiod_put()
|
|
* @dev: GPIO consumer
|
|
* @desc: GPIO descriptor to dispose of
|
|
*
|
|
* Dispose of a GPIO descriptor obtained with devm_gpiod_get() or
|
|
* devm_gpiod_get_index(). Normally this function will not be called as the GPIO
|
|
* will be disposed of by the resource management code.
|
|
*/
|
|
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
|
|
{
|
|
devm_release_action(dev, devm_gpiod_release, desc);
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiod_put);
|
|
|
|
/**
|
|
* devm_gpiod_unhinge - Remove resource management from a gpio descriptor
|
|
* @dev: GPIO consumer
|
|
* @desc: GPIO descriptor to remove resource management from
|
|
*
|
|
* *DEPRECATED*
|
|
* This function should not be used. It's been provided as a workaround for
|
|
* resource ownership issues in the regulator framework and should be replaced
|
|
* with a better solution.
|
|
*
|
|
* Remove resource management from a GPIO descriptor. This is needed when
|
|
* you want to hand over lifecycle management of a descriptor to another
|
|
* mechanism.
|
|
*/
|
|
void devm_gpiod_unhinge(struct device *dev, struct gpio_desc *desc)
|
|
{
|
|
int ret;
|
|
|
|
if (IS_ERR_OR_NULL(desc))
|
|
return;
|
|
|
|
/*
|
|
* If the GPIO descriptor is requested as nonexclusive, we
|
|
* may call this function several times on the same descriptor
|
|
* so it is OK if devres_destroy() returns -ENOENT.
|
|
*/
|
|
ret = devm_remove_action_nowarn(dev, devm_gpiod_release, desc);
|
|
if (ret == -ENOENT)
|
|
return;
|
|
/* Anything else we should warn about */
|
|
WARN_ON(ret);
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiod_unhinge);
|
|
|
|
/**
|
|
* devm_gpiod_put_array - Resource-managed gpiod_put_array()
|
|
* @dev: GPIO consumer
|
|
* @descs: GPIO descriptor array to dispose of
|
|
*
|
|
* Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array().
|
|
* Normally this function will not be called as the GPIOs will be disposed of
|
|
* by the resource management code.
|
|
*/
|
|
void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
|
|
{
|
|
devm_remove_action(dev, devm_gpiod_release_array, descs);
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiod_put_array);
|
|
|
|
static void devm_gpio_chip_release(void *data)
|
|
{
|
|
struct gpio_chip *gc = data;
|
|
|
|
gpiochip_remove(gc);
|
|
}
|
|
|
|
/**
|
|
* devm_gpiochip_add_data_with_key() - Resource managed gpiochip_add_data_with_key()
|
|
* @dev: pointer to the device that gpio_chip belongs to.
|
|
* @gc: the GPIO chip to register
|
|
* @data: driver-private data associated with this chip
|
|
* @lock_key: lockdep class for IRQ lock
|
|
* @request_key: lockdep class for IRQ request
|
|
*
|
|
* Context: potentially before irqs will work
|
|
*
|
|
* The gpio chip automatically be released when the device is unbound.
|
|
*
|
|
* Returns:
|
|
* A negative errno if the chip can't be registered, such as because the
|
|
* gc->base is invalid or already associated with a different chip.
|
|
* Otherwise it returns zero as a success code.
|
|
*/
|
|
int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, void *data,
|
|
struct lock_class_key *lock_key,
|
|
struct lock_class_key *request_key)
|
|
{
|
|
int ret;
|
|
|
|
ret = gpiochip_add_data_with_key(gc, data, lock_key, request_key);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return devm_add_action_or_reset(dev, devm_gpio_chip_release, gc);
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_gpiochip_add_data_with_key);
|