diff options
Diffstat (limited to 'drivers/gpio')
| -rw-r--r-- | drivers/gpio/gpio-amd8111.c | 4 | ||||
| -rw-r--r-- | drivers/gpio/gpio-arizona.c | 5 | ||||
| -rw-r--r-- | drivers/gpio/gpio-aspeed.c | 5 | ||||
| -rw-r--r-- | drivers/gpio/gpio-da9052.c | 9 | ||||
| -rw-r--r-- | drivers/gpio/gpio-mockup.c | 1 | ||||
| -rw-r--r-- | drivers/gpio/gpio-mxc.c | 92 | ||||
| -rw-r--r-- | drivers/gpio/gpio-pca953x.c | 3 | ||||
| -rw-r--r-- | drivers/gpio/gpio-pl061.c | 15 | ||||
| -rw-r--r-- | drivers/gpio/gpio-rockchip.c | 1 | ||||
| -rw-r--r-- | drivers/gpio/gpio-tegra.c | 60 | ||||
| -rw-r--r-- | drivers/gpio/gpio-tegra186.c | 3 | ||||
| -rw-r--r-- | drivers/gpio/gpio-wm8350.c | 7 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib-acpi.h | 12 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib-cdev.c | 4 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib-of.h | 11 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib-sysfs.h | 2 | ||||
| -rw-r--r-- | drivers/gpio/gpiolib.c | 42 |
17 files changed, 218 insertions, 58 deletions
diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c index 14e6b3e64add..6f3ded619c8b 100644 --- a/drivers/gpio/gpio-amd8111.c +++ b/drivers/gpio/gpio-amd8111.c @@ -226,7 +226,10 @@ found: ioport_unmap(gp.pm); goto out; } + return 0; + out: + pci_dev_put(pdev); return err; } @@ -234,6 +237,7 @@ static void __exit amd_gpio_exit(void) { gpiochip_remove(&gp.chip); ioport_unmap(gp.pm); + pci_dev_put(gp.pdev); } module_init(amd_gpio_init); diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 02f9ae19cd44..c15fda99120a 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -7,13 +7,12 @@ * Author: Mark Brown <[email protected]> */ +#include <linux/gpio/driver.h> #include <linux/kernel.h> -#include <linux/slab.h> #include <linux/module.h> -#include <linux/gpio/driver.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/seq_file.h> +#include <linux/slab.h> #include <linux/mfd/arizona/core.h> #include <linux/mfd/arizona/pdata.h> diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index 318a7d95a1a8..a94da80d3a95 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -5,10 +5,9 @@ * Joel Stanley <[email protected]> */ -#include <asm/div64.h> #include <linux/clk.h> -#include <linux/gpio/driver.h> #include <linux/gpio/aspeed.h> +#include <linux/gpio/driver.h> #include <linux/hashtable.h> #include <linux/init.h> #include <linux/io.h> @@ -19,6 +18,8 @@ #include <linux/spinlock.h> #include <linux/string.h> +#include <asm/div64.h> + /* * These two headers aren't meant to be used by GPIO drivers. We need * them in order to access gpio_chip_hwgpio() which we need to implement diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 559188d80c2b..6f3905f1b8f5 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -6,17 +6,16 @@ * * Author: David Dajun Chen <[email protected]> */ -#include <linux/module.h> #include <linux/fs.h> -#include <linux/uaccess.h> -#include <linux/platform_device.h> #include <linux/gpio/driver.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <linux/syscalls.h> -#include <linux/seq_file.h> +#include <linux/uaccess.h> #include <linux/mfd/da9052/da9052.h> -#include <linux/mfd/da9052/reg.h> #include <linux/mfd/da9052/pdata.h> +#include <linux/mfd/da9052/reg.h> #define DA9052_INPUT 1 #define DA9052_OUTPUT_OPENDRAIN 2 diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 523dfd17dd92..e6a7049bef64 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/property.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/string_helpers.h> #include <linux/uaccess.h> diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index c871602fc5ba..d5626c572d24 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -24,6 +24,12 @@ #include <linux/of_device.h> #include <linux/bug.h> +#define IMX_SCU_WAKEUP_OFF 0 +#define IMX_SCU_WAKEUP_LOW_LVL 4 +#define IMX_SCU_WAKEUP_FALL_EDGE 5 +#define IMX_SCU_WAKEUP_RISE_EDGE 6 +#define IMX_SCU_WAKEUP_HIGH_LVL 7 + /* device type dependent stuff */ struct mxc_gpio_hwdata { unsigned dr_reg; @@ -61,6 +67,9 @@ struct mxc_gpio_port { u32 both_edges; struct mxc_gpio_reg_saved gpio_saved_reg; bool power_off; + u32 wakeup_pads; + bool is_pad_wakeup; + u32 pad_type[32]; const struct mxc_gpio_hwdata *hwdata; }; @@ -130,6 +139,9 @@ static const struct of_device_id mxc_gpio_dt_ids[] = { { .compatible = "fsl,imx31-gpio", .data = &imx31_gpio_hwdata }, { .compatible = "fsl,imx35-gpio", .data = &imx35_gpio_hwdata }, { .compatible = "fsl,imx7d-gpio", .data = &imx35_gpio_hwdata }, + { .compatible = "fsl,imx8dxl-gpio", .data = &imx35_gpio_hwdata }, + { .compatible = "fsl,imx8qm-gpio", .data = &imx35_gpio_hwdata }, + { .compatible = "fsl,imx8qxp-gpio", .data = &imx35_gpio_hwdata }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mxc_gpio_dt_ids); @@ -203,6 +215,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) } writel(1 << gpio_idx, port->base + GPIO_ISR); + port->pad_type[gpio_idx] = type; return 0; } @@ -254,6 +267,9 @@ static void mx3_gpio_irq_handler(struct irq_desc *desc) struct mxc_gpio_port *port = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); + if (port->is_pad_wakeup) + return; + chained_irq_enter(chip, desc); irq_stat = readl(port->base + GPIO_ISR) & readl(port->base + GPIO_IMR); @@ -306,11 +322,13 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable) ret = enable_irq_wake(port->irq_high); else ret = enable_irq_wake(port->irq); + port->wakeup_pads |= (1 << gpio_idx); } else { if (port->irq_high && (gpio_idx >= 16)) ret = disable_irq_wake(port->irq_high); else ret = disable_irq_wake(port->irq); + port->wakeup_pads &= ~(1 << gpio_idx); } return ret; @@ -365,7 +383,6 @@ static int mxc_gpio_probe(struct platform_device *pdev) return -ENOMEM; port->dev = &pdev->dev; - port->hwdata = device_get_match_data(&pdev->dev); port->base = devm_platform_ioremap_resource(pdev, 0); @@ -498,6 +515,78 @@ static void mxc_gpio_restore_regs(struct mxc_gpio_port *port) writel(port->gpio_saved_reg.dr, port->base + GPIO_DR); } +static bool mxc_gpio_generic_config(struct mxc_gpio_port *port, + unsigned int offset, unsigned long conf) +{ + struct device_node *np = port->dev->of_node; + + if (of_device_is_compatible(np, "fsl,imx8dxl-gpio") || + of_device_is_compatible(np, "fsl,imx8qxp-gpio") || + of_device_is_compatible(np, "fsl,imx8qm-gpio")) + return (gpiochip_generic_config(&port->gc, offset, conf) == 0); + + return false; +} + +static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable) +{ + unsigned long config; + bool ret = false; + int i, type; + + static const u32 pad_type_map[] = { + IMX_SCU_WAKEUP_OFF, /* 0 */ + IMX_SCU_WAKEUP_RISE_EDGE, /* IRQ_TYPE_EDGE_RISING */ + IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_FALLING */ + IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_BOTH */ + IMX_SCU_WAKEUP_HIGH_LVL, /* IRQ_TYPE_LEVEL_HIGH */ + IMX_SCU_WAKEUP_OFF, /* 5 */ + IMX_SCU_WAKEUP_OFF, /* 6 */ + IMX_SCU_WAKEUP_OFF, /* 7 */ + IMX_SCU_WAKEUP_LOW_LVL, /* IRQ_TYPE_LEVEL_LOW */ + }; + + for (i = 0; i < 32; i++) { + if ((port->wakeup_pads & (1 << i))) { + type = port->pad_type[i]; + if (enable) + config = pad_type_map[type]; + else + config = IMX_SCU_WAKEUP_OFF; + ret |= mxc_gpio_generic_config(port, i, config); + } + } + + return ret; +} + +static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + + if (port->wakeup_pads > 0) + port->is_pad_wakeup = mxc_gpio_set_pad_wakeup(port, true); + + return 0; +} + +static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mxc_gpio_port *port = platform_get_drvdata(pdev); + + if (port->wakeup_pads > 0) + mxc_gpio_set_pad_wakeup(port, false); + port->is_pad_wakeup = false; + + return 0; +} + +static const struct dev_pm_ops mxc_gpio_dev_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume) +}; + static int mxc_gpio_syscore_suspend(void) { struct mxc_gpio_port *port; @@ -537,6 +626,7 @@ static struct platform_driver mxc_gpio_driver = { .name = "gpio-mxc", .of_match_table = mxc_gpio_dt_ids, .suppress_bind_attrs = true, + .pm = &mxc_gpio_dev_pm_ops, }, .probe = mxc_gpio_probe, }; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index ebe1943b85dd..6e67867e1dcd 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -10,8 +10,8 @@ #include <linux/acpi.h> #include <linux/bitmap.h> -#include <linux/gpio/driver.h> #include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -20,6 +20,7 @@ #include <linux/platform_data/pca953x.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <asm/unaligned.h> diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 6464056cb6ae..9fc1f3dd4190 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -8,22 +8,23 @@ * * Data sheet: ARM DDI 0190B, September 2000 */ -#include <linux/spinlock.h> +#include <linux/amba/bus.h> +#include <linux/bitops.h> +#include <linux/device.h> #include <linux/errno.h> +#include <linux/gpio/driver.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/ioport.h> -#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqchip/chained_irq.h> #include <linux/module.h> -#include <linux/bitops.h> -#include <linux/gpio/driver.h> -#include <linux/device.h> -#include <linux/amba/bus.h> -#include <linux/slab.h> #include <linux/pinctrl/consumer.h> #include <linux/pm.h> +#include <linux/seq_file.h> +#include <linux/slab.h> +#include <linux/spinlock.h> #define GPIODIR 0x400 #define GPIOIS 0x404 diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index 870910bb9dd3..200e43a6f4b4 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -610,6 +610,7 @@ static int rockchip_gpiolib_register(struct rockchip_pin_bank *bank) return -ENODATA; pctldev = of_pinctrl_get(pctlnp); + of_node_put(pctlnp); if (!pctldev) return -ENODEV; diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index e4fb4cb38a0f..5b265a6fd3c1 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -18,6 +18,7 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/seq_file.h> #include <linux/irqdomain.h> #include <linux/irqchip/chained_irq.h> #include <linux/pinctrl/consumer.h> @@ -94,7 +95,6 @@ struct tegra_gpio_info { struct tegra_gpio_bank *bank_info; const struct tegra_gpio_soc_config *soc; struct gpio_chip gc; - struct irq_chip ic; u32 bank_count; unsigned int *irqs; }; @@ -288,6 +288,7 @@ static void tegra_gpio_irq_mask(struct irq_data *d) unsigned int gpio = d->hwirq; tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0); + gpiochip_disable_irq(chip, gpio); } static void tegra_gpio_irq_unmask(struct irq_data *d) @@ -296,6 +297,7 @@ static void tegra_gpio_irq_unmask(struct irq_data *d) struct tegra_gpio_info *tgi = gpiochip_get_data(chip); unsigned int gpio = d->hwirq; + gpiochip_enable_irq(chip, gpio); tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 1); } @@ -598,10 +600,47 @@ static void tegra_gpio_irq_release_resources(struct irq_data *d) tegra_gpio_enable(tgi, d->hwirq); } +static void tegra_gpio_irq_print_chip(struct irq_data *d, struct seq_file *s) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + seq_printf(s, dev_name(chip->parent)); +} + +static const struct irq_chip tegra_gpio_irq_chip = { + .irq_shutdown = tegra_gpio_irq_shutdown, + .irq_ack = tegra_gpio_irq_ack, + .irq_mask = tegra_gpio_irq_mask, + .irq_unmask = tegra_gpio_irq_unmask, + .irq_set_type = tegra_gpio_irq_set_type, +#ifdef CONFIG_PM_SLEEP + .irq_set_wake = tegra_gpio_irq_set_wake, +#endif + .irq_print_chip = tegra_gpio_irq_print_chip, + .irq_request_resources = tegra_gpio_irq_request_resources, + .irq_release_resources = tegra_gpio_irq_release_resources, + .flags = IRQCHIP_IMMUTABLE, +}; + +static const struct irq_chip tegra210_gpio_irq_chip = { + .irq_shutdown = tegra_gpio_irq_shutdown, + .irq_ack = tegra_gpio_irq_ack, + .irq_mask = tegra_gpio_irq_mask, + .irq_unmask = tegra_gpio_irq_unmask, + .irq_set_affinity = tegra_gpio_irq_set_affinity, + .irq_set_type = tegra_gpio_irq_set_type, +#ifdef CONFIG_PM_SLEEP + .irq_set_wake = tegra_gpio_irq_set_wake, +#endif + .irq_print_chip = tegra_gpio_irq_print_chip, + .irq_request_resources = tegra_gpio_irq_request_resources, + .irq_release_resources = tegra_gpio_irq_release_resources, + .flags = IRQCHIP_IMMUTABLE, +}; + #ifdef CONFIG_DEBUG_FS #include <linux/debugfs.h> -#include <linux/seq_file.h> static int tegra_dbg_gpio_show(struct seq_file *s, void *unused) { @@ -689,18 +728,6 @@ static int tegra_gpio_probe(struct platform_device *pdev) tgi->gc.ngpio = tgi->bank_count * 32; tgi->gc.parent = &pdev->dev; - tgi->ic.name = "GPIO"; - tgi->ic.irq_ack = tegra_gpio_irq_ack; - tgi->ic.irq_mask = tegra_gpio_irq_mask; - tgi->ic.irq_unmask = tegra_gpio_irq_unmask; - tgi->ic.irq_set_type = tegra_gpio_irq_set_type; - tgi->ic.irq_shutdown = tegra_gpio_irq_shutdown; -#ifdef CONFIG_PM_SLEEP - tgi->ic.irq_set_wake = tegra_gpio_irq_set_wake; -#endif - tgi->ic.irq_request_resources = tegra_gpio_irq_request_resources; - tgi->ic.irq_release_resources = tegra_gpio_irq_release_resources; - platform_set_drvdata(pdev, tgi); if (tgi->soc->debounce_supported) @@ -733,7 +760,6 @@ static int tegra_gpio_probe(struct platform_device *pdev) } irq = &tgi->gc.irq; - irq->chip = &tgi->ic; irq->fwnode = of_node_to_fwnode(pdev->dev.of_node); irq->child_to_parent_hwirq = tegra_gpio_child_to_parent_hwirq; irq->populate_parent_alloc_arg = tegra_gpio_populate_parent_fwspec; @@ -752,7 +778,9 @@ static int tegra_gpio_probe(struct platform_device *pdev) if (!irq->parent_domain) return -EPROBE_DEFER; - tgi->ic.irq_set_affinity = tegra_gpio_irq_set_affinity; + gpio_irq_chip_set_chip(irq, &tegra210_gpio_irq_chip); + } else { + gpio_irq_chip_set_chip(irq, &tegra_gpio_irq_chip); } tgi->regs = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 54d9fa7da9c1..fdc5bdcd5638 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -7,12 +7,13 @@ */ #include <linux/gpio/driver.h> +#include <linux/hte.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> -#include <linux/hte.h> +#include <linux/seq_file.h> #include <dt-bindings/gpio/tegra186-gpio.h> #include <dt-bindings/gpio/tegra194-gpio.h> diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index b1b131fb9804..2421cf606ed6 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -8,13 +8,12 @@ * */ -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/module.h> #include <linux/gpio/driver.h> +#include <linux/kernel.h> #include <linux/mfd/core.h> +#include <linux/module.h> #include <linux/platform_device.h> -#include <linux/seq_file.h> +#include <linux/slab.h> #include <linux/mfd/wm8350/core.h> #include <linux/mfd/wm8350/gpio.h> diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h index 1ac6816839db..01e0cb480a00 100644 --- a/drivers/gpio/gpiolib-acpi.h +++ b/drivers/gpio/gpiolib-acpi.h @@ -8,7 +8,19 @@ #ifndef GPIOLIB_ACPI_H #define GPIOLIB_ACPI_H +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/types.h> + +#include <linux/gpio/consumer.h> + struct acpi_device; +struct device; +struct fwnode_handle; + +struct gpio_chip; +struct gpio_desc; +struct gpio_device; /** * struct acpi_gpio_info - ACPI GPIO specific information diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 0cb6b468f364..65b2c09a4576 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -12,6 +12,7 @@ #include <linux/file.h> #include <linux/gpio.h> #include <linux/gpio/driver.h> +#include <linux/hte.h> #include <linux/interrupt.h> #include <linux/irqreturn.h> #include <linux/kernel.h> @@ -20,11 +21,12 @@ #include <linux/mutex.h> #include <linux/pinctrl/consumer.h> #include <linux/poll.h> +#include <linux/seq_file.h> #include <linux/spinlock.h> #include <linux/timekeeping.h> #include <linux/uaccess.h> #include <linux/workqueue.h> -#include <linux/hte.h> + #include <uapi/linux/gpio.h> #include "gpiolib.h" diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h index 8af2bc899aab..1b5df39a952e 100644 --- a/drivers/gpio/gpiolib-of.h +++ b/drivers/gpio/gpiolib-of.h @@ -3,8 +3,17 @@ #ifndef GPIOLIB_OF_H #define GPIOLIB_OF_H +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/types.h> + +#include <linux/notifier.h> + +struct device; + struct gpio_chip; -enum of_gpio_flags; +struct gpio_desc; +struct gpio_device; #ifdef CONFIG_OF_GPIO struct gpio_desc *of_find_gpio(struct device *dev, diff --git a/drivers/gpio/gpiolib-sysfs.h b/drivers/gpio/gpiolib-sysfs.h index ddd0e503f8eb..0f213bdb4732 100644 --- a/drivers/gpio/gpiolib-sysfs.h +++ b/drivers/gpio/gpiolib-sysfs.h @@ -5,6 +5,8 @@ #ifdef CONFIG_GPIO_SYSFS +struct gpio_device; + int gpiochip_sysfs_register(struct gpio_device *gdev); void gpiochip_sysfs_unregister(struct gpio_device *gdev); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4756ea08894f..a70522aef355 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -526,12 +526,13 @@ static int gpiochip_setup_dev(struct gpio_device *gdev) if (ret) return ret; + /* From this point, the .release() function cleans up gpio_device */ + gdev->dev.release = gpiodevice_release; + ret = gpiochip_sysfs_register(gdev); if (ret) goto err_remove_device; - /* From this point, the .release() function cleans up gpio_device */ - gdev->dev.release = gpiodevice_release; dev_dbg(&gdev->dev, "registered GPIOs %d to %d on %s\n", gdev->base, gdev->base + gdev->ngpio - 1, gdev->chip->label ? : "generic"); @@ -597,10 +598,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, struct fwnode_handle *fwnode = NULL; struct gpio_device *gdev; unsigned long flags; - int base = gc->base; unsigned int i; + u32 ngpios = 0; + int base = 0; int ret = 0; - u32 ngpios; if (gc->fwnode) fwnode = gc->fwnode; @@ -647,17 +648,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, else gdev->owner = THIS_MODULE; - gdev->descs = kcalloc(gc->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL); - if (!gdev->descs) { - ret = -ENOMEM; - goto err_free_dev_name; - } - /* * Try the device properties if the driver didn't supply the number * of GPIO lines. */ - if (gc->ngpio == 0) { + ngpios = gc->ngpio; + if (ngpios == 0) { ret = device_property_read_u32(&gdev->dev, "ngpios", &ngpios); if (ret == -ENODATA) /* @@ -668,7 +664,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, */ ngpios = 0; else if (ret) - goto err_free_descs; + goto err_free_dev_name; gc->ngpio = ngpios; } @@ -676,13 +672,19 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, if (gc->ngpio == 0) { chip_err(gc, "tried to insert a GPIO chip with zero lines\n"); ret = -EINVAL; - goto err_free_descs; + goto err_free_dev_name; } if (gc->ngpio > FASTPATH_NGPIO) chip_warn(gc, "line cnt %u is greater than fast path cnt %u\n", gc->ngpio, FASTPATH_NGPIO); + gdev->descs = kcalloc(gc->ngpio, sizeof(*gdev->descs), GFP_KERNEL); + if (!gdev->descs) { + ret = -ENOMEM; + goto err_free_dev_name; + } + gdev->label = kstrdup_const(gc->label ?: "unknown", GFP_KERNEL); if (!gdev->label) { ret = -ENOMEM; @@ -701,11 +703,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, * it may be a pipe dream. It will not happen before we get rid * of the sysfs interface anyways. */ + base = gc->base; if (base < 0) { base = gpiochip_find_base(gc->ngpio); if (base < 0) { - ret = base; spin_unlock_irqrestore(&gpio_lock, flags); + ret = base; + base = 0; goto err_free_label; } /* @@ -816,6 +820,11 @@ err_remove_of_chip: err_free_gpiochip_mask: gpiochip_remove_pin_ranges(gc); gpiochip_free_valid_mask(gc); + if (gdev->dev.release) { + /* release() has been registered by gpiochip_setup_dev() */ + put_device(&gdev->dev); + goto err_print_message; + } err_remove_from_list: spin_lock_irqsave(&gpio_lock, flags); list_del(&gdev->list); @@ -829,13 +838,14 @@ err_free_dev_name: err_free_ida: ida_free(&gpio_ida, gdev->id); err_free_gdev: + kfree(gdev); +err_print_message: /* failures here can mean systems won't boot... */ if (ret != -EPROBE_DEFER) { pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__, - gdev->base, gdev->base + gdev->ngpio - 1, + base, base + (int)ngpios - 1, gc->label ? : "generic", ret); } - kfree(gdev); return ret; } EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key); |