gpio fixes for v5.12-rc3
- fix two regressions in core GPIO subsystem code: one NULL-pointer dereference and one list corruption - read GPIO line names from fwnode instead of using the generic device properties to fix a regression on stm32mp151 - fixes to ACPI GPIO and gpio-pca953x to handle a regression in IRQ handling on Intel Galileo - update .gitignore in GPIO selftests -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmBHk9AACgkQEacuoBRx 13Kd8RAAzU2lPguxO0DjbLfOfYObqV6fODcPiMSk58LCsojz2AVrS/Kba6oSIsur OGdUQf4wNNMZsr81+DmBbk/4efd8lF1zqkIa6+serBjK+QONGd7Am0Oc3QiXgk6l ZnD51FUAHHdsiHVHmlnCYRg2w93kpu1PHDQCOl4/96xSr1BrRAhC8uV2ImVm+0XS z5ddHEe9qITsVhlD2MEpKm3wZEhhJHGtzxD7mjO3iAXzSQcCwpjD37Y5DDkzrgal gkLEYCXWeaexOHsLxPmfyDO0GMNTWL8ai8GpRMJCJwGTRataf0hVZZ7TVSGhE8+e Ms3hOxKj6AJKbfQVsSy+mJyHTF+ef4UqUp4+CqGdLoz6S5+JkQ9TxPdYNzaNCPeD Vk4htVUEYx0M8xHJhMA5siXLWTfDGRGU5ILNcwCKHA3iAMtQw/H2+SKzNgQARGgo D1LdFVXzfW278zWv1OGybLh2al8CW/Mi2ybg/kmLsXLJFCpj5kzy2/H2BznBJmPT HjU61iiaVlnt7kH3aFd92D+Sr33f7r1kxjonq8aNK3mhMoqOQUxQRtduZp9goJZN Kt0uHBMfz/YiyoGlM/Y3SA9C3b7O0ClYA/0DyJ6Qt/6NTDRMMfwAXEjd1n7dYLH1 ZSOKe1S82GbsVdDQP0qSzzLoziX4U/ttbHxN+RCv4hs67+U5Uw4= =nVo+ -----END PGP SIGNATURE----- Merge tag 'gpio-fixes-for-v5.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux Pull gpio fixes from Bartosz Golaszewski: "A bunch of fixes for the GPIO subsystem. We have two regressions in the core code spotted right after the merge window, a series of fixes for ACPI GPIO and a subsequent fix for a related regression in gpio-pca953x + a minor tweak in .gitignore and a rework of handling of the gpio-line-names to remedy a regression in stm32mp151. Summary: - fix two regressions in core GPIO subsystem code: one NULL-pointer dereference and one list corruption - read GPIO line names from fwnode instead of using the generic device properties to fix a regression on stm32mp151 - fixes to ACPI GPIO and gpio-pca953x to handle a regression in IRQ handling on Intel Galileo - update .gitignore in GPIO selftests" * tag 'gpio-fixes-for-v5.12-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: gpiolib: Read "gpio-line-names" from a firmware node gpio: pca953x: Set IRQ type when handle Intel Galileo Gen 2 gpiolib: acpi: Allow to find GpioInt() resource by name and index gpiolib: acpi: Add ACPI_GPIO_QUIRK_ABSOLUTE_NUMBER quirk gpiolib: acpi: Add missing IRQF_ONESHOT gpio: fix gpio-device list corruption gpio: fix NULL-deref-on-deregistration regression selftests: gpio: update .gitignoremaster
commit
4b3d9f9cf1
|
@ -113,8 +113,29 @@ MODULE_DEVICE_TABLE(i2c, pca953x_id);
|
||||||
#ifdef CONFIG_GPIO_PCA953X_IRQ
|
#ifdef CONFIG_GPIO_PCA953X_IRQ
|
||||||
|
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/list.h>
|
static const struct acpi_gpio_params pca953x_irq_gpios = { 0, 0, true };
|
||||||
|
|
||||||
|
static const struct acpi_gpio_mapping pca953x_acpi_irq_gpios[] = {
|
||||||
|
{ "irq-gpios", &pca953x_irq_gpios, 1, ACPI_GPIO_QUIRK_ABSOLUTE_NUMBER },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pca953x_acpi_get_irq(struct device *dev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = devm_acpi_dev_add_driver_gpios(dev, pca953x_acpi_irq_gpios);
|
||||||
|
if (ret)
|
||||||
|
dev_warn(dev, "can't add GPIO ACPI mapping\n");
|
||||||
|
|
||||||
|
ret = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(dev), "irq-gpios", 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
dev_info(dev, "ACPI interrupt quirk (IRQ %d)\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct dmi_system_id pca953x_dmi_acpi_irq_info[] = {
|
static const struct dmi_system_id pca953x_dmi_acpi_irq_info[] = {
|
||||||
{
|
{
|
||||||
|
@ -133,59 +154,6 @@ static const struct dmi_system_id pca953x_dmi_acpi_irq_info[] = {
|
||||||
},
|
},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
|
||||||
static int pca953x_acpi_get_pin(struct acpi_resource *ares, void *data)
|
|
||||||
{
|
|
||||||
struct acpi_resource_gpio *agpio;
|
|
||||||
int *pin = data;
|
|
||||||
|
|
||||||
if (acpi_gpio_get_irq_resource(ares, &agpio))
|
|
||||||
*pin = agpio->pin_table[0];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pca953x_acpi_find_pin(struct device *dev)
|
|
||||||
{
|
|
||||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
|
||||||
int pin = -ENOENT, ret;
|
|
||||||
LIST_HEAD(r);
|
|
||||||
|
|
||||||
ret = acpi_dev_get_resources(adev, &r, pca953x_acpi_get_pin, &pin);
|
|
||||||
acpi_dev_free_resource_list(&r);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return pin;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static inline int pca953x_acpi_find_pin(struct device *dev) { return -ENXIO; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int pca953x_acpi_get_irq(struct device *dev)
|
|
||||||
{
|
|
||||||
int pin, ret;
|
|
||||||
|
|
||||||
pin = pca953x_acpi_find_pin(dev);
|
|
||||||
if (pin < 0)
|
|
||||||
return pin;
|
|
||||||
|
|
||||||
dev_info(dev, "Applying ACPI interrupt quirk (GPIO %d)\n", pin);
|
|
||||||
|
|
||||||
if (!gpio_is_valid(pin))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
ret = gpio_request(pin, "pca953x interrupt");
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = gpio_to_irq(pin);
|
|
||||||
|
|
||||||
/* When pin is used as an IRQ, no need to keep it requested */
|
|
||||||
gpio_free(pin);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const struct acpi_device_id pca953x_acpi_ids[] = {
|
static const struct acpi_device_id pca953x_acpi_ids[] = {
|
||||||
|
|
|
@ -174,7 +174,7 @@ static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
|
||||||
int ret, value;
|
int ret, value;
|
||||||
|
|
||||||
ret = request_threaded_irq(event->irq, NULL, event->handler,
|
ret = request_threaded_irq(event->irq, NULL, event->handler,
|
||||||
event->irqflags, "ACPI:Event", event);
|
event->irqflags | IRQF_ONESHOT, "ACPI:Event", event);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(acpi_gpio->chip->parent,
|
dev_err(acpi_gpio->chip->parent,
|
||||||
"Failed to setup interrupt handler for %d\n",
|
"Failed to setup interrupt handler for %d\n",
|
||||||
|
@ -677,6 +677,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
|
||||||
if (!lookup->desc) {
|
if (!lookup->desc) {
|
||||||
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
|
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
|
||||||
bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
|
bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
|
||||||
|
struct gpio_desc *desc;
|
||||||
u16 pin_index;
|
u16 pin_index;
|
||||||
|
|
||||||
if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint)
|
if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint)
|
||||||
|
@ -689,8 +690,12 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
|
||||||
if (pin_index >= agpio->pin_table_length)
|
if (pin_index >= agpio->pin_table_length)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
|
if (lookup->info.quirks & ACPI_GPIO_QUIRK_ABSOLUTE_NUMBER)
|
||||||
|
desc = gpio_to_desc(agpio->pin_table[pin_index]);
|
||||||
|
else
|
||||||
|
desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
|
||||||
agpio->pin_table[pin_index]);
|
agpio->pin_table[pin_index]);
|
||||||
|
lookup->desc = desc;
|
||||||
lookup->info.pin_config = agpio->pin_config;
|
lookup->info.pin_config = agpio->pin_config;
|
||||||
lookup->info.debounce = agpio->debounce_timeout;
|
lookup->info.debounce = agpio->debounce_timeout;
|
||||||
lookup->info.gpioint = gpioint;
|
lookup->info.gpioint = gpioint;
|
||||||
|
@ -940,8 +945,9 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpi_dev_gpio_irq_get() - Find GpioInt and translate it to Linux IRQ number
|
* acpi_dev_gpio_irq_get_by() - Find GpioInt and translate it to Linux IRQ number
|
||||||
* @adev: pointer to a ACPI device to get IRQ from
|
* @adev: pointer to a ACPI device to get IRQ from
|
||||||
|
* @name: optional name of GpioInt resource
|
||||||
* @index: index of GpioInt resource (starting from %0)
|
* @index: index of GpioInt resource (starting from %0)
|
||||||
*
|
*
|
||||||
* If the device has one or more GpioInt resources, this function can be
|
* If the device has one or more GpioInt resources, this function can be
|
||||||
|
@ -951,9 +957,12 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
|
||||||
* The function is idempotent, though each time it runs it will configure GPIO
|
* The function is idempotent, though each time it runs it will configure GPIO
|
||||||
* pin direction according to the flags in GpioInt resource.
|
* pin direction according to the flags in GpioInt resource.
|
||||||
*
|
*
|
||||||
|
* The function takes optional @name parameter. If the resource has a property
|
||||||
|
* name, then only those will be taken into account.
|
||||||
|
*
|
||||||
* Return: Linux IRQ number (> %0) on success, negative errno on failure.
|
* Return: Linux IRQ number (> %0) on success, negative errno on failure.
|
||||||
*/
|
*/
|
||||||
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name, int index)
|
||||||
{
|
{
|
||||||
int idx, i;
|
int idx, i;
|
||||||
unsigned int irq_flags;
|
unsigned int irq_flags;
|
||||||
|
@ -963,7 +972,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
||||||
struct acpi_gpio_info info;
|
struct acpi_gpio_info info;
|
||||||
struct gpio_desc *desc;
|
struct gpio_desc *desc;
|
||||||
|
|
||||||
desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
|
desc = acpi_get_gpiod_by_index(adev, name, i, &info);
|
||||||
|
|
||||||
/* Ignore -EPROBE_DEFER, it only matters if idx matches */
|
/* Ignore -EPROBE_DEFER, it only matters if idx matches */
|
||||||
if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
|
if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
|
||||||
|
@ -1008,7 +1017,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
||||||
}
|
}
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get);
|
EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get_by);
|
||||||
|
|
||||||
static acpi_status
|
static acpi_status
|
||||||
acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
||||||
|
|
|
@ -367,22 +367,18 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
|
||||||
*
|
*
|
||||||
* Looks for device property "gpio-line-names" and if it exists assigns
|
* Looks for device property "gpio-line-names" and if it exists assigns
|
||||||
* GPIO line names for the chip. The memory allocated for the assigned
|
* GPIO line names for the chip. The memory allocated for the assigned
|
||||||
* names belong to the underlying software node and should not be released
|
* names belong to the underlying firmware node and should not be released
|
||||||
* by the caller.
|
* by the caller.
|
||||||
*/
|
*/
|
||||||
static int devprop_gpiochip_set_names(struct gpio_chip *chip)
|
static int devprop_gpiochip_set_names(struct gpio_chip *chip)
|
||||||
{
|
{
|
||||||
struct gpio_device *gdev = chip->gpiodev;
|
struct gpio_device *gdev = chip->gpiodev;
|
||||||
struct device *dev = chip->parent;
|
struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
|
||||||
const char **names;
|
const char **names;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
/* GPIO chip may not have a parent device whose properties we inspect. */
|
count = fwnode_property_string_array_count(fwnode, "gpio-line-names");
|
||||||
if (!dev)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
count = device_property_string_array_count(dev, "gpio-line-names");
|
|
||||||
if (count < 0)
|
if (count < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -396,7 +392,7 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)
|
||||||
if (!names)
|
if (!names)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = device_property_read_string_array(dev, "gpio-line-names",
|
ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
|
||||||
names, count);
|
names, count);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_warn(&gdev->dev, "failed to read GPIO line names\n");
|
dev_warn(&gdev->dev, "failed to read GPIO line names\n");
|
||||||
|
@ -474,9 +470,13 @@ EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
|
||||||
|
|
||||||
static void gpiodevice_release(struct device *dev)
|
static void gpiodevice_release(struct device *dev)
|
||||||
{
|
{
|
||||||
struct gpio_device *gdev = dev_get_drvdata(dev);
|
struct gpio_device *gdev = container_of(dev, struct gpio_device, dev);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&gpio_lock, flags);
|
||||||
list_del(&gdev->list);
|
list_del(&gdev->list);
|
||||||
|
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||||
|
|
||||||
ida_free(&gpio_ida, gdev->id);
|
ida_free(&gpio_ida, gdev->id);
|
||||||
kfree_const(gdev->label);
|
kfree_const(gdev->label);
|
||||||
kfree(gdev->descs);
|
kfree(gdev->descs);
|
||||||
|
@ -605,7 +605,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||||
goto err_free_ida;
|
goto err_free_ida;
|
||||||
|
|
||||||
device_initialize(&gdev->dev);
|
device_initialize(&gdev->dev);
|
||||||
dev_set_drvdata(&gdev->dev, gdev);
|
|
||||||
if (gc->parent && gc->parent->driver)
|
if (gc->parent && gc->parent->driver)
|
||||||
gdev->owner = gc->parent->driver->owner;
|
gdev->owner = gc->parent->driver->owner;
|
||||||
else if (gc->owner)
|
else if (gc->owner)
|
||||||
|
|
|
@ -1079,19 +1079,25 @@ void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const c
|
||||||
#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
|
#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
|
||||||
bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
|
bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
|
||||||
struct acpi_resource_gpio **agpio);
|
struct acpi_resource_gpio **agpio);
|
||||||
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
|
int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name, int index);
|
||||||
#else
|
#else
|
||||||
static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
|
static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
|
||||||
struct acpi_resource_gpio **agpio)
|
struct acpi_resource_gpio **agpio)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
static inline int acpi_dev_gpio_irq_get_by(struct acpi_device *adev,
|
||||||
|
const char *name, int index)
|
||||||
{
|
{
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
||||||
|
{
|
||||||
|
return acpi_dev_gpio_irq_get_by(adev, NULL, index);
|
||||||
|
}
|
||||||
|
|
||||||
/* Device properties */
|
/* Device properties */
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
|
|
|
@ -674,6 +674,8 @@ struct acpi_gpio_mapping {
|
||||||
* get GpioIo type explicitly, this quirk may be used.
|
* get GpioIo type explicitly, this quirk may be used.
|
||||||
*/
|
*/
|
||||||
#define ACPI_GPIO_QUIRK_ONLY_GPIOIO BIT(1)
|
#define ACPI_GPIO_QUIRK_ONLY_GPIOIO BIT(1)
|
||||||
|
/* Use given pin as an absolute GPIO number in the system */
|
||||||
|
#define ACPI_GPIO_QUIRK_ABSOLUTE_NUMBER BIT(2)
|
||||||
|
|
||||||
unsigned int quirks;
|
unsigned int quirks;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
gpio-mockup-chardev
|
gpio-mockup-cdev
|
||||||
|
|
Loading…
Reference in New Issue