From 806766af3909258ccab74265e33ce8afd21af952 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 3 Nov 2019 23:38:39 +0100 Subject: Revert "gpio: merrifield: Move hardware initialization to callback" This reverts commit 4c87540940cbc7ddbe9674087919c605fd5c2ef1. This revert is a prerequisite for the later revert of commit 8f86a5b4ad679e4836733b47414226074eee4e4d. Reported-by: Hans de Goede Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 2f1e9da81c1e..9596024c9161 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -362,9 +362,8 @@ static void mrfld_irq_handler(struct irq_desc *desc) chained_irq_exit(irqchip, desc); } -static int mrfld_irq_init_hw(struct gpio_chip *chip) +static void mrfld_irq_init_hw(struct mrfld_gpio *priv) { - struct mrfld_gpio *priv = gpiochip_get_data(chip); void __iomem *reg; unsigned int base; @@ -376,8 +375,6 @@ static int mrfld_irq_init_hw(struct gpio_chip *chip) reg = gpio_reg(&priv->chip, base, GFER); writel(0, reg); } - - return 0; } static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) @@ -450,7 +447,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id girq = &priv->chip.irq; girq->chip = &mrfld_irqchip; - girq->init_hw = mrfld_irq_init_hw; girq->parent_handler = mrfld_irq_handler; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, @@ -463,6 +459,8 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; + mrfld_irq_init_hw(priv); + pci_set_drvdata(pdev, priv); retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); if (retval) { -- cgit v1.2.3 From 52c75f56703e1c40a2bc3f64a140602112dfa302 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 3 Nov 2019 23:40:48 +0100 Subject: Revert "gpio: merrifield: Restore use of irq_base" This reverts commit 6658f87f219427ee776c498e07c878eb5cad1be2. This revert is a prerequisite for the later revert of commit 8f86a5b4ad679e4836733b47414226074eee4e4d. Reported-by: Hans de Goede Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 9596024c9161..4f27ddfe1e2f 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -455,7 +455,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id if (!girq->parents) return -ENOMEM; girq->parents[0] = pdev->irq; - girq->first = irq_base; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; -- cgit v1.2.3 From 1173c3c28abfc3d7b7665db502280ba9322320e6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 3 Nov 2019 23:41:11 +0100 Subject: Revert "gpio: merrifield: Pass irqchip when adding gpiochip" This reverts commit 8f86a5b4ad679e4836733b47414226074eee4e4d. It has been established that this causes a boot regression on both Baytrail and Cherrytrail SoCs, and we can't have that in the final kernel release, so we need to revert it. Reported-by: Hans de Goede Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-merrifield.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 4f27ddfe1e2f..3302125e5265 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -397,7 +397,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id { const struct mrfld_gpio_pinrange *range; const char *pinctrl_dev_name; - struct gpio_irq_chip *girq; struct mrfld_gpio *priv; u32 gpio_base, irq_base; void __iomem *base; @@ -445,21 +444,6 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id raw_spin_lock_init(&priv->lock); - girq = &priv->chip.irq; - girq->chip = &mrfld_irqchip; - girq->parent_handler = mrfld_irq_handler; - girq->num_parents = 1; - girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, - sizeof(*girq->parents), - GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; - girq->parents[0] = pdev->irq; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_bad_irq; - - mrfld_irq_init_hw(priv); - pci_set_drvdata(pdev, priv); retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); if (retval) { @@ -481,6 +465,18 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id } } + retval = gpiochip_irqchip_add(&priv->chip, &mrfld_irqchip, irq_base, + handle_bad_irq, IRQ_TYPE_NONE); + if (retval) { + dev_err(&pdev->dev, "could not connect irqchip to gpiochip\n"); + return retval; + } + + mrfld_irq_init_hw(priv); + + gpiochip_set_chained_irqchip(&priv->chip, &mrfld_irqchip, pdev->irq, + mrfld_irq_handler); + return 0; } -- cgit v1.2.3 From f51b18d92b6668dde131247928233e8a7de6f7b2 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 22 Oct 2019 10:43:17 +0200 Subject: gpio: mvebu: use devm_platform_ioremap_resource_byname() Use devm_platform_ioremap_resource_byname() instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately. Signed-off-by: Bartosz Golaszewski Reviewed-by: Arnd Bergmann Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20191022084318.22256-8-brgl@bgdev.pl Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-mvebu.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 6c0687694341..2f0f50336b9a 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -773,23 +773,12 @@ static int mvebu_pwm_probe(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct mvebu_pwm *mvpwm; - struct resource *res; u32 set; if (!of_device_is_compatible(mvchip->chip.of_node, "marvell,armada-370-gpio")) return 0; - /* - * There are only two sets of PWM configuration registers for - * all the GPIO lines on those SoCs which this driver reserves - * for the first two GPIO chips. So if the resource is missing - * we can't treat it as an error. - */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"); - if (!res) - return 0; - if (IS_ERR(mvchip->clk)) return PTR_ERR(mvchip->clk); @@ -812,7 +801,13 @@ static int mvebu_pwm_probe(struct platform_device *pdev, mvchip->mvpwm = mvpwm; mvpwm->mvchip = mvchip; - mvpwm->membase = devm_ioremap_resource(dev, res); + /* + * There are only two sets of PWM configuration registers for + * all the GPIO lines on those SoCs which this driver reserves + * for the first two GPIO chips. So if the resource is missing + * we can't treat it as an error. + */ + mvpwm->membase = devm_platform_ioremap_resource_byname(pdev, "pwm"); if (IS_ERR(mvpwm->membase)) return PTR_ERR(mvpwm->membase); -- cgit v1.2.3 From cc4c831811c2901b4b896c76ecb97212d73ad5aa Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 22 Oct 2019 10:43:18 +0200 Subject: gpio: tegra186: use devm_platform_ioremap_resource_byname() Use the devm_platform_ioremap_resource_byname() helper instead of calling platform_get_resource_byname() and devm_ioremap_resource() separately. Signed-off-by: Bartosz Golaszewski Reviewed-by: Arnd Bergmann Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20191022084318.22256-9-brgl@bgdev.pl Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-tegra186.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index a9058fda187e..ef40fbe923cf 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -407,7 +407,6 @@ static int tegra186_gpio_probe(struct platform_device *pdev) unsigned int i, j, offset; struct gpio_irq_chip *irq; struct tegra_gpio *gpio; - struct resource *res; char **names; int err; @@ -417,8 +416,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->soc = of_device_get_match_data(&pdev->dev); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio"); - gpio->base = devm_ioremap_resource(&pdev->dev, res); + gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio"); if (IS_ERR(gpio->base)) return PTR_ERR(gpio->base); -- cgit v1.2.3 From bd84f2881a8d4c720bb4acaab371578f4f96b3de Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 23 Oct 2019 15:21:50 +0300 Subject: gpio: bd70528: Add MODULE ALIAS to autoload module The bd70528 GPIO driver is probed by MFD driver. Add MODULE_ALIAS in order to allow udev to load the module when MFD sub-device cell for GPIO is added. Signed-off-by: Matti Vaittinen Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-bd70528.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c index 734be6b752d0..88ab3bc85aac 100644 --- a/drivers/gpio/gpio-bd70528.c +++ b/drivers/gpio/gpio-bd70528.c @@ -232,3 +232,4 @@ module_platform_driver(bd70528_gpio); MODULE_AUTHOR("Matti Vaittinen "); MODULE_DESCRIPTION("BD70528 voltage regulator driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bd70528-gpio"); -- cgit v1.2.3 From b74f0456c120289b026701f849e0fd7de56fd2d7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Oct 2019 14:22:23 +0200 Subject: gpio: em: Use proper irq_chip name The irq_chip .name field should contain the device's class name, not the instance's name. Signed-off-by: Geert Uytterhoeven Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-em.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 674ebebaf90b..adc281daacff 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -322,7 +322,7 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->ngpio = ngpios; irq_chip = &p->irq_chip; - irq_chip->name = name; + irq_chip->name = "gpio-em"; irq_chip->irq_mask = em_gio_irq_disable; irq_chip->irq_unmask = em_gio_irq_enable; irq_chip->irq_set_type = em_gio_irq_set_type; -- cgit v1.2.3 From f932a68695e4c7d92e721d2c23580d9f35494662 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Oct 2019 14:22:24 +0200 Subject: gpio: rcar: Use proper irq_chip name The irq_chip .name field should contain the device's class name, not the instance's name. Signed-off-by: Geert Uytterhoeven Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-rcar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index d7e6e68c25af..f800b250971c 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -486,7 +486,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip->ngpio = npins; irq_chip = &p->irq_chip; - irq_chip->name = name; + irq_chip->name = "gpio-rcar"; irq_chip->parent_device = dev; irq_chip->irq_mask = gpio_rcar_irq_disable; irq_chip->irq_unmask = gpio_rcar_irq_enable; -- cgit v1.2.3 From 9225d5169d110734099a82c39c073a11e399cb3f Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 5 Nov 2019 10:04:23 +0800 Subject: gpio: expose pull-up/pull-down line flags to userspace Add pull-up/pull-down flags to the gpio line get and set ioctl() calls. Use cases include a push button that does not have an external resistor. Addition use cases described by Limor Fried (ladyada) of Adafruit in this PR for Adafruit_Blinka Python lib: https://github.com/adafruit/Adafruit_Blinka/pull/59 Signed-off-by: Drew Fustini [Kent: added BIAS to GPIO flag names and restrict application to input lines] Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 18 ++++++++++++++++++ include/uapi/linux/gpio.h | 4 ++++ 2 files changed, 22 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 731d732cdc2b..53086724c051 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -422,6 +422,8 @@ struct linehandle_state { (GPIOHANDLE_REQUEST_INPUT | \ GPIOHANDLE_REQUEST_OUTPUT | \ GPIOHANDLE_REQUEST_ACTIVE_LOW | \ + GPIOHANDLE_REQUEST_BIAS_PULL_UP | \ + GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | \ GPIOHANDLE_REQUEST_OPEN_DRAIN | \ GPIOHANDLE_REQUEST_OPEN_SOURCE) @@ -553,6 +555,12 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))) return -EINVAL; + /* PULL_UP and PULL_DOWN flags only make sense for input mode. */ + if (!(lflags & GPIOHANDLE_REQUEST_INPUT) && + ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) || + (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN))) + return -EINVAL; + lh = kzalloc(sizeof(*lh), GFP_KERNEL); if (!lh) return -ENOMEM; @@ -593,6 +601,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) set_bit(FLAG_OPEN_DRAIN, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) + set_bit(FLAG_PULL_DOWN, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) + set_bit(FLAG_PULL_UP, &desc->flags); ret = gpiod_set_transitory(desc, false); if (ret < 0) @@ -1092,6 +1104,10 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE | GPIOLINE_FLAG_IS_OUT); + if (test_bit(FLAG_PULL_DOWN, &desc->flags)) + lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN; + if (test_bit(FLAG_PULL_UP, &desc->flags)) + lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_UP; if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; @@ -2785,6 +2801,8 @@ static bool gpiod_free_commit(struct gpio_desc *desc) clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); + clear_bit(FLAG_PULL_UP, &desc->flags); + clear_bit(FLAG_PULL_DOWN, &desc->flags); clear_bit(FLAG_IS_HOGGED, &desc->flags); ret = true; } diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 4ebfe0ac6c5b..39e6c7854d63 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -33,6 +33,8 @@ struct gpiochip_info { #define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) #define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) #define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) +#define GPIOLINE_FLAG_BIAS_PULL_UP (1UL << 5) +#define GPIOLINE_FLAG_BIAS_PULL_DOWN (1UL << 6) /** * struct gpioline_info - Information about a certain GPIO line @@ -62,6 +64,8 @@ struct gpioline_info { #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2) #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) +#define GPIOHANDLE_REQUEST_BIAS_PULL_UP (1UL << 5) +#define GPIOHANDLE_REQUEST_BIAS_PULL_DOWN (1UL << 6) /** * struct gpiohandle_request - Information about a GPIO handle request -- cgit v1.2.3 From 7b479a8448c2e5ced36ca6a2d03178b920298ee5 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 5 Nov 2019 10:04:24 +0800 Subject: gpiolib: add support for pull up/down to lineevent_create Add support for pull up/down to lineevent_create. Use cases include receiving asynchronous presses from a push button without an external pull up/down. Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 53086724c051..b7d7bb8bd20d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -951,6 +951,10 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) + set_bit(FLAG_PULL_DOWN, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) + set_bit(FLAG_PULL_UP, &desc->flags); ret = gpiod_direction_input(desc); if (ret) -- cgit v1.2.3 From 2148ad7790ea4f1f0081e6404fbb776bdbc793bb Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 5 Nov 2019 10:04:25 +0800 Subject: gpiolib: add support for disabling line bias Allow pull up/down bias to be disabled, allowing the line to float or to be biased only by external circuitry. Use case is for where the bias has been applied previously, either by default or by the user, but that setting may conflict with the current use of the line. Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 61 +++++++++++++++++++++++++++++++++++++++-------- drivers/gpio/gpiolib.h | 1 + include/uapi/linux/gpio.h | 2 ++ 3 files changed, 54 insertions(+), 10 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b7d7bb8bd20d..996911660306 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -424,6 +424,7 @@ struct linehandle_state { GPIOHANDLE_REQUEST_ACTIVE_LOW | \ GPIOHANDLE_REQUEST_BIAS_PULL_UP | \ GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | \ + GPIOHANDLE_REQUEST_BIAS_DISABLE | \ GPIOHANDLE_REQUEST_OPEN_DRAIN | \ GPIOHANDLE_REQUEST_OPEN_SOURCE) @@ -555,12 +556,21 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))) return -EINVAL; - /* PULL_UP and PULL_DOWN flags only make sense for input mode. */ + /* Bias flags only allowed for input mode. */ if (!(lflags & GPIOHANDLE_REQUEST_INPUT) && - ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) || + ((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) || + (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) || (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN))) return -EINVAL; + /* Only one bias flag can be set. */ + if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) && + (lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | + GPIOHANDLE_REQUEST_BIAS_PULL_UP))) || + ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) && + (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP))) + return -EINVAL; + lh = kzalloc(sizeof(*lh), GFP_KERNEL); if (!lh) return -ENOMEM; @@ -601,6 +611,8 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) set_bit(FLAG_OPEN_DRAIN, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) + set_bit(FLAG_BIAS_DISABLE, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) set_bit(FLAG_PULL_DOWN, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) @@ -925,6 +937,14 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) return -EINVAL; + /* Only one bias flag can be set. */ + if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) && + (lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | + GPIOHANDLE_REQUEST_BIAS_PULL_UP))) || + ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) && + (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP))) + return -EINVAL; + le = kzalloc(sizeof(*le), GFP_KERNEL); if (!le) return -ENOMEM; @@ -951,6 +971,8 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) + set_bit(FLAG_BIAS_DISABLE, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) set_bit(FLAG_PULL_DOWN, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) @@ -1108,6 +1130,8 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE | GPIOLINE_FLAG_IS_OUT); + if (test_bit(FLAG_BIAS_DISABLE, &desc->flags)) + lineinfo.flags |= GPIOLINE_FLAG_BIAS_DISABLE; if (test_bit(FLAG_PULL_DOWN, &desc->flags)) lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN; if (test_bit(FLAG_PULL_UP, &desc->flags)) @@ -2807,6 +2831,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc) clear_bit(FLAG_OPEN_SOURCE, &desc->flags); clear_bit(FLAG_PULL_UP, &desc->flags); clear_bit(FLAG_PULL_DOWN, &desc->flags); + clear_bit(FLAG_BIAS_DISABLE, &desc->flags); clear_bit(FLAG_IS_HOGGED, &desc->flags); ret = true; } @@ -2933,6 +2958,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset, unsigned arg; switch (mode) { + case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_UP: arg = 1; @@ -2946,6 +2972,26 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset, return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP; } +static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc) +{ + int bias = 0; + int ret = 0; + + if (test_bit(FLAG_BIAS_DISABLE, &desc->flags)) + bias = PIN_CONFIG_BIAS_DISABLE; + else if (test_bit(FLAG_PULL_UP, &desc->flags)) + bias = PIN_CONFIG_BIAS_PULL_UP; + else if (test_bit(FLAG_PULL_DOWN, &desc->flags)) + bias = PIN_CONFIG_BIAS_PULL_DOWN; + + if (bias) { + ret = gpio_set_config(chip, gpio_chip_hwgpio(desc), bias); + if (ret != -ENOTSUPP) + return ret; + } + return 0; +} + /** * gpiod_direction_input - set the GPIO direction to input * @desc: GPIO to set to input @@ -2990,15 +3036,10 @@ int gpiod_direction_input(struct gpio_desc *desc) __func__); return -EIO; } - if (ret == 0) + if (ret == 0) { clear_bit(FLAG_IS_OUT, &desc->flags); - - if (test_bit(FLAG_PULL_UP, &desc->flags)) - gpio_set_config(chip, gpio_chip_hwgpio(desc), - PIN_CONFIG_BIAS_PULL_UP); - else if (test_bit(FLAG_PULL_DOWN, &desc->flags)) - gpio_set_config(chip, gpio_chip_hwgpio(desc), - PIN_CONFIG_BIAS_PULL_DOWN); + ret = gpio_set_bias(chip, desc); + } trace_gpio_direction(desc_to_gpio(desc), 1, ret); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index b8b10a409c7b..ca9bc1e4803c 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -110,6 +110,7 @@ struct gpio_desc { #define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ #define FLAG_PULL_UP 13 /* GPIO has pull up enabled */ #define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */ +#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */ /* Connection label */ const char *label; diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 39e6c7854d63..7cc21c3b0839 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -35,6 +35,7 @@ struct gpiochip_info { #define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) #define GPIOLINE_FLAG_BIAS_PULL_UP (1UL << 5) #define GPIOLINE_FLAG_BIAS_PULL_DOWN (1UL << 6) +#define GPIOLINE_FLAG_BIAS_DISABLE (1UL << 7) /** * struct gpioline_info - Information about a certain GPIO line @@ -66,6 +67,7 @@ struct gpioline_info { #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) #define GPIOHANDLE_REQUEST_BIAS_PULL_UP (1UL << 5) #define GPIOHANDLE_REQUEST_BIAS_PULL_DOWN (1UL << 6) +#define GPIOHANDLE_REQUEST_BIAS_DISABLE (1UL << 7) /** * struct gpiohandle_request - Information about a GPIO handle request -- cgit v1.2.3 From 2821ae5f3033fb4140855ffd728c28fb42ba2bb9 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 5 Nov 2019 10:04:26 +0800 Subject: gpiolib: add support for biasing output lines Allow pull up/down bias to be set on output lines. Use case is for open source or open drain applications where internal pull up/down may conflict with external biasing. Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 996911660306..be159f56ff45 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -556,8 +556,9 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))) return -EINVAL; - /* Bias flags only allowed for input mode. */ - if (!(lflags & GPIOHANDLE_REQUEST_INPUT) && + /* Bias flags only allowed for input or output mode. */ + if (!((lflags & GPIOHANDLE_REQUEST_INPUT) || + (lflags & GPIOHANDLE_REQUEST_OUTPUT)) && ((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) || (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) || (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN))) @@ -3169,6 +3170,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) } set_output_value: + ret = gpio_set_bias(gc, desc); + if (ret) + return ret; return gpiod_direction_output_raw_commit(desc, value); set_output_flag: -- cgit v1.2.3 From 64e7112ee307834680eed578fdc0cfee63263fa7 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 5 Nov 2019 10:04:27 +0800 Subject: gpio: mockup: add set_config to support pull up/down Add support for the pull up/down state set via gpiolib line requests to be reflected in the state of the mockup. Use case is for testing of the GPIO uAPI, specifically the pull up/down flags. Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mockup.c | 94 +++++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 34 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 47c172b2f5ad..56d647a30e3e 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -141,6 +141,61 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc, mutex_unlock(&chip->lock); } +static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip, + unsigned int offset, int value) +{ + struct gpio_desc *desc; + struct gpio_chip *gc; + struct irq_sim *sim; + int curr, irq, irq_type; + + gc = &chip->gc; + desc = &gc->gpiodev->descs[offset]; + sim = &chip->irqsim; + + mutex_lock(&chip->lock); + + if (test_bit(FLAG_REQUESTED, &desc->flags) && + !test_bit(FLAG_IS_OUT, &desc->flags)) { + curr = __gpio_mockup_get(chip, offset); + if (curr == value) + goto out; + + irq = irq_sim_irqnum(sim, offset); + irq_type = irq_get_trigger_type(irq); + + if ((value == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) || + (value == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING))) + irq_sim_fire(sim, offset); + } + + /* Change the value unless we're actively driving the line. */ + if (!test_bit(FLAG_REQUESTED, &desc->flags) || + !test_bit(FLAG_IS_OUT, &desc->flags)) + __gpio_mockup_set(chip, offset, value); + +out: + chip->lines[offset].pull = value; + mutex_unlock(&chip->lock); + return 0; +} + +static int gpio_mockup_set_config(struct gpio_chip *gc, + unsigned int offset, unsigned long config) +{ + struct gpio_mockup_chip *chip = gpiochip_get_data(gc); + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_PULL_UP: + return gpio_mockup_apply_pull(chip, offset, 1); + case PIN_CONFIG_BIAS_PULL_DOWN: + return gpio_mockup_apply_pull(chip, offset, 0); + default: + break; + } + return -ENOTSUPP; +} + static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset, int value) { @@ -221,12 +276,8 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file, size_t size, loff_t *ppos) { struct gpio_mockup_dbgfs_private *priv; - int rv, val, curr, irq, irq_type; - struct gpio_mockup_chip *chip; + int rv, val; struct seq_file *sfile; - struct gpio_desc *desc; - struct gpio_chip *gc; - struct irq_sim *sim; if (*ppos != 0) return -EINVAL; @@ -239,35 +290,9 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file, sfile = file->private_data; priv = sfile->private; - chip = priv->chip; - gc = &chip->gc; - desc = &gc->gpiodev->descs[priv->offset]; - sim = &chip->irqsim; - - mutex_lock(&chip->lock); - - if (test_bit(FLAG_REQUESTED, &desc->flags) && - !test_bit(FLAG_IS_OUT, &desc->flags)) { - curr = __gpio_mockup_get(chip, priv->offset); - if (curr == val) - goto out; - - irq = irq_sim_irqnum(sim, priv->offset); - irq_type = irq_get_trigger_type(irq); - - if ((val == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) || - (val == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING))) - irq_sim_fire(sim, priv->offset); - } - - /* Change the value unless we're actively driving the line. */ - if (!test_bit(FLAG_REQUESTED, &desc->flags) || - !test_bit(FLAG_IS_OUT, &desc->flags)) - __gpio_mockup_set(chip, priv->offset, val); - -out: - chip->lines[priv->offset].pull = val; - mutex_unlock(&chip->lock); + rv = gpio_mockup_apply_pull(priv->chip, priv->offset, val); + if (rv) + return rv; return size; } @@ -413,6 +438,7 @@ static int gpio_mockup_probe(struct platform_device *pdev) gc->direction_output = gpio_mockup_dirout; gc->direction_input = gpio_mockup_dirin; gc->get_direction = gpio_mockup_get_direction; + gc->set_config = gpio_mockup_set_config; gc->to_irq = gpio_mockup_to_irq; gc->free = gpio_mockup_free; -- cgit v1.2.3 From b043ed7ef0b358d7f32dc57c218f925fd2802aba Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 5 Nov 2019 10:04:28 +0800 Subject: gpiolib: move validation of line handle flags into helper function Move validation of line handle flags into helper function. This reduces the size and complexity of linehandle_create and allows the validation to be reused elsewhere. Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 93 +++++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 42 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index be159f56ff45..a9826627f347 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -428,6 +428,54 @@ struct linehandle_state { GPIOHANDLE_REQUEST_OPEN_DRAIN | \ GPIOHANDLE_REQUEST_OPEN_SOURCE) +static int linehandle_validate_flags(u32 flags) +{ + /* Return an error if an unknown flag is set */ + if (flags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) + return -EINVAL; + + /* + * Do not allow both INPUT & OUTPUT flags to be set as they are + * contradictory. + */ + if ((flags & GPIOHANDLE_REQUEST_INPUT) && + (flags & GPIOHANDLE_REQUEST_OUTPUT)) + return -EINVAL; + + /* + * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If + * the hardware actually supports enabling both at the same time the + * electrical result would be disastrous. + */ + if ((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) && + (flags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) + return -EINVAL; + + /* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */ + if (!(flags & GPIOHANDLE_REQUEST_OUTPUT) && + ((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) || + (flags & GPIOHANDLE_REQUEST_OPEN_SOURCE))) + return -EINVAL; + + /* Bias flags only allowed for input or output mode. */ + if (!((flags & GPIOHANDLE_REQUEST_INPUT) || + (flags & GPIOHANDLE_REQUEST_OUTPUT)) && + ((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) || + (flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) || + (flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN))) + return -EINVAL; + + /* Only one bias flag can be set. */ + if (((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) && + (flags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | + GPIOHANDLE_REQUEST_BIAS_PULL_UP))) || + ((flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) && + (flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP))) + return -EINVAL; + + return 0; +} + static long linehandle_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { @@ -529,48 +577,9 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) lflags = handlereq.flags; - /* Return an error if an unknown flag is set */ - if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) - return -EINVAL; - - /* - * Do not allow both INPUT & OUTPUT flags to be set as they are - * contradictory. - */ - if ((lflags & GPIOHANDLE_REQUEST_INPUT) && - (lflags & GPIOHANDLE_REQUEST_OUTPUT)) - return -EINVAL; - - /* - * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If - * the hardware actually supports enabling both at the same time the - * electrical result would be disastrous. - */ - if ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) && - (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) - return -EINVAL; - - /* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */ - if (!(lflags & GPIOHANDLE_REQUEST_OUTPUT) && - ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) || - (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))) - return -EINVAL; - - /* Bias flags only allowed for input or output mode. */ - if (!((lflags & GPIOHANDLE_REQUEST_INPUT) || - (lflags & GPIOHANDLE_REQUEST_OUTPUT)) && - ((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) || - (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) || - (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN))) - return -EINVAL; - - /* Only one bias flag can be set. */ - if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) && - (lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | - GPIOHANDLE_REQUEST_BIAS_PULL_UP))) || - ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) && - (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP))) - return -EINVAL; + ret = linehandle_validate_flags(lflags); + if (ret) + return ret; lh = kzalloc(sizeof(*lh), GFP_KERNEL); if (!lh) -- cgit v1.2.3 From e588bb1eae31be73fbec2b731be986a7c09635a4 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 5 Nov 2019 10:04:29 +0800 Subject: gpio: add new SET_CONFIG ioctl() to gpio chardev Add the GPIOHANDLE_SET_CONFIG_IOCTL to the gpio chardev. The ioctl allows some of the configuration of a requested handle to be changed without having to release the line. The primary use case is the changing of direction for bi-directional lines. Based on initial work by Bartosz Golaszewski Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/gpio.h | 18 +++++++++++++ 2 files changed, 87 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a9826627f347..dba5f08f308c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -476,6 +476,73 @@ static int linehandle_validate_flags(u32 flags) return 0; } +static void linehandle_configure_flag(unsigned long *flagsp, + u32 bit, bool active) +{ + if (active) + set_bit(bit, flagsp); + else + clear_bit(bit, flagsp); +} + +static long linehandle_set_config(struct linehandle_state *lh, + void __user *ip) +{ + struct gpiohandle_config gcnf; + struct gpio_desc *desc; + int i, ret; + u32 lflags; + unsigned long *flagsp; + + if (copy_from_user(&gcnf, ip, sizeof(gcnf))) + return -EFAULT; + + lflags = gcnf.flags; + ret = linehandle_validate_flags(lflags); + if (ret) + return ret; + + for (i = 0; i < lh->numdescs; i++) { + desc = lh->descs[i]; + flagsp = &desc->flags; + + linehandle_configure_flag(flagsp, FLAG_ACTIVE_LOW, + lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW); + + linehandle_configure_flag(flagsp, FLAG_OPEN_DRAIN, + lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN); + + linehandle_configure_flag(flagsp, FLAG_OPEN_SOURCE, + lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE); + + linehandle_configure_flag(flagsp, FLAG_PULL_UP, + lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP); + + linehandle_configure_flag(flagsp, FLAG_PULL_DOWN, + lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN); + + linehandle_configure_flag(flagsp, FLAG_BIAS_DISABLE, + lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE); + + /* + * Lines have to be requested explicitly for input + * or output, else the line will be treated "as is". + */ + if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { + int val = !!gcnf.default_values[i]; + + ret = gpiod_direction_output(desc, val); + if (ret) + return ret; + } else if (lflags & GPIOHANDLE_REQUEST_INPUT) { + ret = gpiod_direction_input(desc); + if (ret) + return ret; + } + } + return 0; +} + static long linehandle_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { @@ -526,6 +593,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, lh->descs, NULL, vals); + } else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) { + return linehandle_set_config(lh, ip); } return -EINVAL; } diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 7cc21c3b0839..799cf823d493 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -100,6 +100,24 @@ struct gpiohandle_request { int fd; }; +/** + * struct gpiohandle_config - Configuration for a GPIO handle request + * @flags: updated flags for the requested GPIO lines, such as + * GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed + * together + * @default_values: if the GPIOHANDLE_REQUEST_OUTPUT is set in flags, + * this specifies the default output value, should be 0 (low) or + * 1 (high), anything else than 0 or 1 will be interpreted as 1 (high) + * @padding: reserved for future use and should be zero filled + */ +struct gpiohandle_config { + __u32 flags; + __u8 default_values[GPIOHANDLES_MAX]; + __u32 padding[4]; /* padding for future use */ +}; + +#define GPIOHANDLE_SET_CONFIG_IOCTL _IOWR(0xB4, 0x0a, struct gpiohandle_config) + /** * struct gpiohandle_data - Information of values on a GPIO handle * @values: when getting the state of lines this contains the current -- cgit v1.2.3 From 13a62a56aa4cdab94e696bc0a3e4fb6dc4200b0f Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Nov 2019 16:33:51 +0100 Subject: gpio: tegra186: Derive register offsets from bank/port The register offsets for a given bank and port can be easily derived from the bank and port indices. Update the port descriptors to list only the bank and port numbers to simplify this. Signed-off-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra186.c | 195 ++++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 95 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 934ab3605849..1e9993143eb4 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -44,9 +44,9 @@ struct tegra_gpio_port { const char *name; - unsigned int offset; + unsigned int bank; + unsigned int port; unsigned int pins; - unsigned int irq; }; struct tegra_gpio_soc { @@ -90,12 +90,15 @@ static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio, unsigned int pin) { const struct tegra_gpio_port *port; + unsigned int offset; port = tegra186_gpio_get_port(gpio, &pin); if (!port) return NULL; - return gpio->base + port->offset + pin * 0x20; + offset = port->bank * 0x1000 + port->port * 0x200; + + return gpio->base + offset + pin * 0x20; } static int tegra186_gpio_get_direction(struct gpio_chip *chip, @@ -343,12 +346,14 @@ static void tegra186_gpio_irq(struct irq_desc *desc) for (i = 0; i < gpio->soc->num_ports; i++) { const struct tegra_gpio_port *port = &gpio->soc->ports[i]; - void __iomem *base = gpio->base + port->offset; unsigned int pin, irq; unsigned long value; + void __iomem *base; + + base = gpio->base + port->bank * 0x1000 + port->port * 0x200; - /* skip ports that are not associated with this controller */ - if (parent != gpio->irq[port->irq]) + /* skip ports that are not associated with this bank */ + if (parent != gpio->irq[port->bank]) goto skip; value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1)); @@ -562,7 +567,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) const struct tegra_gpio_port *port = &gpio->soc->ports[i]; for (j = 0; j < port->pins; j++) - irq->map[offset + j] = irq->parents[port->irq]; + irq->map[offset + j] = irq->parents[port->bank]; offset += port->pins; } @@ -581,38 +586,38 @@ static int tegra186_gpio_remove(struct platform_device *pdev) return 0; } -#define TEGRA186_MAIN_GPIO_PORT(port, base, count, controller) \ - [TEGRA186_MAIN_GPIO_PORT_##port] = { \ - .name = #port, \ - .offset = base, \ - .pins = count, \ - .irq = controller, \ +#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA186_MAIN_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ } static const struct tegra_gpio_port tegra186_main_ports[] = { - TEGRA186_MAIN_GPIO_PORT( A, 0x2000, 7, 2), - TEGRA186_MAIN_GPIO_PORT( B, 0x3000, 7, 3), - TEGRA186_MAIN_GPIO_PORT( C, 0x3200, 7, 3), - TEGRA186_MAIN_GPIO_PORT( D, 0x3400, 6, 3), - TEGRA186_MAIN_GPIO_PORT( E, 0x2200, 8, 2), - TEGRA186_MAIN_GPIO_PORT( F, 0x2400, 6, 2), - TEGRA186_MAIN_GPIO_PORT( G, 0x4200, 6, 4), - TEGRA186_MAIN_GPIO_PORT( H, 0x1000, 7, 1), - TEGRA186_MAIN_GPIO_PORT( I, 0x0800, 8, 0), - TEGRA186_MAIN_GPIO_PORT( J, 0x5000, 8, 5), - TEGRA186_MAIN_GPIO_PORT( K, 0x5200, 1, 5), - TEGRA186_MAIN_GPIO_PORT( L, 0x1200, 8, 1), - TEGRA186_MAIN_GPIO_PORT( M, 0x5600, 6, 5), - TEGRA186_MAIN_GPIO_PORT( N, 0x0000, 7, 0), - TEGRA186_MAIN_GPIO_PORT( O, 0x0200, 4, 0), - TEGRA186_MAIN_GPIO_PORT( P, 0x4000, 7, 4), - TEGRA186_MAIN_GPIO_PORT( Q, 0x0400, 6, 0), - TEGRA186_MAIN_GPIO_PORT( R, 0x0a00, 6, 0), - TEGRA186_MAIN_GPIO_PORT( T, 0x0600, 4, 0), - TEGRA186_MAIN_GPIO_PORT( X, 0x1400, 8, 1), - TEGRA186_MAIN_GPIO_PORT( Y, 0x1600, 7, 1), - TEGRA186_MAIN_GPIO_PORT(BB, 0x2600, 2, 2), - TEGRA186_MAIN_GPIO_PORT(CC, 0x5400, 4, 5), + TEGRA186_MAIN_GPIO_PORT( A, 2, 0, 7), + TEGRA186_MAIN_GPIO_PORT( B, 3, 0, 7), + TEGRA186_MAIN_GPIO_PORT( C, 3, 1, 7), + TEGRA186_MAIN_GPIO_PORT( D, 3, 2, 6), + TEGRA186_MAIN_GPIO_PORT( E, 2, 1, 8), + TEGRA186_MAIN_GPIO_PORT( F, 2, 2, 6), + TEGRA186_MAIN_GPIO_PORT( G, 4, 1, 6), + TEGRA186_MAIN_GPIO_PORT( H, 1, 0, 7), + TEGRA186_MAIN_GPIO_PORT( I, 0, 4, 8), + TEGRA186_MAIN_GPIO_PORT( J, 5, 0, 8), + TEGRA186_MAIN_GPIO_PORT( K, 5, 1, 1), + TEGRA186_MAIN_GPIO_PORT( L, 1, 1, 8), + TEGRA186_MAIN_GPIO_PORT( M, 5, 3, 6), + TEGRA186_MAIN_GPIO_PORT( N, 0, 0, 7), + TEGRA186_MAIN_GPIO_PORT( O, 0, 1, 4), + TEGRA186_MAIN_GPIO_PORT( P, 4, 0, 7), + TEGRA186_MAIN_GPIO_PORT( Q, 0, 2, 6), + TEGRA186_MAIN_GPIO_PORT( R, 0, 5, 6), + TEGRA186_MAIN_GPIO_PORT( T, 0, 3, 4), + TEGRA186_MAIN_GPIO_PORT( X, 1, 2, 8), + TEGRA186_MAIN_GPIO_PORT( Y, 1, 3, 7), + TEGRA186_MAIN_GPIO_PORT(BB, 2, 3, 2), + TEGRA186_MAIN_GPIO_PORT(CC, 5, 2, 4), }; static const struct tegra_gpio_soc tegra186_main_soc = { @@ -622,23 +627,23 @@ static const struct tegra_gpio_soc tegra186_main_soc = { .instance = 0, }; -#define TEGRA186_AON_GPIO_PORT(port, base, count, controller) \ - [TEGRA186_AON_GPIO_PORT_##port] = { \ - .name = #port, \ - .offset = base, \ - .pins = count, \ - .irq = controller, \ +#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA186_AON_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ } static const struct tegra_gpio_port tegra186_aon_ports[] = { - TEGRA186_AON_GPIO_PORT( S, 0x0200, 5, 0), - TEGRA186_AON_GPIO_PORT( U, 0x0400, 6, 0), - TEGRA186_AON_GPIO_PORT( V, 0x0800, 8, 0), - TEGRA186_AON_GPIO_PORT( W, 0x0a00, 8, 0), - TEGRA186_AON_GPIO_PORT( Z, 0x0e00, 4, 0), - TEGRA186_AON_GPIO_PORT(AA, 0x0c00, 8, 0), - TEGRA186_AON_GPIO_PORT(EE, 0x0600, 3, 0), - TEGRA186_AON_GPIO_PORT(FF, 0x0000, 5, 0), + TEGRA186_AON_GPIO_PORT( S, 0, 1, 5), + TEGRA186_AON_GPIO_PORT( U, 0, 2, 6), + TEGRA186_AON_GPIO_PORT( V, 0, 4, 8), + TEGRA186_AON_GPIO_PORT( W, 0, 5, 8), + TEGRA186_AON_GPIO_PORT( Z, 0, 7, 4), + TEGRA186_AON_GPIO_PORT(AA, 0, 6, 8), + TEGRA186_AON_GPIO_PORT(EE, 0, 3, 3), + TEGRA186_AON_GPIO_PORT(FF, 0, 0, 5), }; static const struct tegra_gpio_soc tegra186_aon_soc = { @@ -648,43 +653,43 @@ static const struct tegra_gpio_soc tegra186_aon_soc = { .instance = 1, }; -#define TEGRA194_MAIN_GPIO_PORT(port, base, count, controller) \ - [TEGRA194_MAIN_GPIO_PORT_##port] = { \ - .name = #port, \ - .offset = base, \ - .pins = count, \ - .irq = controller, \ +#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA194_MAIN_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ } static const struct tegra_gpio_port tegra194_main_ports[] = { - TEGRA194_MAIN_GPIO_PORT( A, 0x1400, 8, 1), - TEGRA194_MAIN_GPIO_PORT( B, 0x4e00, 2, 4), - TEGRA194_MAIN_GPIO_PORT( C, 0x4600, 8, 4), - TEGRA194_MAIN_GPIO_PORT( D, 0x4800, 4, 4), - TEGRA194_MAIN_GPIO_PORT( E, 0x4a00, 8, 4), - TEGRA194_MAIN_GPIO_PORT( F, 0x4c00, 6, 4), - TEGRA194_MAIN_GPIO_PORT( G, 0x4000, 8, 4), - TEGRA194_MAIN_GPIO_PORT( H, 0x4200, 8, 4), - TEGRA194_MAIN_GPIO_PORT( I, 0x4400, 5, 4), - TEGRA194_MAIN_GPIO_PORT( J, 0x5200, 6, 5), - TEGRA194_MAIN_GPIO_PORT( K, 0x3000, 8, 3), - TEGRA194_MAIN_GPIO_PORT( L, 0x3200, 4, 3), - TEGRA194_MAIN_GPIO_PORT( M, 0x2600, 8, 2), - TEGRA194_MAIN_GPIO_PORT( N, 0x2800, 3, 2), - TEGRA194_MAIN_GPIO_PORT( O, 0x5000, 6, 5), - TEGRA194_MAIN_GPIO_PORT( P, 0x2a00, 8, 2), - TEGRA194_MAIN_GPIO_PORT( Q, 0x2c00, 8, 2), - TEGRA194_MAIN_GPIO_PORT( R, 0x2e00, 6, 2), - TEGRA194_MAIN_GPIO_PORT( S, 0x3600, 8, 3), - TEGRA194_MAIN_GPIO_PORT( T, 0x3800, 8, 3), - TEGRA194_MAIN_GPIO_PORT( U, 0x3a00, 1, 3), - TEGRA194_MAIN_GPIO_PORT( V, 0x1000, 8, 1), - TEGRA194_MAIN_GPIO_PORT( W, 0x1200, 2, 1), - TEGRA194_MAIN_GPIO_PORT( X, 0x2000, 8, 2), - TEGRA194_MAIN_GPIO_PORT( Y, 0x2200, 8, 2), - TEGRA194_MAIN_GPIO_PORT( Z, 0x2400, 8, 2), - TEGRA194_MAIN_GPIO_PORT(FF, 0x3400, 2, 3), - TEGRA194_MAIN_GPIO_PORT(GG, 0x0000, 2, 0) + TEGRA194_MAIN_GPIO_PORT( A, 1, 2, 8), + TEGRA194_MAIN_GPIO_PORT( B, 4, 7, 2), + TEGRA194_MAIN_GPIO_PORT( C, 4, 3, 8), + TEGRA194_MAIN_GPIO_PORT( D, 4, 4, 4), + TEGRA194_MAIN_GPIO_PORT( E, 4, 5, 8), + TEGRA194_MAIN_GPIO_PORT( F, 4, 6, 6), + TEGRA194_MAIN_GPIO_PORT( G, 4, 0, 8), + TEGRA194_MAIN_GPIO_PORT( H, 4, 1, 8), + TEGRA194_MAIN_GPIO_PORT( I, 4, 2, 5), + TEGRA194_MAIN_GPIO_PORT( J, 5, 1, 6), + TEGRA194_MAIN_GPIO_PORT( K, 3, 0, 8), + TEGRA194_MAIN_GPIO_PORT( L, 3, 1, 4), + TEGRA194_MAIN_GPIO_PORT( M, 2, 3, 8), + TEGRA194_MAIN_GPIO_PORT( N, 2, 4, 3), + TEGRA194_MAIN_GPIO_PORT( O, 5, 0, 6), + TEGRA194_MAIN_GPIO_PORT( P, 2, 5, 8), + TEGRA194_MAIN_GPIO_PORT( Q, 2, 6, 8), + TEGRA194_MAIN_GPIO_PORT( R, 2, 7, 6), + TEGRA194_MAIN_GPIO_PORT( S, 3, 3, 8), + TEGRA194_MAIN_GPIO_PORT( T, 3, 4, 8), + TEGRA194_MAIN_GPIO_PORT( U, 3, 5, 1), + TEGRA194_MAIN_GPIO_PORT( V, 1, 0, 8), + TEGRA194_MAIN_GPIO_PORT( W, 1, 1, 2), + TEGRA194_MAIN_GPIO_PORT( X, 2, 0, 8), + TEGRA194_MAIN_GPIO_PORT( Y, 2, 1, 8), + TEGRA194_MAIN_GPIO_PORT( Z, 2, 2, 8), + TEGRA194_MAIN_GPIO_PORT(FF, 3, 2, 2), + TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2) }; static const struct tegra_gpio_soc tegra194_main_soc = { @@ -694,20 +699,20 @@ static const struct tegra_gpio_soc tegra194_main_soc = { .instance = 0, }; -#define TEGRA194_AON_GPIO_PORT(port, base, count, controller) \ - [TEGRA194_AON_GPIO_PORT_##port] = { \ - .name = #port, \ - .offset = base, \ - .pins = count, \ - .irq = controller, \ +#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins) \ + [TEGRA194_AON_GPIO_PORT_##_name] = { \ + .name = #_name, \ + .bank = _bank, \ + .port = _port, \ + .pins = _pins, \ } static const struct tegra_gpio_port tegra194_aon_ports[] = { - TEGRA194_AON_GPIO_PORT(AA, 0x0600, 8, 0), - TEGRA194_AON_GPIO_PORT(BB, 0x0800, 4, 0), - TEGRA194_AON_GPIO_PORT(CC, 0x0200, 8, 0), - TEGRA194_AON_GPIO_PORT(DD, 0x0400, 3, 0), - TEGRA194_AON_GPIO_PORT(EE, 0x0000, 7, 0) + TEGRA194_AON_GPIO_PORT(AA, 0, 3, 8), + TEGRA194_AON_GPIO_PORT(BB, 0, 4, 4), + TEGRA194_AON_GPIO_PORT(CC, 0, 1, 8), + TEGRA194_AON_GPIO_PORT(DD, 0, 2, 3), + TEGRA194_AON_GPIO_PORT(EE, 0, 0, 7) }; static const struct tegra_gpio_soc tegra194_aon_soc = { -- cgit v1.2.3 From 22635ed8a20d47ae3a590171aee90ccecfb62241 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Nov 2019 16:33:52 +0100 Subject: gpio: tegra186: Program interrupt route mapping The controls for the GG port on Tegra194 resides in the power partition of the C5 PCIe controller and its interrupt route mapping can therefore not be programmed by early boot firmware along with that of the other ports. Detect this generically by looking at which controls have already been locked down using the security registers and fill in default values for controls that are unlocked. Signed-off-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra186.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 1e9993143eb4..cb5efb83bad4 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -15,6 +15,14 @@ #include #include +/* security registers */ +#define TEGRA186_GPIO_CTL_SCR 0x0c +#define TEGRA186_GPIO_CTL_SCR_SEC_WEN BIT(28) +#define TEGRA186_GPIO_CTL_SCR_SEC_REN BIT(27) + +#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4) + +/* control registers */ #define TEGRA186_GPIO_ENABLE_CONFIG 0x00 #define TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0) #define TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1) @@ -64,6 +72,7 @@ struct tegra_gpio { const struct tegra_gpio_soc *soc; + void __iomem *secure; void __iomem *base; }; @@ -449,6 +458,37 @@ static const struct of_device_id tegra186_pmc_of_match[] = { { /* sentinel */ } }; +static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio) +{ + unsigned int i, j; + u32 value; + + for (i = 0; i < gpio->soc->num_ports; i++) { + const struct tegra_gpio_port *port = &gpio->soc->ports[i]; + unsigned int offset, p = port->port; + void __iomem *base; + + base = gpio->secure + port->bank * 0x1000 + 0x800; + + value = readl(base + TEGRA186_GPIO_CTL_SCR); + + /* + * For controllers that haven't been locked down yet, make + * sure to program the default interrupt route mapping. + */ + if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 && + (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) { + for (j = 0; j < 8; j++) { + offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j); + + value = readl(base + offset); + value = BIT(port->pins) - 1; + writel(value, base + offset); + } + } + } +} + static int tegra186_gpio_probe(struct platform_device *pdev) { unsigned int i, j, offset; @@ -464,6 +504,10 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->soc = of_device_get_match_data(&pdev->dev); + gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security"); + if (IS_ERR(gpio->secure)) + return PTR_ERR(gpio->secure); + gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio"); if (IS_ERR(gpio->base)) return PTR_ERR(gpio->base); @@ -558,6 +602,8 @@ static int tegra186_gpio_probe(struct platform_device *pdev) return -EPROBE_DEFER; } + tegra186_gpio_init_route_mapping(gpio); + irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio, sizeof(*irq->map), GFP_KERNEL); if (!irq->map) -- cgit v1.2.3 From adce1183932265e94bbaf92138b9c98d1c5359b9 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 8 Nov 2019 16:33:53 +0100 Subject: gpio: tegra186: Add debounce support The GPIO controller found on Tegra186 and later supports debouncing for inputs for up to 255 ms. Signed-off-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra186.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index cb5efb83bad4..55b43b7ce88d 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -32,6 +32,7 @@ #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE (0x3 << 2) #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK (0x3 << 2) #define TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4) +#define TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5) #define TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6) #define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04 @@ -217,6 +218,42 @@ static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset, writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE); } +static int tegra186_gpio_set_config(struct gpio_chip *chip, + unsigned int offset, + unsigned long config) +{ + struct tegra_gpio *gpio = gpiochip_get_data(chip); + u32 debounce, value; + void __iomem *base; + + base = tegra186_gpio_get_base(gpio, offset); + if (base == NULL) + return -ENXIO; + + if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) + return -ENOTSUPP; + + debounce = pinconf_to_config_argument(config); + + /* + * The Tegra186 GPIO controller supports a maximum of 255 ms debounce + * time. + */ + if (debounce > 255000) + return -EINVAL; + + debounce = DIV_ROUND_UP(debounce, USEC_PER_MSEC); + + value = TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(debounce); + writel(value, base + TEGRA186_GPIO_DEBOUNCE_CONTROL); + + value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); + value |= TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE; + writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG); + + return 0; +} + static int tegra186_gpio_of_xlate(struct gpio_chip *chip, const struct of_phandle_args *spec, u32 *flags) @@ -539,6 +576,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->gpio.direction_output = tegra186_gpio_direction_output; gpio->gpio.get = tegra186_gpio_get, gpio->gpio.set = tegra186_gpio_set; + gpio->gpio.set_config = tegra186_gpio_set_config; gpio->gpio.base = -1; -- cgit v1.2.3 From be053b2dc91c1a02881db0c90e9438b56ac1a019 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Nov 2019 11:11:03 +0100 Subject: gpio: em: Use platform_get_irq() to obtain interrupts Use the platform_get_irq() helper instead of handling resources directly. Signed-off-by: Geert Uytterhoeven Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-em.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index adc281daacff..17a243c528ad 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -269,13 +269,12 @@ static void em_gio_irq_domain_remove(void *data) static int em_gio_probe(struct platform_device *pdev) { struct em_gio_priv *p; - struct resource *irq[2]; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; struct device *dev = &pdev->dev; const char *name = dev_name(dev); unsigned int ngpios; - int ret; + int irq[2], ret; p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); if (!p) @@ -285,13 +284,13 @@ static int em_gio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); spin_lock_init(&p->sense_lock); - irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + irq[0] = platform_get_irq(pdev, 0); + if (irq[0] < 0) + return irq[0]; - if (!irq[0] || !irq[1]) { - dev_err(dev, "missing IRQ or IOMEM\n"); - return -EINVAL; - } + irq[1] = platform_get_irq(pdev, 1); + if (irq[1] < 0) + return irq[1]; p->base0 = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(p->base0)) @@ -342,14 +341,12 @@ static int em_gio_probe(struct platform_device *pdev) if (ret) return ret; - if (devm_request_irq(dev, irq[0]->start, - em_gio_irq_handler, 0, name, p)) { + if (devm_request_irq(dev, irq[0], em_gio_irq_handler, 0, name, p)) { dev_err(dev, "failed to request low IRQ\n"); return -ENOENT; } - if (devm_request_irq(dev, irq[1]->start, - em_gio_irq_handler, 0, name, p)) { + if (devm_request_irq(dev, irq[1], em_gio_irq_handler, 0, name, p)) { dev_err(dev, "failed to request high IRQ\n"); return -ENOENT; } -- cgit v1.2.3 From 0f67f16a6e88749fc3bf88da7515d3fff472a1cc Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 13 Nov 2019 10:43:52 +0200 Subject: gpio: mmio: remove untrue leftover comment The comment should have been removed when new GPIO direction definitions were taken in use as the function logic was changed. It is now perfectly valid and Ok to hit the return from the bottom of the direction getting function. Signed-off-by: Matti Vaittinen Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mmio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index cd07c948649f..f729e3e9e983 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -386,7 +386,6 @@ static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) if (!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio))) return GPIO_LINE_DIRECTION_OUT; - /* This should not happen */ return GPIO_LINE_DIRECTION_IN; } -- cgit v1.2.3