From 7808755d4b0ccdaa9e78edfc8cce94f51c5c8da4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 22 Nov 2013 10:11:49 +0100 Subject: gpio: pl061: proper error messages This makes the PL061 driver print proper error messages when probe fails, and also tell us when the chip is finally registered. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b4d4211..eba66c7 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -270,21 +270,27 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) if (pdata) { chip->gc.base = pdata->gpio_base; irq_base = pdata->irq_base; - if (irq_base <= 0) + if (irq_base <= 0) { + dev_err(&adev->dev, "invalid IRQ base in pdata\n"); return -ENODEV; + } } else { chip->gc.base = -1; irq_base = 0; } if (!devm_request_mem_region(dev, adev->res.start, - resource_size(&adev->res), "pl061")) + resource_size(&adev->res), "pl061")) { + dev_err(&adev->dev, "no memory region\n"); return -EBUSY; + } chip->base = devm_ioremap(dev, adev->res.start, resource_size(&adev->res)); - if (!chip->base) + if (!chip->base) { + dev_err(&adev->dev, "could not remap memory\n"); return -ENOMEM; + } spin_lock_init(&chip->lock); @@ -309,16 +315,20 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) */ writeb(0, chip->base + GPIOIE); /* disable irqs */ irq = adev->irq[0]; - if (irq < 0) + if (irq < 0) { + dev_err(&adev->dev, "invalid IRQ\n"); return -ENODEV; + } irq_set_chained_handler(irq, pl061_irq_handler); irq_set_handler_data(irq, chip); chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR, irq_base, &pl061_domain_ops, chip); - if (!chip->domain) + if (!chip->domain) { + dev_err(&adev->dev, "no irq domain\n"); return -ENODEV; + } for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { @@ -331,6 +341,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) } amba_set_drvdata(adev, chip); + dev_info(&adev->dev, "PL061 GPIO chip @%08x registered\n", + adev->res.start); return 0; } -- cgit v1.1 From f6f293112e3d747e5d39ff0d12793909c3946035 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 26 Nov 2013 12:33:41 +0100 Subject: gpio: pl061: lock IRQs when starting them This uses the new API for tagging GPIO lines as in use by IRQs. This enforces a few semantic checks on how the underlying GPIO line is used. Cc: Haojian Zhuang Cc: Deepak Sikri Acked-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index eba66c7..93b51e3 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -231,11 +231,33 @@ static void pl061_irq_unmask(struct irq_data *d) spin_unlock(&chip->lock); } +static unsigned int pl061_irq_startup(struct irq_data *d) +{ + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&chip->gc, irqd_to_hwirq(d))) + dev_err(chip->gc.dev, + "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + pl061_irq_unmask(d); + return 0; +} + +static void pl061_irq_shutdown(struct irq_data *d) +{ + struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + + pl061_irq_mask(d); + gpio_unlock_as_irq(&chip->gc, irqd_to_hwirq(d)); +} + static struct irq_chip pl061_irqchip = { .name = "pl061 gpio", .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, + .irq_startup = pl061_irq_startup, + .irq_shutdown = pl061_irq_shutdown, }; static int pl061_irq_map(struct irq_domain *d, unsigned int irq, -- cgit v1.1 From 438a2c9a743b54f3e79b5e54dd4d0590da304017 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 26 Nov 2013 12:59:51 +0100 Subject: gpio: pl061: refactor type setting Refactor this function so that I can understand it, do one big read/modify/write operation and have the bitmask in a variable instead of recalculating it every time it's needed. Cc: Haojian Zhuang Cc: Deepak Sikri Acked-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 93b51e3..a934881 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -150,6 +150,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) int offset = irqd_to_hwirq(d); unsigned long flags; u8 gpiois, gpioibe, gpioiev; + u8 bit = BIT(offset); if (offset < 0 || offset >= PL061_GPIO_NR) return -EINVAL; @@ -157,30 +158,31 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) spin_lock_irqsave(&chip->lock, flags); gpioiev = readb(chip->base + GPIOIEV); - gpiois = readb(chip->base + GPIOIS); + gpioibe = readb(chip->base + GPIOIBE); + if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { - gpiois |= 1 << offset; + gpiois |= bit; if (trigger & IRQ_TYPE_LEVEL_HIGH) - gpioiev |= 1 << offset; + gpioiev |= bit; else - gpioiev &= ~(1 << offset); + gpioiev &= ~bit; } else - gpiois &= ~(1 << offset); - writeb(gpiois, chip->base + GPIOIS); + gpiois &= ~bit; - gpioibe = readb(chip->base + GPIOIBE); if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) - gpioibe |= 1 << offset; + /* Setting this makes GPIOEV be ignored */ + gpioibe |= bit; else { - gpioibe &= ~(1 << offset); + gpioibe &= ~bit; if (trigger & IRQ_TYPE_EDGE_RISING) - gpioiev |= 1 << offset; + gpioiev |= bit; else if (trigger & IRQ_TYPE_EDGE_FALLING) - gpioiev &= ~(1 << offset); + gpioiev &= ~bit; } - writeb(gpioibe, chip->base + GPIOIBE); + writeb(gpiois, chip->base + GPIOIS); + writeb(gpioibe, chip->base + GPIOIBE); writeb(gpioiev, chip->base + GPIOIEV); spin_unlock_irqrestore(&chip->lock, flags); -- cgit v1.1 From 9ae7e9e38acfae8d651fbe73844ca837d03499ee Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 26 Nov 2013 14:19:44 +0100 Subject: gpio: pl061: remove confusing naming Drop the " gpio" suffix after the pl061 irq_chip name: this is only confusing: an irqchip name should be a single, short, simple string that looks nice in /proc/interrupts. Drop the nameing of each individual IRQ to "pl061" - I think this naming function is for naming the IRQ line, not for boilerplating them all with the name of the parent controller, which is already known from the .name field of the irq_chip. Cc: Haojian Zhuang Cc: Deepak Sikri Acked-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index a934881..062a1be 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -254,7 +254,7 @@ static void pl061_irq_shutdown(struct irq_data *d) } static struct irq_chip pl061_irqchip = { - .name = "pl061 gpio", + .name = "pl061", .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, @@ -267,8 +267,7 @@ static int pl061_irq_map(struct irq_domain *d, unsigned int irq, { struct pl061_gpio *chip = d->host_data; - irq_set_chip_and_handler_name(irq, &pl061_irqchip, handle_simple_irq, - "pl061"); + irq_set_chip_and_handler(irq, &pl061_irqchip, handle_simple_irq); irq_set_chip_data(irq, chip); irq_set_irq_type(irq, IRQ_TYPE_NONE); -- cgit v1.1 From a0bbf03270fde9d96a9f814512e77a693648e159 Mon Sep 17 00:00:00 2001 From: David Cohen Date: Fri, 17 Jan 2014 07:30:01 -0800 Subject: gpio: intel-mid: comments cleanup This is a simple cleanup on gpio-intel-mid.c's header comments. Signed-off-by: David Cohen Signed-off-by: Linus Walleij --- drivers/gpio/gpio-intel-mid.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index d1b50ef..62860d7 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -1,7 +1,7 @@ /* - * Moorestown platform Langwell chip GPIO driver + * Intel MID GPIO driver * - * Copyright (c) 2008, 2009, 2013, Intel Corporation. + * Copyright (c) 2008-2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Supports: -- cgit v1.1 From d762bae45a3dd65d02a35b4252598912f7fbcde0 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 21 Jan 2014 16:10:04 -0800 Subject: gpio: bcm281xx: Fix parameter name for GPIO_CONTROL macro The GPIO_CONTROL macro returns the control register offset when given a GPIO number. Update the argument name in the macro to reflect that it takes in a GPIO number and not a bank. Signed-off-by: Markus Mayer Reviewed-by: Tim Kryger Signed-off-by: Linus Walleij --- drivers/gpio/gpio-bcm-kona.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 233d088..93a5b01 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -28,6 +28,10 @@ #define GPIO_BANK(gpio) ((gpio) >> 5) #define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1)) +/* There is a GPIO control register for each GPIO */ +#define GPIO_CONTROL(gpio) (0x00000100 + ((gpio) << 2)) + +/* The remaining registers are per GPIO bank */ #define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2)) #define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2)) #define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2)) @@ -35,7 +39,6 @@ #define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2)) #define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2)) #define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2)) -#define GPIO_CONTROL(bank) (0x00000100 + ((bank) << 2)) #define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2)) #define GPIO_GPPWR_OFFSET 0x00000520 -- cgit v1.1 From bdb93c03c5503aba9a6d98d49e543d879d85d0c4 Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Tue, 21 Jan 2014 16:10:41 -0800 Subject: gpio: bcm281xx: Centralize register locking Rather than unlock/re-lock for every write access, unlock a GPIO when it is requested and re-lock it when it is freed. As a result, the GPIO helper functions no longer have to deal with unlocking and re-locking the register. In addition, only unlock a specific GPIO rather than unlocking the entire GPIO bank as before. Signed-off-by: Markus Mayer Reviewed-by: Tim Kryger Signed-off-by: Linus Walleij --- drivers/gpio/gpio-bcm-kona.c | 82 ++++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 93a5b01..e5aa4d0 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -83,22 +83,43 @@ static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip) return container_of(chip, struct bcm_kona_gpio, gpio_chip); } -static void bcm_kona_gpio_set_lockcode_bank(void __iomem *reg_base, - int bank_id, int lockcode) +static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base, + int bank_id, u32 lockcode) { writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET); writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id)); } -static inline void bcm_kona_gpio_lock_bank(void __iomem *reg_base, int bank_id) +static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio, + unsigned gpio) { - bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, LOCK_CODE); + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + spin_lock_irqsave(&kona_gpio->lock, flags); + + val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id)); + val |= BIT(gpio); + bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val); + + spin_unlock_irqrestore(&kona_gpio->lock, flags); } -static inline void bcm_kona_gpio_unlock_bank(void __iomem *reg_base, - int bank_id) +static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio, + unsigned gpio) { - bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, UNLOCK_CODE); + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + spin_lock_irqsave(&kona_gpio->lock, flags); + + val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id)); + val &= ~BIT(gpio); + bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val); + + spin_unlock_irqrestore(&kona_gpio->lock, flags); } static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) @@ -113,7 +134,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); /* determine the GPIO pin direction */ val = readl(reg_base + GPIO_CONTROL(gpio)); @@ -130,7 +150,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) writel(val, reg_base + reg_offset); out: - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -146,7 +165,6 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); /* determine the GPIO pin direction */ val = readl(reg_base + GPIO_CONTROL(gpio)); @@ -157,32 +175,43 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id); val = readl(reg_base + reg_offset); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); /* return the specified bit status */ return !!(val & BIT(bit)); } +static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip); + + bcm_kona_gpio_unlock_gpio(kona_gpio, gpio); + return 0; +} + +static void bcm_kona_gpio_free(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip); + + bcm_kona_gpio_lock_gpio(kona_gpio, gpio); +} + static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; u32 val; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_IOTR_MASK; val |= GPIO_GPCTR0_IOTR_CMD_INPUT; writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -201,7 +230,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_IOTR_MASK; @@ -213,7 +241,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, val |= BIT(bit); writel(val, reg_base + reg_offset); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -236,7 +263,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, void __iomem *reg_base; u32 val, res; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; @@ -260,7 +286,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, /* spin lock for read-modify-write of the GPIO register */ spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_DBR_MASK; @@ -275,7 +300,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -284,6 +308,8 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, static struct gpio_chip template_chip = { .label = "bcm-kona-gpio", .owner = THIS_MODULE, + .request = bcm_kona_gpio_request, + .free = bcm_kona_gpio_free, .direction_input = bcm_kona_gpio_direction_input, .get = bcm_kona_gpio_get, .direction_output = bcm_kona_gpio_direction_output, @@ -306,13 +332,11 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_STATUS(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_STATUS(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -329,13 +353,11 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_MASK(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MASK(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -352,13 +374,11 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_MSKCLR(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MSKCLR(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -370,7 +390,6 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) u32 lvl_type; u32 val; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; @@ -397,14 +416,12 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) } spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_ITR_MASK; val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT; writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -427,7 +444,6 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) */ reg_base = bank->kona_gpio->reg_base; bank_id = bank->id; - bcm_kona_gpio_unlock_bank(reg_base, bank_id); while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) & (~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) { @@ -447,8 +463,6 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } } - bcm_kona_gpio_lock_bank(reg_base, bank_id); - chained_irq_exit(chip, desc); } @@ -534,10 +548,12 @@ static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio) reg_base = kona_gpio->reg_base; /* disable interrupts and clear status */ for (i = 0; i < kona_gpio->num_bank; i++) { - bcm_kona_gpio_unlock_bank(reg_base, i); + /* Unlock the entire bank first */ + bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE); writel(0xffffffff, reg_base + GPIO_INT_MASK(i)); writel(0xffffffff, reg_base + GPIO_INT_STATUS(i)); - bcm_kona_gpio_lock_bank(reg_base, i); + /* Now re-lock the bank */ + bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE); } } -- cgit v1.1 From bea4dbee952ac7a03885646de3247685dabad972 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 27 Jan 2014 12:15:08 +0530 Subject: gpio: gpiolib-of: Use PTR_ERR_OR_ZERO PTR_RET is deprecated. Use PTR_ERR_OR_ZERO instead. While at it also include missing err.h header. Signed-off-by: Sachin Kamat Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index e0a98f5..2024d45 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -90,7 +91,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, of_node_put(gg_data.gpiospec.np); pr_debug("%s exited with status %d\n", __func__, - PTR_RET(gg_data.out_gpio)); + PTR_ERR_OR_ZERO(gg_data.out_gpio)); return gg_data.out_gpio; } EXPORT_SYMBOL(of_get_named_gpiod_flags); -- cgit v1.1 From b7ab697369716ecf7c5b71114bdd22445f9a7a5e Mon Sep 17 00:00:00 2001 From: Markus Mayer Date: Mon, 27 Jan 2014 17:32:18 -0800 Subject: gpio: bcm281xx: Use "unsigned gpio" consistently throughout the code This patch removes some inconsistencies caused by the use of "int gpio" in some parts of the code and "unsigned gpio" in others. Signed-off-by: Markus Mayer Reviewed-by: Tim Kryger Signed-off-by: Linus Walleij --- drivers/gpio/gpio-bcm-kona.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index e5aa4d0..b4f20f7 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -323,7 +323,7 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -344,7 +344,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -365,7 +365,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -386,7 +386,7 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; u32 lvl_type; u32 val; unsigned long flags; -- cgit v1.1 From 781f6d710d4482eab05cfaad50060a0ea8c0e4e0 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Thu, 30 Jan 2014 13:18:57 +0000 Subject: gpio: generic: Add label to platform data When registering more than one platform device, it is useful to set the gpio chip label in the platform data. Signed-off-by: Pawel Moll Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index d2196bf..8c778af 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -531,6 +531,8 @@ static int bgpio_pdev_probe(struct platform_device *pdev) return err; if (pdata) { + if (pdata->label) + bgc->gc.label = pdata->label; bgc->gc.base = pdata->base; if (pdata->ngpio > 0) bgc->gc.ngpio = pdata->ngpio; -- cgit v1.1 From a5d6d271b388330a21ff75bca928fefb8489a6f5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 4 Feb 2014 20:39:01 +0800 Subject: gpio: pl061: Select IRQ_DOMAIN rather than GENERIC_IRQ_CHIP commit f1f70479e999 "gpio: pl061: support irqdomain" drops the support of irq generic chip and use irqdomain instead. Thus fixes the dependency by selecting IRQ_DOMAIN rather than GENERIC_IRQ_CHIP. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6973387..2ca735f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -228,7 +228,7 @@ config GPIO_OCTEON config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA - select GENERIC_IRQ_CHIP + select IRQ_DOMAIN help Say yes here to support the PrimeCell PL061 GPIO device -- cgit v1.1 From f86b7c70bc03236188c9a865aacd57b8d1ddb08c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 4 Feb 2014 22:25:27 +0800 Subject: gpio: clps711x: Add missing .owner to struct gpio_chip Add missing .owner of struct gpio_chip. This prevents the module from being removed from underneath its users. Signed-off-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/gpio/gpio-clps711x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index d355027..20a7839 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -65,6 +65,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev) } bgc->gc.base = id * 8; + bgc->gc.owner = THIS_MODULE; platform_set_drvdata(pdev, bgc); return gpiochip_add(&bgc->gc); -- cgit v1.1 From 25b35da7f4cce82271859f1b6eabd9f3bd41a2bb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 5 Feb 2014 14:08:02 +0100 Subject: gpio: generic: clamp retured value to [0,1] The generic GPIO would return 0 for low generic GPIO, and something != 0 for high GPIO. Let's make this sane by clamping the returned value to [0,1]. Reported-by: Evgeny Boger Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 8c778af..d815dd2 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -139,7 +139,7 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct bgpio_chip *bgc = to_bgpio_chip(gc); - return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio); + return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); } static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) -- cgit v1.1 From ef70bbe1aaa612f75360e5df5952fddec50b7ca9 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 7 Jan 2014 12:34:11 +0100 Subject: gpio: make gpiod_direction_output take a logical value The documentation was not clear about whether gpio_direction_output should take a logical value or the physical level on the output line, i.e. whether the ACTIVE_LOW status would be taken into account. This converts gpiod_direction_output to use the logical level and adds a new gpiod_direction_output_raw for the raw value. Signed-off-by: Philipp Zabel Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 67 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 50c4922..80da9f1 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -350,9 +350,9 @@ static ssize_t gpio_direction_store(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else if (sysfs_streq(buf, "high")) - status = gpiod_direction_output(desc, 1); + status = gpiod_direction_output_raw(desc, 1); else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) - status = gpiod_direction_output(desc, 0); + status = gpiod_direction_output_raw(desc, 0); else if (sysfs_streq(buf, "in")) status = gpiod_direction_input(desc); else @@ -1590,7 +1590,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (flags & GPIOF_DIR_IN) err = gpiod_direction_input(desc); else - err = gpiod_direction_output(desc, + err = gpiod_direction_output_raw(desc, (flags & GPIOF_INIT_HIGH) ? 1 : 0); if (err) @@ -1756,28 +1756,13 @@ fail: } EXPORT_SYMBOL_GPL(gpiod_direction_input); -/** - * gpiod_direction_output - set the GPIO direction to input - * @desc: GPIO to set to output - * @value: initial output value of the GPIO - * - * Set the direction of the passed GPIO to output, such as gpiod_set_value() can - * be called safely on it. The initial value of the output must be specified. - * - * Return 0 in case of success, else an error code. - */ -int gpiod_direction_output(struct gpio_desc *desc, int value) +static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; int offset; - if (!desc || !desc->chip) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - /* GPIOs used for IRQs shall not be set as output */ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { gpiod_err(desc, @@ -1840,6 +1825,50 @@ fail: gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } + +/** + * gpiod_direction_output_raw - set the GPIO direction to output + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as raw value on the physical line without regard for the ACTIVE_LOW status. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output_raw(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + return _gpiod_direction_output_raw(desc, value); +} +EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); + +/** + * gpiod_direction_output - set the GPIO direction to input + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into + * account. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + return _gpiod_direction_output_raw(desc, value); +} EXPORT_SYMBOL_GPL(gpiod_direction_output); /** -- cgit v1.1 From e54674f898c4d3ad88b7ec604cf5e59e4170c4f5 Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Fri, 7 Feb 2014 14:21:04 +0100 Subject: gpio: ich: Add blink capability option This patch allows gpio_ich driver to be aware of non blink capable chipsets. Signed-off-by: Vincent Donnefort Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ich.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index f5bf3c3..82887c5 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -62,6 +62,9 @@ struct ichx_desc { /* Max GPIO pins the chipset can have */ uint ngpio; + /* GPO_BLINK is available on this chipset */ + bool have_blink; + /* Whether the chipset has GPIO in GPE0_STS in the PM IO region */ bool uses_gpe0; @@ -151,7 +154,7 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, int val) { /* Disable blink hardware which is available for GPIOs from 0 to 31. */ - if (nr < 32) + if (nr < 32 && ichx_priv.desc->have_blink) ichx_write_bit(GPO_BLINK, nr, 0, 0); /* Set GPIO output value. */ @@ -266,6 +269,7 @@ static struct ichx_desc ich6_desc = { .uses_gpe0 = true, .ngpio = 50, + .have_blink = true, }; /* Intel 3100 */ @@ -290,19 +294,23 @@ static struct ichx_desc i3100_desc = { /* ICH7 and ICH8-based */ static struct ichx_desc ich7_desc = { .ngpio = 50, + .have_blink = true, }; /* ICH9-based */ static struct ichx_desc ich9_desc = { .ngpio = 61, + .have_blink = true, }; /* ICH10-based - Consumer/corporate versions have different amount of GPIO */ static struct ichx_desc ich10_cons_desc = { .ngpio = 61, + .have_blink = true, }; static struct ichx_desc ich10_corp_desc = { .ngpio = 72, + .have_blink = true, }; /* Intel 5 series, 6 series, 3400 series, and C200 series */ -- cgit v1.1 From b667cf488aa9476b0ab64acd91f2a96f188cfd21 Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Fri, 7 Feb 2014 14:21:05 +0100 Subject: gpio: ich: Add support for multiple register addresses This patch introduces regs and reglen pointers which allow a chipset to have register addresses differing from ICH ones. Signed-off-by: Vincent Donnefort Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ich.c | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 82887c5..f3eb1c5 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -62,6 +62,10 @@ struct ichx_desc { /* Max GPIO pins the chipset can have */ uint ngpio; + /* chipset registers */ + const u8 (*regs)[3]; + const u8 *reglen; + /* GPO_BLINK is available on this chipset */ bool have_blink; @@ -102,13 +106,16 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify) spin_lock_irqsave(&ichx_priv.lock, flags); - data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base); + data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); if (val) data |= 1 << bit; else data &= ~(1 << bit); - ICHX_WRITE(data, ichx_regs[reg][reg_nr], ichx_priv.gpio_base); - tmp = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base); + ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); if (verify && data != tmp) ret = -EPERM; @@ -126,7 +133,8 @@ static int ichx_read_bit(int reg, unsigned nr) spin_lock_irqsave(&ichx_priv.lock, flags); - data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base); + data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); spin_unlock_irqrestore(&ichx_priv.lock, flags); @@ -295,27 +303,37 @@ static struct ichx_desc i3100_desc = { static struct ichx_desc ich7_desc = { .ngpio = 50, .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* ICH9-based */ static struct ichx_desc ich9_desc = { .ngpio = 61, .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* ICH10-based - Consumer/corporate versions have different amount of GPIO */ static struct ichx_desc ich10_cons_desc = { .ngpio = 61, .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; static struct ichx_desc ich10_corp_desc = { .ngpio = 72, .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* Intel 5 series, 6 series, 3400 series, and C200 series */ static struct ichx_desc intel5_desc = { .ngpio = 76, + .regs = ichx_regs, + .reglen = ichx_reglen, }; static int ichx_gpio_request_regions(struct resource *res_base, @@ -326,11 +344,12 @@ static int ichx_gpio_request_regions(struct resource *res_base, if (!res_base || !res_base->start || !res_base->end) return -ENODEV; - for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { if (!(use_gpio & (1 << i))) continue; - if (!request_region(res_base->start + ichx_regs[0][i], - ichx_reglen[i], name)) + if (!request_region( + res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i], name)) goto request_err; } return 0; @@ -340,8 +359,8 @@ request_err: for (i--; i >= 0; i--) { if (!(use_gpio & (1 << i))) continue; - release_region(res_base->start + ichx_regs[0][i], - ichx_reglen[i]); + release_region(res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i]); } return -EBUSY; } @@ -350,11 +369,11 @@ static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio) { int i; - for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { if (!(use_gpio & (1 << i))) continue; - release_region(res_base->start + ichx_regs[0][i], - ichx_reglen[i]); + release_region(res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i]); } } -- cgit v1.1 From ff2ed0491d9f6e8b1a0fa205324030588f9e4037 Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Fri, 7 Feb 2014 14:21:06 +0100 Subject: gpio: ich: Add output levels cache support This patch allows GPIO driver to cache GPIO_LVL output registers. The aim is to support chipsets on which GPIO_LVL value can't be read for output pins. Caching output levels implies the first output values reading as 0. The driver so can't be aware of set values GPIOs by bootloader or BIOS. Signed-off-by: Vincent Donnefort Signed-off-by: Linus Walleij --- drivers/gpio/gpio-ich.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index f3eb1c5..bfef20f 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -78,6 +78,12 @@ struct ichx_desc { /* Some chipsets have quirks, let these use their own request/get */ int (*request)(struct gpio_chip *chip, unsigned offset); int (*get)(struct gpio_chip *chip, unsigned offset); + + /* + * Some chipsets don't let reading output values on GPIO_LVL register + * this option allows driver caching written output values + */ + bool use_outlvl_cache; }; static struct { @@ -89,6 +95,7 @@ static struct { struct ichx_desc *desc; /* Pointer to chipset-specific description */ u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ u8 use_gpio; /* Which GPIO groups are usable */ + int outlvl_cache[3]; /* cached output values */ } ichx_priv; static int modparam_gpiobase = -1; /* dynamic */ @@ -106,14 +113,21 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify) spin_lock_irqsave(&ichx_priv.lock, flags); - data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], - ichx_priv.gpio_base); + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + data = ichx_priv.outlvl_cache[reg_nr]; + else + data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + if (val) data |= 1 << bit; else data &= ~(1 << bit); ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr], ichx_priv.gpio_base); + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + ichx_priv.outlvl_cache[reg_nr] = data; + tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], ichx_priv.gpio_base); if (verify && data != tmp) @@ -136,6 +150,9 @@ static int ichx_read_bit(int reg, unsigned nr) data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], ichx_priv.gpio_base); + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + data = ichx_priv.outlvl_cache[reg_nr] | data; + spin_unlock_irqrestore(&ichx_priv.lock, flags); return data & (1 << bit) ? 1 : 0; -- cgit v1.1 From 01ca59f1bb1e71f1f40d0cfbec6b467df144924d Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 7 Feb 2014 12:29:19 +0100 Subject: gpio: mvebu: use chained_irq_{enter,exit} for GIC compatibility On currently supported SoCs, the GPIO block used on Marvell EBU SoCs is always connected to the Marvell MPIC. However, we are going to introduce the support for newer Marvell EBU SoCs that use the Cortex-A9 core, and therefore use the GIC as their main interrupt controller, to which the GPIO block controlled by the gpio-mvebu driver is connected. The GIC interrupt controller driver uses the fasteoi flow handler. In order to ensure that the eoi hook of the GIC driver gets called, the GPIO driver should call chained_irq_enter() and chained_irq_exit() in its handler. Without this, the first GPIO interrupt locks up the system because it doesn't get acked at the GIC level. This change is similar to for example commit 0d978eb7349941139241a99acf05de6dd49b78d1 ("gpio: davinci: use chained_irq_enter/chained_irq_exit API"). Signed-off-by: Thomas Petazzoni Acked-by: Jason Cooper Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 3b1fd1c..d425094 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -44,6 +44,7 @@ #include #include #include +#include /* * GPIO unit register offsets. @@ -438,12 +439,15 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); u32 cause, type; int i; if (mvchip == NULL) return; + chained_irq_enter(chip, desc); + cause = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) & readl_relaxed(mvebu_gpioreg_level_mask(mvchip)); cause |= readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)) & @@ -466,8 +470,11 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) polarity ^= 1 << i; writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip)); } + generic_handle_irq(irq); } + + chained_irq_exit(chip, desc); } #ifdef CONFIG_DEBUG_FS -- cgit v1.1 From 90df4fe07f9794984bd2dafd1d28acd45318d37f Mon Sep 17 00:00:00 2001 From: Rahul Bedarkar Date: Sat, 8 Feb 2014 11:55:25 +0530 Subject: GPIO: gpiolib: correct description of gpiod_direction_output Signed-off-by: Rahul Bedarkar Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 80da9f1..9b241bc 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1848,7 +1848,7 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value) EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); /** - * gpiod_direction_output - set the GPIO direction to input + * gpiod_direction_output - set the GPIO direction to output * @desc: GPIO to set to output * @value: initial output value of the GPIO * -- cgit v1.1 From bb1e88ccb771492ac908ac295ec135efa1d53093 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 9 Feb 2014 17:43:54 +0900 Subject: gpiolib: add gpiochip_get_desc() driver function Some drivers dealing with a gpio_chip might need to act on its descriptors directly; one example is pinctrl drivers that need to lock a GPIO for being used as IRQ using gpiod_lock_as_irq(). This patch exports a gpiochip_get_desc() function that returns the GPIO descriptor at the requested index. It also sweeps the gpio_to_chip() function out of the consumer interface since any holder of a gpio_chip reference can manipulate its GPIOs way beyond what a consumer should be allowed to do. As a result, gpio_chip is not visible anymore to simple GPIO consumers. Signed-off-by: Alexandre Courbot Reviewed-by: Mika Westerberg Reviewed-by: Jean-Jacques Hiblot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9b241bc..9cd7082 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -164,16 +164,17 @@ struct gpio_desc *gpio_to_desc(unsigned gpio) EXPORT_SYMBOL_GPL(gpio_to_desc); /** - * Convert an offset on a certain chip to a corresponding descriptor + * Get the GPIO descriptor corresponding to the given hw number for this chip. */ -static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip, - unsigned int offset) +struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, + u16 hwnum) { - if (offset >= chip->ngpio) + if (hwnum >= chip->ngpio) return ERR_PTR(-EINVAL); - return &chip->desc[offset]; + return &chip->desc[hwnum]; } +EXPORT_SYMBOL_GPL(gpiochip_get_desc); /** * Convert a GPIO descriptor to the integer namespace. @@ -2190,7 +2191,7 @@ EXPORT_SYMBOL_GPL(gpiod_lock_as_irq); int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) { - return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset)); + return gpiod_lock_as_irq(gpiochip_get_desc(chip, offset)); } EXPORT_SYMBOL_GPL(gpio_lock_as_irq); @@ -2212,7 +2213,7 @@ EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq); void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) { - return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset)); + return gpiod_unlock_as_irq(gpiochip_get_desc(chip, offset)); } EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); @@ -2433,7 +2434,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return ERR_PTR(-EINVAL); } - desc = gpiochip_offset_to_desc(chip, p->chip_hwnum); + desc = gpiochip_get_desc(chip, p->chip_hwnum); *flags = p->flags; return desc; -- cgit v1.1 From 390d82e312c56b75407a3606cbcde8c4bc7f10ae Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Sun, 9 Feb 2014 17:43:55 +0900 Subject: gpiolib: ACPI: remove gpio_to_desc() usage gpio_to_desc() must die. Replace one of its usage by the newly-introduced gpiochip_get_desc() function. Signed-off-by: Alexandre Courbot Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 716ee98..b7db098 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -60,7 +60,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) if (pin < 0 || pin > chip->ngpio) return ERR_PTR(-EINVAL); - return gpio_to_desc(chip->base + pin); + return gpiochip_get_desc(chip, pin); } static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) -- cgit v1.1 From 992196f28c3c0a589a3d461aab83b7af2eb7b3cf Mon Sep 17 00:00:00 2001 From: Jean-Francois Dagenais Date: Mon, 10 Feb 2014 12:05:28 -0500 Subject: gpio: adp5588: get value from data out when dir is out As discussed here: http://ez.analog.com/message/35852, the 5587 revC and 5588 revB spec sheets contain a mistake in the GPIO_DAT_STATx register description. According to R.Shnell at ADI, as well as my own observations, it should read: "GPIO data status (shows GPIO state when read for inputs)". This commit changes the get value function accordingly. Signed-off-by: Jean-Francois Dagenais Acked-by: Michael Hennerich Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adp5588.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 3f190e6..7d3c8d9 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -67,9 +67,20 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off) { struct adp5588_gpio *dev = container_of(chip, struct adp5588_gpio, gpio_chip); + unsigned bank = ADP5588_BANK(off); + unsigned bit = ADP5588_BIT(off); + int val; - return !!(adp5588_gpio_read(dev->client, - GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off)); + mutex_lock(&dev->lock); + + if (dev->dir[bank] & bit) + val = dev->dat_out[bank]; + else + val = adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + bank); + + mutex_unlock(&dev->lock); + + return !!(val & bit); } static void adp5588_gpio_set_value(struct gpio_chip *chip, -- cgit v1.1 From 1163316e52e3cbcca29547a948fee72056708b62 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dagenais Date: Mon, 10 Feb 2014 12:24:05 -0500 Subject: gpio: adp5588 - add support for gpio names which is already found in the common header for adp5588 Signed-off-by: Jean-Francois Dagenais Acked-by: Michael Hennerich Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adp5588.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 7d3c8d9..d974020 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -397,6 +397,7 @@ static int adp5588_gpio_probe(struct i2c_client *client, gc->ngpio = ADP5588_MAXGPIO; gc->label = client->name; gc->owner = THIS_MODULE; + gc->names = pdata->names; mutex_init(&dev->lock); -- cgit v1.1 From 1e1916950b00838226295e2600496040276a949f Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Fri, 7 Feb 2014 16:35:48 -0600 Subject: gpio: pca953x: Add devices to Kconfig help The pca953x driver supports tca6424 (24-bit) and pca9505 (40-bit) devices. They were the only supported devices not mentioned in the Kconfig help. Signed-off-by: Aaron Sierra Acked-by: Graeme Smecher Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 4 ++++ drivers/gpio/gpio-pca953x.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2ca735f..69d1a90 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -476,6 +476,10 @@ config GPIO_PCA953X 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575, tca6416 + 24 bits: tca6424 + + 40 bits: pca9505 + config GPIO_PCA953X_IRQ bool "Interrupt controller support for PCA953x" depends on GPIO_PCA953X=y diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 019b23b..cede6f6 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -1,5 +1,5 @@ /* - * PCA953x 4/8/16 bit I/O ports + * PCA953x 4/8/16/24/40 bit I/O ports * * Copyright (C) 2005 Ben Gardner * Copyright (C) 2007 Marvell International Ltd. -- cgit v1.1 From eb32b5aae92176e7a00411082955dab8c62761ee Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Thu, 13 Feb 2014 13:59:23 +0100 Subject: gpio: pca953x: Add NXP PCA9698 Add the NXP PCA9698 40-bit GPIO expander to the supported list. Note: This only enables GPIO functionality. Tested-by: Bob Schmitz Signed-off-by: Aaron Sierra Acked-by: Graeme Smecher Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 4 ++-- drivers/gpio/gpio-pca953x.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 69d1a90..9f71927 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -461,7 +461,7 @@ config GPIO_MC9S08DZ60 Select this to enable the MC9S08DZ60 GPIO driver config GPIO_PCA953X - tristate "PCA953x, PCA955x, PCA957x, TCA64xx, and MAX7310 I/O ports" + tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports" depends on I2C help Say yes here to provide access to several register-oriented @@ -478,7 +478,7 @@ config GPIO_PCA953X 24 bits: tca6424 - 40 bits: pca9505 + 40 bits: pca9505, pca9698 config GPIO_PCA953X_IRQ bool "Interrupt controller support for PCA953x" diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index cede6f6..dbc95bc 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -59,6 +59,7 @@ static const struct i2c_device_id pca953x_id[] = { { "pca9557", 8 | PCA953X_TYPE, }, { "pca9574", 8 | PCA957X_TYPE | PCA_INT, }, { "pca9575", 16 | PCA957X_TYPE | PCA_INT, }, + { "pca9698", 40 | PCA953X_TYPE, }, { "max7310", 8 | PCA953X_TYPE, }, { "max7312", 16 | PCA953X_TYPE | PCA_INT, }, @@ -812,6 +813,7 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "nxp,pca9557", }, { .compatible = "nxp,pca9574", }, { .compatible = "nxp,pca9575", }, + { .compatible = "nxp,pca9698", }, { .compatible = "maxim,max7310", }, { .compatible = "maxim,max7312", }, -- cgit v1.1 From e73760a60582b667cfe6d2ba70b74d5297419c42 Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Fri, 7 Feb 2014 16:36:21 -0600 Subject: gpio: pca953x: Add Exar XRA1202 Add Exar XRA1202 8-bit GPIO expander to supported list. Signed-off-by: Aaron Sierra Acked-by: Graeme Smecher Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-pca953x.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9f71927..87bfcaf 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -471,7 +471,7 @@ config GPIO_PCA953X 4 bits: pca9536, pca9537 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554, - pca9556, pca9557, pca9574, tca6408 + pca9556, pca9557, pca9574, tca6408, xra1202 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575, tca6416 diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index dbc95bc..948a074 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -69,6 +69,7 @@ static const struct i2c_device_id pca953x_id[] = { { "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, { "tca6424", 24 | PCA953X_TYPE | PCA_INT, }, + { "xra1202", 8 | PCA953X_TYPE }, { } }; MODULE_DEVICE_TABLE(i2c, pca953x_id); @@ -824,6 +825,8 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "ti,tca6408", }, { .compatible = "ti,tca6416", }, { .compatible = "ti,tca6424", }, + + { .compatible = "exar,xra1202", }, { } }; -- cgit v1.1 From 2b1f597f7f40f8f289489eaa1a973254afc2a632 Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Fri, 7 Feb 2014 19:23:04 -0600 Subject: gpio: pca953x: Fix gpio_base may not default to -1 If no device tree node existed for a device when CONFIG_OF_GPIO was defined, then gpio_base would not default to -1. Signed-off-by: Aaron Sierra Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pca953x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 948a074..d550d8e 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -627,11 +627,12 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) const __be32 *val; int size; + *gpio_base = -1; + node = client->dev.of_node; if (node == NULL) return; - *gpio_base = -1; val = of_get_property(node, "linux,gpio-base", &size); WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__); if (val) { -- cgit v1.1 From 09bafc30b6fea0b374ac4ff0b8e923c07f5cda78 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 12 Feb 2014 11:53:58 +0900 Subject: gpio: pl061: Use devm_ioremap_resource() Use devm_ioremap_resource() in order to make the code simpler. Signed-off-by: Jingoo Han Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 062a1be..e528cb2 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -302,18 +302,9 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) irq_base = 0; } - if (!devm_request_mem_region(dev, adev->res.start, - resource_size(&adev->res), "pl061")) { - dev_err(&adev->dev, "no memory region\n"); - return -EBUSY; - } - - chip->base = devm_ioremap(dev, adev->res.start, - resource_size(&adev->res)); - if (!chip->base) { - dev_err(&adev->dev, "could not remap memory\n"); - return -ENOMEM; - } + chip->base = devm_ioremap_resource(dev, &adev->res); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); spin_lock_init(&chip->lock); -- cgit v1.1 From 717f70e39a98867751f6a3eb94cc281f3da32685 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 12 Feb 2014 11:51:38 +0900 Subject: gpio: omap: Use devm_ioremap_resource() Use devm_ioremap_resource() in order to make the code simpler, and remove redundant return value check of platform_get_resource() because the value is checked by devm_ioremap_resource(). Signed-off-by: Jingoo Han Reviewed-by: Alexandre Courbot Acked-by: Kevin Hilman Acked-by: Santosh Shilimkar Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 4243190..19b886c 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1214,24 +1214,10 @@ static int omap_gpio_probe(struct platform_device *pdev) /* Static mapping, never released */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!res)) { - dev_err(dev, "Invalid mem resource\n"); - irq_domain_remove(bank->domain); - return -ENODEV; - } - - if (!devm_request_mem_region(dev, res->start, resource_size(res), - pdev->name)) { - dev_err(dev, "Region already claimed\n"); + bank->base = devm_ioremap_resource(dev, res); + if (IS_ERR(bank->base)) { irq_domain_remove(bank->domain); - return -EBUSY; - } - - bank->base = devm_ioremap(dev, res->start, resource_size(res)); - if (!bank->base) { - dev_err(dev, "Could not ioremap\n"); - irq_domain_remove(bank->domain); - return -ENOMEM; + return PTR_ERR(bank->base); } platform_set_drvdata(pdev, bank); -- cgit v1.1 From 58c0f5aa124534af16d7faaf1abdfa0d9fec8290 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 15 Feb 2014 17:12:05 +0400 Subject: gpio: davinci: Use signed type for 'irq' variable Variable 'irq' is declared as unsigned and then used to store negative return values from irq_alloc_descs() such as -EINVAL. This patch fix this by declaring the variable as a signed. Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 7629b4f..29321ee 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -423,7 +423,8 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = { static int davinci_gpio_irq_setup(struct platform_device *pdev) { - unsigned gpio, irq, bank; + unsigned gpio, bank; + int irq; struct clk *clk; u32 binten = 0; unsigned ngpio, bank_irq; -- cgit v1.1 From 3bde4d26f9d7d9ebc87fbd9980d5140ba391b5d4 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 15 Feb 2014 17:24:07 +0400 Subject: gpio: rc5t583: Remove redundant check Variable "offset" cannot be negative, so no need to check if it greater than zero or equal. Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rc5t583.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index 122b776..9b42317 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -97,7 +97,7 @@ static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); - if ((offset >= 0) && (offset < 8)) + if (offset < RC5T583_MAX_GPIO) return rc5t583_gpio->rc5t583->irq_base + RC5T583_IRQ_GPIO0 + offset; return -EINVAL; -- cgit v1.1 From f29b9d13ddb32f84f33197042ca187c531cfda7a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 14 Feb 2014 11:32:14 +0100 Subject: gpio-ts5500: Add dependency There is no point in displaying the TS5500-specific driver entries if TS5500 board support itself isn't enabled. Signed-off-by: Jean Delvare Cc: Linus Walleij Cc: Vivien Didelot Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 87bfcaf..3bddd36 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -277,6 +277,7 @@ config GPIO_STA2X11 config GPIO_TS5500 tristate "TS-5500 DIO blocks and compatibles" + depends on TS5500 || COMPILE_TEST help This driver supports Digital I/O exposed by pin blocks found on some Technologic Systems platforms. It includes, but is not limited to, 3 -- cgit v1.1 From 9af4d80ba5666579944f570e113c5a87444afbde Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Mon, 24 Feb 2014 20:54:58 +0100 Subject: gpio: New driver for LSI ZEVIO SoCs This driver supports the GPIO controller found in LSI ZEVIO SoCs. It has been successfully tested on a TI nspire CX calculator. Signed-off-by: Fabian Vogt Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 6 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-zevio.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 drivers/gpio/gpio-zevio.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3bddd36..5e8bd21 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -145,6 +145,12 @@ config GPIO_EP93XX depends on ARCH_EP93XX select GPIO_GENERIC +config GPIO_ZEVIO + bool "LSI ZEVIO SoC memory mapped GPIOs" + depends on OF + help + Say yes here to support the GPIO controller in LSI ZEVIO SoCs. + config GPIO_MM_LANTIQ bool "Lantiq Memory mapped GPIOs" depends on LANTIQ && SOC_XWAY diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 5d50179..b845375 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -99,3 +99,4 @@ obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o +obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c new file mode 100644 index 0000000..9bf5034 --- /dev/null +++ b/drivers/gpio/gpio-zevio.c @@ -0,0 +1,220 @@ +/* + * GPIO controller in LSI ZEVIO SoCs. + * + * Author: Fabian Vogt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Memory layout: + * This chip has four gpio sections, each controls 8 GPIOs. + * Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10. + * Disclaimer: Reverse engineered! + * For more information refer to: + * http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29 + * + * 0x00-0x3F: Section 0 + * +0x00: Masked interrupt status (read-only) + * +0x04: R: Interrupt status W: Reset interrupt status + * +0x08: R: Interrupt mask W: Mask interrupt + * +0x0C: W: Unmask interrupt (write-only) + * +0x10: Direction: I/O=1/0 + * +0x14: Output + * +0x18: Input (read-only) + * +0x20: R: Level interrupt W: Set as level interrupt + * 0x40-0x7F: Section 1 + * 0x80-0xBF: Section 2 + * 0xC0-0xFF: Section 3 + */ + +#define ZEVIO_GPIO_SECTION_SIZE 0x40 + +/* Offsets to various registers */ +#define ZEVIO_GPIO_INT_MASKED_STATUS 0x00 +#define ZEVIO_GPIO_INT_STATUS 0x04 +#define ZEVIO_GPIO_INT_UNMASK 0x08 +#define ZEVIO_GPIO_INT_MASK 0x0C +#define ZEVIO_GPIO_DIRECTION 0x10 +#define ZEVIO_GPIO_OUTPUT 0x14 +#define ZEVIO_GPIO_INPUT 0x18 +#define ZEVIO_GPIO_INT_STICKY 0x20 + +#define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \ + struct zevio_gpio, chip) + +/* Bit number of GPIO in its section */ +#define ZEVIO_GPIO_BIT(gpio) (gpio&7) + +struct zevio_gpio { + spinlock_t lock; + struct of_mm_gpio_chip chip; +}; + +static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin, + unsigned port_offset) +{ + unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; + return readl(IOMEM(c->chip.regs + section_offset + port_offset)); +} + +static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin, + unsigned port_offset, u32 val) +{ + unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; + writel(val, IOMEM(c->chip.regs + section_offset + port_offset)); +} + +/* Functions for struct gpio_chip */ +static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + + /* Only reading allowed, so no spinlock needed */ + u32 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT); + + return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1; +} + +static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val; + + spin_lock(&controller->lock); + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); + if (value) + val |= BIT(ZEVIO_GPIO_BIT(pin)); + else + val &= ~BIT(ZEVIO_GPIO_BIT(pin)); + + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); + spin_unlock(&controller->lock); +} + +static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val; + + spin_lock(&controller->lock); + + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); + val |= BIT(ZEVIO_GPIO_BIT(pin)); + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); + + spin_unlock(&controller->lock); + + return 0; +} + +static int zevio_gpio_direction_output(struct gpio_chip *chip, + unsigned pin, int value) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val; + + spin_lock(&controller->lock); + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); + if (value) + val |= BIT(ZEVIO_GPIO_BIT(pin)); + else + val &= ~BIT(ZEVIO_GPIO_BIT(pin)); + + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); + val &= ~BIT(ZEVIO_GPIO_BIT(pin)); + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); + + spin_unlock(&controller->lock); + + return 0; +} + +static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin) +{ + /* + * TODO: Implement IRQs. + * Not implemented yet due to weird lockups + */ + + return -ENXIO; +} + +static struct gpio_chip zevio_gpio_chip = { + .direction_input = zevio_gpio_direction_input, + .direction_output = zevio_gpio_direction_output, + .set = zevio_gpio_set, + .get = zevio_gpio_get, + .to_irq = zevio_gpio_to_irq, + .base = 0, + .owner = THIS_MODULE, + .ngpio = 32, + .of_gpio_n_cells = 2, +}; + +/* Initialization */ +static int zevio_gpio_probe(struct platform_device *pdev) +{ + struct zevio_gpio *controller; + int status, i; + + controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL); + if (!controller) { + dev_err(&pdev->dev, "not enough free memory\n"); + return -ENOMEM; + } + + /* Copy our reference */ + controller->chip.gc = zevio_gpio_chip; + controller->chip.gc.dev = &pdev->dev; + + status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip)); + if (status) { + dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status); + return status; + } + + spin_lock_init(&controller->lock); + + /* Disable interrupts, they only cause errors */ + for (i = 0; i < controller->chip.gc.ngpio; i += 8) + zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF); + + dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n"); + + return 0; +} + +static struct of_device_id zevio_gpio_of_match[] = { + { .compatible = "lsi,zevio-gpio", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, zevio_gpio_of_match); + +static struct platform_driver zevio_gpio_driver = { + .driver = { + .name = "gpio-zevio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(zevio_gpio_of_match), + }, + .probe = zevio_gpio_probe, +}; +module_platform_driver(zevio_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Fabian Vogt "); +MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver"); -- cgit v1.1 From 0c6feb0796ea6407c6477994b854659311078cfa Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 13 Feb 2014 17:58:45 +0200 Subject: gpio: davinci: reuse for keystone soc The similar GPIO HW block is used by keystone SoCs as in Davinci SoCs. Hence, reuse Davinci GPIO driver for Keystone taking into account that Keystone contains ARM GIC IRQ controller which is implemented using IRQ Chip. Documentation: http://www.ti.com/lit/ug/sprugv1/sprugv1.pdf Acked-by: Santosh Shilimkar Acked-by: Linus Walleij Signed-off-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 48 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 29321ee..5247038 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -37,6 +37,8 @@ struct davinci_gpio_regs { u32 intstat; }; +typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); + #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ #define chip2controller(chip) \ @@ -413,6 +415,26 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = { .xlate = irq_domain_xlate_onetwocell, }; +static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq) +{ + static struct irq_chip_type gpio_unbanked; + + gpio_unbanked = *container_of(irq_get_chip(irq), + struct irq_chip_type, chip); + + return &gpio_unbanked.chip; +}; + +static struct irq_chip *keystone_gpio_get_irq_chip(unsigned int irq) +{ + static struct irq_chip gpio_unbanked; + + gpio_unbanked = *irq_get_chip(irq); + return &gpio_unbanked; +}; + +static const struct of_device_id davinci_gpio_ids[]; + /* * NOTE: for suspend/resume, probably best to make a platform_device with * suspend_late/resume_resume calls hooking into results of the set_wake() @@ -434,6 +456,18 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) struct davinci_gpio_platform_data *pdata = dev->platform_data; struct davinci_gpio_regs __iomem *g; struct irq_domain *irq_domain = NULL; + const struct of_device_id *match; + struct irq_chip *irq_chip; + gpio_get_irq_chip_cb_t gpio_get_irq_chip; + + /* + * Use davinci_gpio_get_irq_chip by default to handle non DT cases + */ + gpio_get_irq_chip = davinci_gpio_get_irq_chip; + match = of_match_device(of_match_ptr(davinci_gpio_ids), + dev); + if (match) + gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data; ngpio = pdata->ngpio; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -490,8 +524,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. */ if (pdata->gpio_unbanked) { - static struct irq_chip_type gpio_unbanked; - /* pass "bank 0" GPIO IRQs to AINTC */ chips[0].chip.to_irq = gpio_to_irq_unbanked; chips[0].gpio_irq = bank_irq; @@ -500,10 +532,9 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; - gpio_unbanked = *container_of(irq_get_chip(irq), - struct irq_chip_type, chip); - gpio_unbanked.chip.name = "GPIO-AINTC"; - gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked; + irq_chip = gpio_get_irq_chip(irq); + irq_chip->name = "GPIO-AINTC"; + irq_chip->irq_set_type = gpio_irq_type_unbanked; /* default trigger: both edges */ g = gpio2regs(0); @@ -512,7 +543,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) { - irq_set_chip(irq, &gpio_unbanked.chip); + irq_set_chip(irq, irq_chip); irq_set_handler_data(irq, &chips[gpio / 32]); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } @@ -555,7 +586,8 @@ done: #if IS_ENABLED(CONFIG_OF) static const struct of_device_id davinci_gpio_ids[] = { - { .compatible = "ti,dm6441-gpio", }, + { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip}, + { .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip}, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, davinci_gpio_ids); -- cgit v1.1 From 7779b34556978f6771a78bd87557523623e0405b Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 25 Feb 2014 17:01:01 -0600 Subject: gpio: add a driver for the Synopsys DesignWare APB GPIO block The Synopsys DesignWare block is used in some ARM devices (picoxcell) and can be configured to provide multiple banks of GPIO pins. v12: - Add irq_startup/shutdown - do irq_create_mapping() in probe, irq_find_mapping() in to_irq() - Adjust mappings to show support for 1 gpio per port. - gpio-cells = <1> v11: - Use NULL when checking existence of 'interrupts' property - Bindings descriptions cleanup v10: - in documentation nr-gpio -> nr-gpios v9: - cleanup in dt bindings doc - use of_get_child_count() v8: - remove socfpga.dtsi changes - minor cleanup in devicetree documentation v7: - use irq_generic_chip - support one irq per gpio line or one irq for many - s/bank/port/ and other cleanup v6: - (atull) squash the set of patches - use linear irq domain - build fixes. Original driver was reviewed on v3.2. - Fix setting irq edge type for 'rising' and 'both'. - Support as a loadable module. - Use bgpio_chip's spinlock during register access. - Clean up register names to match spec - s/bank/port/ because register names use the word 'port' - s/nr-gpio/nr-gpios/ - don't get/put the of_node - remove signoffs/acked-by's because of changes - other cleanup v5: - handle sparse bank population correctly v3: - depend on rather than select IRQ_DOMAIN - split IRQ support into a separate patch v2: - use Rob Herring's irqdomain in generic irq chip patches - use reg property to indicate bank index - support irqs on both edges based on LinusW's u300 driver Signed-off-by: Jamie Iles Signed-off-by: Alan Tull Reviewed-by: Sebastian Hesselbarth Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 9 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-dwapb.c | 438 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 448 insertions(+) create mode 100644 drivers/gpio/gpio-dwapb.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5e8bd21..e9dda86 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -128,6 +128,15 @@ config GPIO_GENERIC_PLATFORM help Say yes here to support basic platform_device memory-mapped GPIO controllers. +config GPIO_DWAPB + tristate "Synopsys DesignWare APB GPIO driver" + select GPIO_GENERIC + select GENERIC_IRQ_CHIP + depends on OF_GPIO && IRQ_DOMAIN + help + Say Y or M here to build support for the Synopsys DesignWare APB + GPIO block. + config GPIO_IT8761E tristate "IT8761E GPIO support" depends on X86 # unconditional access to IO space. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index b845375..7038470 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o +obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c new file mode 100644 index 0000000..2797fbb --- /dev/null +++ b/drivers/gpio/gpio-dwapb.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2011 Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * All enquiries to support@picochip.com + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_SWPORTA_DR 0x00 +#define GPIO_SWPORTA_DDR 0x04 +#define GPIO_SWPORTB_DR 0x0c +#define GPIO_SWPORTB_DDR 0x10 +#define GPIO_SWPORTC_DR 0x18 +#define GPIO_SWPORTC_DDR 0x1c +#define GPIO_SWPORTD_DR 0x24 +#define GPIO_SWPORTD_DDR 0x28 +#define GPIO_INTEN 0x30 +#define GPIO_INTMASK 0x34 +#define GPIO_INTTYPE_LEVEL 0x38 +#define GPIO_INT_POLARITY 0x3c +#define GPIO_INTSTATUS 0x40 +#define GPIO_PORTA_EOI 0x4c +#define GPIO_EXT_PORTA 0x50 +#define GPIO_EXT_PORTB 0x54 +#define GPIO_EXT_PORTC 0x58 +#define GPIO_EXT_PORTD 0x5c + +#define DWAPB_MAX_PORTS 4 +#define GPIO_EXT_PORT_SIZE (GPIO_EXT_PORTB - GPIO_EXT_PORTA) +#define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR) +#define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR) + +struct dwapb_gpio; + +struct dwapb_gpio_port { + struct bgpio_chip bgc; + bool is_registered; + struct dwapb_gpio *gpio; +}; + +struct dwapb_gpio { + struct device *dev; + void __iomem *regs; + struct dwapb_gpio_port *ports; + unsigned int nr_ports; + struct irq_domain *domain; +}; + +static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + struct dwapb_gpio_port *port = container_of(bgc, struct + dwapb_gpio_port, bgc); + struct dwapb_gpio *gpio = port->gpio; + + return irq_find_mapping(gpio->domain, offset); +} + +static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs) +{ + u32 v = readl(gpio->regs + GPIO_INT_POLARITY); + + if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs)) + v &= ~BIT(offs); + else + v |= BIT(offs); + + writel(v, gpio->regs + GPIO_INT_POLARITY); +} + +static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) +{ + struct dwapb_gpio *gpio = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS); + + while (irq_status) { + int hwirq = fls(irq_status) - 1; + int gpio_irq = irq_find_mapping(gpio->domain, hwirq); + + generic_handle_irq(gpio_irq); + irq_status &= ~BIT(hwirq); + + if ((irq_get_trigger_type(gpio_irq) & IRQ_TYPE_SENSE_MASK) + == IRQ_TYPE_EDGE_BOTH) + dwapb_toggle_trigger(gpio, hwirq); + } + + if (chip->irq_eoi) + chip->irq_eoi(irq_desc_get_irq_data(desc)); +} + +static void dwapb_irq_enable(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&bgc->lock, flags); + val = readl(gpio->regs + GPIO_INTEN); + val |= BIT(d->hwirq); + writel(val, gpio->regs + GPIO_INTEN); + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static void dwapb_irq_disable(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&bgc->lock, flags); + val = readl(gpio->regs + GPIO_INTEN); + val &= ~BIT(d->hwirq); + writel(val, gpio->regs + GPIO_INTEN); + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static unsigned int dwapb_irq_startup(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + + if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) + dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + dwapb_irq_enable(d); + return 0; +} + +static void dwapb_irq_shutdown(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + + dwapb_irq_disable(d); + gpio_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d)); +} + +static int dwapb_irq_set_type(struct irq_data *d, u32 type) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + int bit = d->hwirq; + unsigned long level, polarity, flags; + + if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | + IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) + return -EINVAL; + + spin_lock_irqsave(&bgc->lock, flags); + level = readl(gpio->regs + GPIO_INTTYPE_LEVEL); + polarity = readl(gpio->regs + GPIO_INT_POLARITY); + + switch (type) { + case IRQ_TYPE_EDGE_BOTH: + level |= BIT(bit); + dwapb_toggle_trigger(gpio, bit); + break; + case IRQ_TYPE_EDGE_RISING: + level |= BIT(bit); + polarity |= BIT(bit); + break; + case IRQ_TYPE_EDGE_FALLING: + level |= BIT(bit); + polarity &= ~BIT(bit); + break; + case IRQ_TYPE_LEVEL_HIGH: + level &= ~BIT(bit); + polarity |= BIT(bit); + break; + case IRQ_TYPE_LEVEL_LOW: + level &= ~BIT(bit); + polarity &= ~BIT(bit); + break; + } + + writel(level, gpio->regs + GPIO_INTTYPE_LEVEL); + writel(polarity, gpio->regs + GPIO_INT_POLARITY); + spin_unlock_irqrestore(&bgc->lock, flags); + + return 0; +} + +static void dwapb_configure_irqs(struct dwapb_gpio *gpio, + struct dwapb_gpio_port *port) +{ + struct gpio_chip *gc = &port->bgc.gc; + struct device_node *node = gc->of_node; + struct irq_chip_generic *irq_gc; + unsigned int hwirq, ngpio = gc->ngpio; + struct irq_chip_type *ct; + int err, irq; + + irq = irq_of_parse_and_map(node, 0); + if (!irq) { + dev_warn(gpio->dev, "no irq for bank %s\n", + port->bgc.gc.of_node->full_name); + return; + } + + gpio->domain = irq_domain_add_linear(node, ngpio, + &irq_generic_chip_ops, gpio); + if (!gpio->domain) + return; + + err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 1, + "gpio-dwapb", handle_level_irq, + IRQ_NOREQUEST, 0, + IRQ_GC_INIT_NESTED_LOCK); + if (err) { + dev_info(gpio->dev, "irq_alloc_domain_generic_chips failed\n"); + irq_domain_remove(gpio->domain); + gpio->domain = NULL; + return; + } + + irq_gc = irq_get_domain_generic_chip(gpio->domain, 0); + if (!irq_gc) { + irq_domain_remove(gpio->domain); + gpio->domain = NULL; + return; + } + + irq_gc->reg_base = gpio->regs; + irq_gc->private = gpio; + + ct = irq_gc->chip_types; + ct->chip.irq_ack = irq_gc_ack_set_bit; + ct->chip.irq_mask = irq_gc_mask_set_bit; + ct->chip.irq_unmask = irq_gc_mask_clr_bit; + ct->chip.irq_set_type = dwapb_irq_set_type; + ct->chip.irq_enable = dwapb_irq_enable; + ct->chip.irq_disable = dwapb_irq_disable; + ct->chip.irq_startup = dwapb_irq_startup; + ct->chip.irq_shutdown = dwapb_irq_shutdown; + ct->regs.ack = GPIO_PORTA_EOI; + ct->regs.mask = GPIO_INTMASK; + + irq_setup_generic_chip(irq_gc, IRQ_MSK(port->bgc.gc.ngpio), + IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); + + irq_set_chained_handler(irq, dwapb_irq_handler); + irq_set_handler_data(irq, gpio); + + for (hwirq = 0 ; hwirq < ngpio ; hwirq++) + irq_create_mapping(gpio->domain, hwirq); + + port->bgc.gc.to_irq = dwapb_gpio_to_irq; +} + +static void dwapb_irq_teardown(struct dwapb_gpio *gpio) +{ + struct dwapb_gpio_port *port = &gpio->ports[0]; + struct gpio_chip *gc = &port->bgc.gc; + unsigned int ngpio = gc->ngpio; + irq_hw_number_t hwirq; + + if (!gpio->domain) + return; + + for (hwirq = 0 ; hwirq < ngpio ; hwirq++) + irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq)); + + irq_domain_remove(gpio->domain); + gpio->domain = NULL; +} + +static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, + struct device_node *port_np, + unsigned int offs) +{ + struct dwapb_gpio_port *port; + u32 port_idx, ngpio; + void __iomem *dat, *set, *dirout; + int err; + + if (of_property_read_u32(port_np, "reg", &port_idx) || + port_idx >= DWAPB_MAX_PORTS) { + dev_err(gpio->dev, "missing/invalid port index for %s\n", + port_np->full_name); + return -EINVAL; + } + + port = &gpio->ports[offs]; + port->gpio = gpio; + + if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) { + dev_info(gpio->dev, "failed to get number of gpios for %s\n", + port_np->full_name); + ngpio = 32; + } + + dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE); + set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE); + dirout = gpio->regs + GPIO_SWPORTA_DDR + + (port_idx * GPIO_SWPORT_DDR_SIZE); + + err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout, + NULL, false); + if (err) { + dev_err(gpio->dev, "failed to init gpio chip for %s\n", + port_np->full_name); + return err; + } + + port->bgc.gc.ngpio = ngpio; + port->bgc.gc.of_node = port_np; + + /* + * Only port A can provide interrupts in all configurations of the IP. + */ + if (port_idx == 0 && + of_property_read_bool(port_np, "interrupt-controller")) + dwapb_configure_irqs(gpio, port); + + err = gpiochip_add(&port->bgc.gc); + if (err) + dev_err(gpio->dev, "failed to register gpiochip for %s\n", + port_np->full_name); + else + port->is_registered = true; + + return err; +} + +static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) +{ + unsigned int m; + + for (m = 0; m < gpio->nr_ports; ++m) + if (gpio->ports[m].is_registered) + WARN_ON(gpiochip_remove(&gpio->ports[m].bgc.gc)); +} + +static int dwapb_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + struct dwapb_gpio *gpio; + struct device_node *np; + int err; + unsigned int offs = 0; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + gpio->dev = &pdev->dev; + + gpio->nr_ports = of_get_child_count(pdev->dev.of_node); + if (!gpio->nr_ports) { + err = -EINVAL; + goto out_err; + } + gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports * + sizeof(*gpio->ports), GFP_KERNEL); + if (!gpio->ports) { + err = -ENOMEM; + goto out_err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio->regs)) { + err = PTR_ERR(gpio->regs); + goto out_err; + } + + for_each_child_of_node(pdev->dev.of_node, np) { + err = dwapb_gpio_add_port(gpio, np, offs++); + if (err) + goto out_unregister; + } + platform_set_drvdata(pdev, gpio); + + return 0; + +out_unregister: + dwapb_gpio_unregister(gpio); + dwapb_irq_teardown(gpio); + +out_err: + return err; +} + +static int dwapb_gpio_remove(struct platform_device *pdev) +{ + struct dwapb_gpio *gpio = platform_get_drvdata(pdev); + + dwapb_gpio_unregister(gpio); + dwapb_irq_teardown(gpio); + + return 0; +} + +static const struct of_device_id dwapb_of_match[] = { + { .compatible = "snps,dw-apb-gpio" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dwapb_of_match); + +static struct platform_driver dwapb_gpio_driver = { + .driver = { + .name = "gpio-dwapb", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(dwapb_of_match), + }, + .probe = dwapb_gpio_probe, + .remove = dwapb_gpio_remove, +}; + +module_platform_driver(dwapb_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jamie Iles"); +MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver"); -- cgit v1.1 From de15011ac4e03a81e1483ddb7e876e6b64531887 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Feb 2014 13:43:31 +0100 Subject: gpio: remove obsolete tnetv107x driver The tnetv107x platform is getting removed, so this driver won't be needed any more. Signed-off-by: Arnd Bergmann Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org Acked-by: Sekhar Nori Signed-off-by: Linus Walleij --- drivers/gpio/Makefile | 1 - drivers/gpio/gpio-tnetv107x.c | 206 ------------------------------------------ 2 files changed, 207 deletions(-) delete mode 100644 drivers/gpio/gpio-tnetv107x.c (limited to 'drivers') diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 7038470..aaff7ff 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -81,7 +81,6 @@ obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o -obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o diff --git a/drivers/gpio/gpio-tnetv107x.c b/drivers/gpio/gpio-tnetv107x.c deleted file mode 100644 index 4aa4815..0000000 --- a/drivers/gpio/gpio-tnetv107x.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Texas Instruments TNETV107X GPIO Controller - * - * Copyright (C) 2010 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include -#include -#include -#include - -#include -#include - -struct tnetv107x_gpio_regs { - u32 idver; - u32 data_in[3]; - u32 data_out[3]; - u32 direction[3]; - u32 enable[3]; -}; - -#define gpio_reg_index(gpio) ((gpio) >> 5) -#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f) - -#define gpio_reg_rmw(reg, mask, val) \ - __raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg)) - -#define gpio_reg_set_bit(reg, gpio) \ - gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio)) - -#define gpio_reg_clear_bit(reg, gpio) \ - gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0) - -#define gpio_reg_get_bit(reg, gpio) \ - (__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio)) - -#define chip2controller(chip) \ - container_of(chip, struct davinci_gpio_controller, chip) - -#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32) - -static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS]; - -static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - gpio_reg_set_bit(regs->enable, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); - - return 0; -} - -static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - gpio_reg_clear_bit(regs->enable, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); -} - -static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - gpio_reg_set_bit(regs->direction, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); - - return 0; -} - -static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - if (value) - gpio_reg_set_bit(regs->data_out, gpio); - else - gpio_reg_clear_bit(regs->data_out, gpio); - - gpio_reg_clear_bit(regs->direction, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); - - return 0; -} - -static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - int ret; - - ret = gpio_reg_get_bit(regs->data_in, gpio); - - return ret ? 1 : 0; -} - -static void tnetv107x_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - if (value) - gpio_reg_set_bit(regs->data_out, gpio); - else - gpio_reg_clear_bit(regs->data_out, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); -} - -static int __init tnetv107x_gpio_setup(void) -{ - int i, base; - unsigned ngpio; - struct davinci_soc_info *soc_info = &davinci_soc_info; - struct tnetv107x_gpio_regs *regs; - struct davinci_gpio_controller *ctlr; - - if (soc_info->gpio_type != GPIO_TYPE_TNETV107X) - return 0; - - ngpio = soc_info->gpio_num; - if (ngpio == 0) { - pr_err("GPIO setup: how many GPIOs?\n"); - return -EINVAL; - } - - if (WARN_ON(TNETV107X_N_GPIO < ngpio)) - ngpio = TNETV107X_N_GPIO; - - regs = ioremap(soc_info->gpio_base, SZ_4K); - if (WARN_ON(!regs)) - return -EINVAL; - - for (i = 0, base = 0; base < ngpio; i++, base += 32) { - ctlr = &chips[i]; - - ctlr->chip.label = "tnetv107x"; - ctlr->chip.can_sleep = false; - ctlr->chip.base = base; - ctlr->chip.ngpio = ngpio - base; - if (ctlr->chip.ngpio > 32) - ctlr->chip.ngpio = 32; - - ctlr->chip.request = tnetv107x_gpio_request; - ctlr->chip.free = tnetv107x_gpio_free; - ctlr->chip.direction_input = tnetv107x_gpio_dir_in; - ctlr->chip.get = tnetv107x_gpio_get; - ctlr->chip.direction_output = tnetv107x_gpio_dir_out; - ctlr->chip.set = tnetv107x_gpio_set; - - spin_lock_init(&ctlr->lock); - - ctlr->regs = regs; - ctlr->set_data = ®s->data_out[i]; - ctlr->clr_data = ®s->data_out[i]; - ctlr->in_data = ®s->data_in[i]; - - gpiochip_add(&ctlr->chip); - } - - soc_info->gpio_ctlrs = chips; - soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32); - return 0; -} -pure_initcall(tnetv107x_gpio_setup); -- cgit v1.1 From feabf0cd4536f4853a501549e8c848d84b45dc36 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 6 Mar 2014 10:25:36 +0800 Subject: gpio: zevio: depend on ARM and OF_GPIO Instead of just depending on OF and getting build failures, depend on ARM && OF_GPIO. Cc: Fabian Vogt Cc: Stephen Rothwell Cc: Andrew Morton Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e9dda86..b56bd0c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -156,7 +156,7 @@ config GPIO_EP93XX config GPIO_ZEVIO bool "LSI ZEVIO SoC memory mapped GPIOs" - depends on OF + depends on ARM && OF_GPIO help Say yes here to support the GPIO controller in LSI ZEVIO SoCs. -- cgit v1.1 From c7861f37b4c63b7f45d37b113acabbf352597c46 Mon Sep 17 00:00:00 2001 From: Alan Tull Date: Thu, 6 Mar 2014 13:29:40 -0600 Subject: fix build error in gpio-dwapb patch fix build error with this message: kernel/irq/Kconfig:41:error: recursive dependency detected! kernel/irq/Kconfig:41: symbol GENERIC_IRQ_CHIP is selected by GPIO_DWAPB drivers/gpio/Kconfig:131: symbol GPIO_DWAPB depends on IRQ_DOMAIN kernel/irq/Kconfig:46: symbol IRQ_DOMAIN is selected by GENERIC_IRQ_CHIP Signed-off-by: Alan Tull Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b56bd0c..4d5096e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -132,7 +132,7 @@ config GPIO_DWAPB tristate "Synopsys DesignWare APB GPIO driver" select GPIO_GENERIC select GENERIC_IRQ_CHIP - depends on OF_GPIO && IRQ_DOMAIN + depends on OF_GPIO help Say Y or M here to build support for the Synopsys DesignWare APB GPIO block. -- cgit v1.1 From 76b3627ea511f73c25c9d9a4c28e4449d72a9b1c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 26 Feb 2014 08:12:37 -0300 Subject: gpio: gpio-pl061: Use %pa to print 'resource_size_t' The following build warning is generated when building multi_v7_defconfig with LPAE option selected: drivers/gpio/gpio-pl061.c:358:2: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'resource_size_t' [-Wformat=] Fix it by using %pa to print 'resource_size_t'. Reported-by: Olof's autobuilder Signed-off-by: Fabio Estevam Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pl061.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index e528cb2..391766e 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -355,8 +355,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) } amba_set_drvdata(adev, chip); - dev_info(&adev->dev, "PL061 GPIO chip @%08x registered\n", - adev->res.start); + dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n", + &adev->res.start); return 0; } -- cgit v1.1 From f438acdf3de8f19ad2789eddbf52e3280292759b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 7 Mar 2014 10:12:49 +0800 Subject: gpio: remove misleading documentation It is currently debated where the functions to lock a certain GPIO line as used for IRQs should be called. Delete all misleading documentation. Reported-by: Thomas Gleixner Cc: Jean-Jacques Hiblot Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9cd7082..aa6a11b 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2167,10 +2167,7 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq); * @gpio: the GPIO line to lock as used for IRQ * * This is used directly by GPIO drivers that want to lock down - * a certain GPIO line to be used as IRQs, for example in the - * .to_irq() callback of their gpio_chip, or in the .irq_enable() - * of its irq_chip implementation if the GPIO is known from that - * code. + * a certain GPIO line to be used for IRQs. */ int gpiod_lock_as_irq(struct gpio_desc *desc) { -- cgit v1.1 From d3e144532703fe2454b56eddb56f30d2d620187b Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 4 Mar 2014 11:28:48 +0000 Subject: gpio-tz1090: Replace commas with semi-colons Replace commas with semicolons between irqchip callback initialisation statements in tz1090_gpio_bank_probe. The commas appear to be a subtle remnant of when the irqchips were statically initialised. Thanks to Thomas Gleixner for spotting it while whipping up a coccinelle script. Reported-by: Thomas Gleixner Signed-off-by: James Hogan Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org Cc: linux-metag@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tz1090.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index 23e0613..5246a60 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -488,26 +488,26 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) gc->chip_types[0].handler = handle_level_irq; gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS; gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[0].chip.irq_startup = gpio_startup_irq, - gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit, - gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit, - gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit, - gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type, - gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake, - gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + gc->chip_types[0].chip.irq_startup = gpio_startup_irq; + gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type; + gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake; + gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* edge chip type */ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; gc->chip_types[1].handler = handle_edge_irq; gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS; gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[1].chip.irq_startup = gpio_startup_irq, - gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit, - gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit, - gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit, - gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type, - gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake, - gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + gc->chip_types[1].chip.irq_startup = gpio_startup_irq; + gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit; + gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type; + gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake; + gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* Setup chained handler for this GPIO bank */ irq_set_handler_data(bank->irq, bank); -- cgit v1.1 From 758afe429c501924ac650ad667fd79f4bb06c05a Mon Sep 17 00:00:00 2001 From: Alexander Holler Date: Wed, 5 Mar 2014 12:21:01 +0100 Subject: gpio: davinci: fix gpio selection for OF The driver missed an of_xlate function to translate gpio numbers as found in the DT to the correct chip and number. While there I've set #gpio_cells to a fixed value of 2. I've used gpio-pxa.c as template for those changes and tested my changes successfully on a da850 board using entries for gpio-leds in a DT. So I didn't reinvent the wheel but just copied and tested stuff. Thanks to Grygorii Strashko for the hint to the existing code in gpio-pxa. Signed-off-by: Alexander Holler Signed-off-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 5247038..339f9da 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -174,6 +174,27 @@ of_err: return NULL; } +#ifdef CONFIG_OF_GPIO +static int davinci_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev); + struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev); + + if (gpiospec->args[0] > pdata->ngpio) + return -EINVAL; + + if (gc != &chips[gpiospec->args[0] / 32].chip) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[1]; + + return gpiospec->args[0] % 32; +} +#endif + static int davinci_gpio_probe(struct platform_device *pdev) { int i, base; @@ -238,6 +259,9 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips[i].chip.ngpio = 32; #ifdef CONFIG_OF_GPIO + chips[i].chip.of_gpio_n_cells = 2; + chips[i].chip.of_xlate = davinci_gpio_of_xlate; + chips[i].chip.dev = dev; chips[i].chip.of_node = dev->of_node; #endif spin_lock_init(&chips[i].lock); -- cgit v1.1 From c75793d8ab743acdd07120cf11c0242daea8f780 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Mar 2014 10:31:15 +0100 Subject: gpio: max732x: Fix I2C dummy device resource leak on probe failure In max732x_probe() driver allocates dummy I2C device (if number of ports is greater than 8) however it is not unregistered if probe fails later. Fix the leak by unregistering dummy I2C device if it was allocated. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 36cb290..74432da 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -647,6 +647,8 @@ static int max732x_probe(struct i2c_client *client, return 0; out_failed: + if (chip->client_dummy) + i2c_unregister_device(chip->client_dummy); max732x_irq_teardown(chip); return ret; } -- cgit v1.1 From f561b4230cec90137baeba1b1c9302461939b870 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Mar 2014 10:31:16 +0100 Subject: gpio: max732x: Fix possible NULL pointer dereference on i2c_new_dummy error In max732x_probe() driver allocates dummy I2C device (if number of ports is greater than 8) with i2c_new_dummy() but it does not check the return value of this call. In case of error (i2c_new_device(): memory allocation failure or I2C address cannot be used) this function returns NULL which is later dereferenced by i2c_smbus_read_byte() (called from max732x_readb()). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 74432da..7c36f2b 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -622,6 +622,13 @@ static int max732x_probe(struct i2c_client *client, goto out_failed; } + if (nr_port > 8 && !chip->client_dummy) { + dev_err(&client->dev, + "Failed to allocate second group I2C device\n"); + ret = -ENODEV; + goto out_failed; + } + mutex_init(&chip->lock); max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); -- cgit v1.1 From 33bc8411eec33f92ba59e8ef7394b82245ec556e Mon Sep 17 00:00:00 2001 From: Gary Servin Date: Thu, 6 Mar 2014 20:25:26 -0300 Subject: gpio: mcp23s08: trivial: fixed coding style issues This coding style issue was detected using the checkpatch.pl script Signed-off-by: Gary Servin Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mcp23s08.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 1ac288e..e1734c1 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -173,7 +173,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); return (status < 0) ? status : rx[0]; } @@ -184,7 +184,7 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[0] = mcp->addr; tx[1] = reg; tx[2] = val; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); } static int @@ -193,13 +193,13 @@ mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) u8 tx[2], *tmp; int status; - if ((n + reg) > sizeof mcp->cache) + if ((n + reg) > sizeof(mcp->cache)) return -EINVAL; tx[0] = mcp->addr | 0x01; tx[1] = reg; tmp = (u8 *)vals; - status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), tmp, n); if (status >= 0) { while (n--) vals[n] = tmp[n]; /* expand to 16bit */ @@ -214,7 +214,7 @@ static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); return (status < 0) ? status : (rx[0] | (rx[1] << 8)); } @@ -226,7 +226,7 @@ static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[1] = reg << 1; tx[2] = val; tx[3] = val >> 8; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); } static int @@ -235,12 +235,12 @@ mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) u8 tx[2]; int status; - if ((n + reg) > sizeof mcp->cache) + if ((n + reg) > sizeof(mcp->cache)) return -EINVAL; tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, + status = spi_write_then_read(mcp->data, tx, sizeof(tx), (u8 *)vals, n * 2); if (status >= 0) { while (n--) @@ -567,7 +567,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo", (mcp->cache[MCP_GPPU] & mask) ? "up" : " "); /* NOTE: ignoring the irq-related registers */ - seq_printf(s, "\n"); + seq_puts(s, "\n"); } done: mutex_unlock(&mcp->lock); @@ -789,7 +789,7 @@ static int mcp230xx_probe(struct i2c_client *client, pullups = pdata->chip[0].pullups; } - mcp = kzalloc(sizeof *mcp, GFP_KERNEL); + mcp = kzalloc(sizeof(*mcp), GFP_KERNEL); if (!mcp) return -ENOMEM; @@ -925,7 +925,7 @@ static int mcp23s08_probe(struct spi_device *spi) base = pdata->base; } - data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08), + data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08), GFP_KERNEL); if (!data) return -ENOMEM; -- cgit v1.1 From 5da82cac7496ec4593715ed00ec5fb7feb594323 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 7 Mar 2014 22:11:37 +0100 Subject: gpio: cs5535: Simplify dependencies The bus and architecture dependencies are already on MFD_CS5535, so there is no need to repeat them here. Signed-off-by: Jean Delvare Cc: Linus Walleij Cc: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4d5096e..00e48c5 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -649,7 +649,7 @@ comment "PCI GPIO expanders:" config GPIO_CS5535 tristate "AMD CS5535/CS5536 GPIO support" - depends on PCI && X86 && MFD_CS5535 + depends on MFD_CS5535 help The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that can be used for quite a number of things. The CS5535/6 is found on -- cgit v1.1 From 22520edc92d02b5a7dd3c24f57583a41643a8454 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:23:44 +0100 Subject: gpio: Spelling s/than/that/ Signed-off-by: Geert Uytterhoeven Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 00e48c5..149557f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -661,7 +661,7 @@ config GPIO_BT8XX tristate "BT8XX GPIO abuser" depends on PCI && VIDEO_BT848=n help - The BT8xx frame grabber chip has 24 GPIO pins than can be abused + The BT8xx frame grabber chip has 24 GPIO pins that can be abused as a cheap PCI GPIO card. This chip can be found on Miro, Hauppauge and STB TV-cards. -- cgit v1.1 From 77c2d7929d7d7f0e391b17f85d2d954912ed0590 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 10 Mar 2014 14:54:50 +0200 Subject: gpiolib: Allow GPIO chips to request their own GPIOs Sometimes it is useful to allow GPIO chips themselves to request GPIOs they own through gpiolib API. One use case is ACPI ASL code that should be able to toggle GPIOs through GPIO operation regions. We can't use gpio_request() because it will pin the module to the kernel forever (it calls try_module_get()). To solve this we move module refcount manipulation to gpiod_request() and let __gpiod_request() handle the actual request. This changes the sequence a bit as now try_module_get() is called outside of gpio_lock (I think this is safe, try_module_get() handles serialization it needs already). Then we provide gpiolib internal functions gpiochip_request/free_own_desc() that do the same as gpio_request() but don't manipulate module refrence count. This allows the GPIO chip driver to request and free descriptors it owns without being pinned to the kernel forever. Signed-off-by: Mika Westerberg Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 100 ++++++++++++++++++++++++++++++++++++------------- drivers/gpio/gpiolib.h | 3 ++ 2 files changed, 76 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index aa6a11b..8fbc67a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1458,26 +1458,14 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. */ -static int gpiod_request(struct gpio_desc *desc, const char *label) +static int __gpiod_request(struct gpio_desc *desc, const char *label) { - struct gpio_chip *chip; - int status = -EPROBE_DEFER; + struct gpio_chip *chip = desc->chip; + int status; unsigned long flags; - if (!desc) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (chip == NULL) - goto done; - - if (!try_module_get(chip->owner)) - goto done; - /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled, for non-sleeping (SOC) GPIOs. */ @@ -1487,7 +1475,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) status = 0; } else { status = -EBUSY; - module_put(chip->owner); goto done; } @@ -1499,7 +1486,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) if (status < 0) { desc_set_label(desc, NULL); - module_put(chip->owner); clear_bit(FLAG_REQUESTED, &desc->flags); goto done; } @@ -1511,9 +1497,34 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) spin_lock_irqsave(&gpio_lock, flags); } done: + spin_unlock_irqrestore(&gpio_lock, flags); + return status; +} + +static int gpiod_request(struct gpio_desc *desc, const char *label) +{ + int status = -EPROBE_DEFER; + struct gpio_chip *chip; + + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + + chip = desc->chip; + if (!chip) + goto done; + + if (try_module_get(chip->owner)) { + status = __gpiod_request(desc, label); + if (status < 0) + module_put(chip->owner); + } + +done: if (status) gpiod_dbg(desc, "%s: status %d\n", __func__, status); - spin_unlock_irqrestore(&gpio_lock, flags); + return status; } @@ -1523,18 +1534,14 @@ int gpio_request(unsigned gpio, const char *label) } EXPORT_SYMBOL_GPL(gpio_request); -static void gpiod_free(struct gpio_desc *desc) +static bool __gpiod_free(struct gpio_desc *desc) { + bool ret = false; unsigned long flags; struct gpio_chip *chip; might_sleep(); - if (!desc) { - WARN_ON(extra_checks); - return; - } - gpiod_unexport(desc); spin_lock_irqsave(&gpio_lock, flags); @@ -1548,15 +1555,23 @@ static void gpiod_free(struct gpio_desc *desc) spin_lock_irqsave(&gpio_lock, flags); } desc_set_label(desc, NULL); - module_put(desc->chip->owner); clear_bit(FLAG_ACTIVE_LOW, &desc->flags); clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); - } else - WARN_ON(extra_checks); + ret = true; + } spin_unlock_irqrestore(&gpio_lock, flags); + return ret; +} + +static void gpiod_free(struct gpio_desc *desc) +{ + if (desc && __gpiod_free(desc)) + module_put(desc->chip->owner); + else + WARN_ON(extra_checks); } void gpio_free(unsigned gpio) @@ -1678,6 +1693,37 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) } EXPORT_SYMBOL_GPL(gpiochip_is_requested); +/** + * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor + * @desc: GPIO descriptor to request + * @label: label for the GPIO + * + * Function allows GPIO chip drivers to request and use their own GPIO + * descriptors via gpiolib API. Difference to gpiod_request() is that this + * function will not increase reference count of the GPIO chip module. This + * allows the GPIO chip module to be unloaded as needed (we assume that the + * GPIO chip driver handles freeing the GPIOs it has requested). + */ +int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) +{ + if (!desc || !desc->chip) + return -EINVAL; + + return __gpiod_request(desc, label); +} + +/** + * gpiochip_free_own_desc - Free GPIO requested by the chip driver + * @desc: GPIO descriptor to free + * + * Function frees the given GPIO requested previously with + * gpiochip_request_own_desc(). + */ +void gpiochip_free_own_desc(struct gpio_desc *desc) +{ + if (desc) + __gpiod_free(desc); +} /* Drivers MUST set GPIO direction before making get/set calls. In * some cases this is done in early boot, before IRQs are enabled. diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 82be586..cf09294 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -43,4 +43,7 @@ acpi_get_gpiod_by_index(struct device *dev, int index, } #endif +int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label); +void gpiochip_free_own_desc(struct gpio_desc *desc); + #endif /* GPIOLIB_H */ -- cgit v1.1 From aa92b6f689acf159120ce0753f36100c3b190b4d Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 10 Mar 2014 14:54:51 +0200 Subject: gpio / ACPI: Allocate ACPI specific data directly in acpi_gpiochip_add() We are going to add more ACPI specific data to accompany GPIO chip so instead of allocating it per each use-case we allocate it once when acpi_gpiochip_add() is called and release it when acpi_gpiochip_remove() is called. Doing this allows us to add more ACPI specific data by merely adding new fields to struct acpi_gpio_chip. In addition we embed evt_pins member directly to the structure instead of having it as a pointer. This simplifies the code a bit since we don't need to check against NULL. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 106 ++++++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index b7db098..5c0cf1d 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -26,6 +26,11 @@ struct acpi_gpio_evt_pin { unsigned int irq; }; +struct acpi_gpio_chip { + struct gpio_chip *chip; + struct list_head evt_pins; +}; + static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) { if (!gc->dev) @@ -81,14 +86,14 @@ static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) return IRQ_HANDLED; } -static void acpi_gpio_evt_dh(acpi_handle handle, void *data) +static void acpi_gpio_chip_dh(acpi_handle handle, void *data) { /* The address of this function is used as a key. */ } /** * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events - * @chip: gpio chip + * @acpi_gpio: ACPI GPIO chip * * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are * handled by ACPI event methods which need to be called from the GPIO @@ -96,12 +101,12 @@ static void acpi_gpio_evt_dh(acpi_handle handle, void *data) * gpio pins have acpi event methods and assigns interrupt handlers that calls * the acpi event methods for those pins. */ -static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) +static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) { struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + struct gpio_chip *chip = acpi_gpio->chip; struct acpi_resource *res; acpi_handle handle, evt_handle; - struct list_head *evt_pins = NULL; acpi_status status; unsigned int pin; int irq, ret; @@ -114,23 +119,7 @@ static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) if (!handle) return; - status = acpi_get_event_resources(handle, &buf); - if (ACPI_FAILURE(status)) - return; - - status = acpi_get_handle(handle, "_EVT", &evt_handle); - if (ACPI_SUCCESS(status)) { - evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL); - if (evt_pins) { - INIT_LIST_HEAD(evt_pins); - status = acpi_attach_data(handle, acpi_gpio_evt_dh, - evt_pins); - if (ACPI_FAILURE(status)) { - kfree(evt_pins); - evt_pins = NULL; - } - } - } + INIT_LIST_HEAD(&acpi_gpio->evt_pins); /* * If a GPIO interrupt has an ACPI event handler method, or _EVT is @@ -167,14 +156,18 @@ static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) data = ev_handle; } } - if (!handler && evt_pins) { + if (!handler) { struct acpi_gpio_evt_pin *evt_pin; + status = acpi_get_handle(handle, "_EVT", &evt_handle); + if (ACPI_FAILURE(status)) + continue + evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL); if (!evt_pin) continue; - list_add_tail(&evt_pin->node, evt_pins); + list_add_tail(&evt_pin->node, &acpi_gpio->evt_pins); evt_pin->evt_handle = evt_handle; evt_pin->pin = pin; evt_pin->irq = irq; @@ -197,39 +190,27 @@ static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) /** * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. - * @chip: gpio chip + * @acpi_gpio: ACPI GPIO chip * * Free interrupts associated with the _EVT method for the given GPIO chip. * * The remaining ACPI event interrupts associated with the chip are freed * automatically. */ -static void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) +static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) { - acpi_handle handle; - acpi_status status; - struct list_head *evt_pins; struct acpi_gpio_evt_pin *evt_pin, *ep; + struct gpio_chip *chip = acpi_gpio->chip; if (!chip->dev || !chip->to_irq) return; - handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; - - status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); - if (ACPI_FAILURE(status)) - return; - - list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) { + list_for_each_entry_safe_reverse(evt_pin, ep, &acpi_gpio->evt_pins, + node) { devm_free_irq(chip->dev, evt_pin->irq, evt_pin); list_del(&evt_pin->node); kfree(evt_pin); } - - acpi_detach_data(handle, acpi_gpio_evt_dh); - kfree(evt_pins); } struct acpi_gpio_lookup { @@ -312,10 +293,51 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, void acpi_gpiochip_add(struct gpio_chip *chip) { - acpi_gpiochip_request_interrupts(chip); + struct acpi_gpio_chip *acpi_gpio; + acpi_handle handle; + acpi_status status; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL); + if (!acpi_gpio) { + dev_err(chip->dev, + "Failed to allocate memory for ACPI GPIO chip\n"); + return; + } + + acpi_gpio->chip = chip; + + status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio); + if (ACPI_FAILURE(status)) { + dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n"); + kfree(acpi_gpio); + return; + } + + acpi_gpiochip_request_interrupts(acpi_gpio); } void acpi_gpiochip_remove(struct gpio_chip *chip) { - acpi_gpiochip_free_interrupts(chip); + struct acpi_gpio_chip *acpi_gpio; + acpi_handle handle; + acpi_status status; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio); + if (ACPI_FAILURE(status)) { + dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n"); + return; + } + + acpi_gpiochip_free_interrupts(acpi_gpio); + + acpi_detach_data(handle, acpi_gpio_chip_dh); + kfree(acpi_gpio); } -- cgit v1.1 From 4b01a14bac73352a9c7d7850ea4111fcb0c0a5bf Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 10 Mar 2014 14:54:52 +0200 Subject: gpio / ACPI: Rename acpi_gpio_evt_pin to acpi_gpio_event In order to consolidate _Exx, _Lxx and _EVT to use the same structure make the structure name to reflect that we are dealing with any event, not just _EVT. This is just rename, no functional changes. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 5c0cf1d..be09e75 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -19,16 +19,16 @@ #include "gpiolib.h" -struct acpi_gpio_evt_pin { +struct acpi_gpio_event { struct list_head node; - acpi_handle *evt_handle; + acpi_handle handle; unsigned int pin; unsigned int irq; }; struct acpi_gpio_chip { struct gpio_chip *chip; - struct list_head evt_pins; + struct list_head events; }; static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) @@ -79,9 +79,9 @@ static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) { - struct acpi_gpio_evt_pin *evt_pin = data; + struct acpi_gpio_event *event = data; - acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin); + acpi_execute_simple_method(event->handle, NULL, event->pin); return IRQ_HANDLED; } @@ -119,7 +119,7 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) if (!handle) return; - INIT_LIST_HEAD(&acpi_gpio->evt_pins); + INIT_LIST_HEAD(&acpi_gpio->events); /* * If a GPIO interrupt has an ACPI event handler method, or _EVT is @@ -157,22 +157,22 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) } } if (!handler) { - struct acpi_gpio_evt_pin *evt_pin; + struct acpi_gpio_event *event; status = acpi_get_handle(handle, "_EVT", &evt_handle); if (ACPI_FAILURE(status)) continue - evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL); - if (!evt_pin) + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) continue; - list_add_tail(&evt_pin->node, &acpi_gpio->evt_pins); - evt_pin->evt_handle = evt_handle; - evt_pin->pin = pin; - evt_pin->irq = irq; + list_add_tail(&event->node, &acpi_gpio->events); + event->handle = evt_handle; + event->pin = pin; + event->irq = irq; handler = acpi_gpio_irq_handler_evt; - data = evt_pin; + data = event; } if (!handler) continue; @@ -199,17 +199,16 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) */ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) { - struct acpi_gpio_evt_pin *evt_pin, *ep; + struct acpi_gpio_event *event, *ep; struct gpio_chip *chip = acpi_gpio->chip; if (!chip->dev || !chip->to_irq) return; - list_for_each_entry_safe_reverse(evt_pin, ep, &acpi_gpio->evt_pins, - node) { - devm_free_irq(chip->dev, evt_pin->irq, evt_pin); - list_del(&evt_pin->node); - kfree(evt_pin); + list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { + devm_free_irq(chip->dev, event->irq, event); + list_del(&event->node); + kfree(event); } } -- cgit v1.1 From 6072b9dcf97870c9e840ad91862da7ff8ed680ee Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 10 Mar 2014 14:54:53 +0200 Subject: gpio / ACPI: Rework ACPI GPIO event handling The current ACPI GPIO event handling code was never tested against real hardware with functioning GPIO triggered events (at the time such hardware wasn't available). Thus it misses certain things like requesting the GPIOs properly, passing correct flags to the interrupt handler and so on. This patch reworks ACPI GPIO event handling so that we: 1) Use struct acpi_gpio_event for all GPIO signaled events. 2) Switch to use GPIO descriptor API and request GPIOs by calling gpiochip_request_own_desc() that we added in a previous patch. 3) Pass proper flags from ACPI GPIO resource to request_threaded_irq(). Also instead of open-coding the _AEI iteration loop we can use acpi_walk_resources(). This simplifies the code a bit and fixes memory leak that was caused by missing kfree() for buffer returned by acpi_get_event_resources(). Since the remove path now calls gpiochip_free_own_desc() which takes GPIO spinlock we need to call acpi_gpiochip_remove() outside of that lock (analogous to acpi_gpiochip_add() path where the lock is released before those funtions are called). Signed-off-by: Mika Westerberg Reviewed-by: Rafael J. Wysocki Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 214 ++++++++++++++++++++++++++------------------ drivers/gpio/gpiolib.c | 3 +- 2 files changed, 131 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index be09e75..092ea4e 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -70,9 +70,9 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) { - acpi_handle handle = data; + struct acpi_gpio_event *event = data; - acpi_evaluate_object(handle, NULL, NULL, NULL); + acpi_evaluate_object(event->handle, NULL, NULL, NULL); return IRQ_HANDLED; } @@ -91,111 +91,148 @@ static void acpi_gpio_chip_dh(acpi_handle handle, void *data) /* The address of this function is used as a key. */ } -/** - * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events - * @acpi_gpio: ACPI GPIO chip - * - * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are - * handled by ACPI event methods which need to be called from the GPIO - * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which - * gpio pins have acpi event methods and assigns interrupt handlers that calls - * the acpi event methods for those pins. - */ -static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) +static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, + void *context) { - struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + struct acpi_gpio_chip *acpi_gpio = context; struct gpio_chip *chip = acpi_gpio->chip; - struct acpi_resource *res; + struct acpi_resource_gpio *agpio; acpi_handle handle, evt_handle; - acpi_status status; - unsigned int pin; - int irq, ret; - char ev_name[5]; + struct acpi_gpio_event *event; + irq_handler_t handler = NULL; + struct gpio_desc *desc; + unsigned long irqflags; + int ret, pin, irq; - if (!chip->dev || !chip->to_irq) - return; + if (ares->type != ACPI_RESOURCE_TYPE_GPIO) + return AE_OK; + + agpio = &ares->data.gpio; + if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) + return AE_OK; handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; + pin = agpio->pin_table[0]; + + if (pin <= 255) { + char ev_name[5]; + sprintf(ev_name, "_%c%02X", + agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L', + pin); + if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle))) + handler = acpi_gpio_irq_handler; + } + if (!handler) { + if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle))) + handler = acpi_gpio_irq_handler_evt; + } + if (!handler) + return AE_BAD_PARAMETER; - INIT_LIST_HEAD(&acpi_gpio->events); + desc = gpiochip_get_desc(chip, pin); + if (IS_ERR(desc)) { + dev_err(chip->dev, "Failed to get GPIO descriptor\n"); + return AE_ERROR; + } - /* - * If a GPIO interrupt has an ACPI event handler method, or _EVT is - * present, set up an interrupt handler that calls the ACPI event - * handler. - */ - for (res = buf.pointer; - res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); - res = ACPI_NEXT_RESOURCE(res)) { - irq_handler_t handler = NULL; - void *data; - - if (res->type != ACPI_RESOURCE_TYPE_GPIO || - res->data.gpio.connection_type != - ACPI_RESOURCE_GPIO_TYPE_INT) - continue; + ret = gpiochip_request_own_desc(desc, "ACPI:Event"); + if (ret) { + dev_err(chip->dev, "Failed to request GPIO\n"); + return AE_ERROR; + } - pin = res->data.gpio.pin_table[0]; - if (pin > chip->ngpio) - continue; + gpiod_direction_input(desc); - irq = chip->to_irq(chip, pin); - if (irq < 0) - continue; + ret = gpiod_lock_as_irq(desc); + if (ret) { + dev_err(chip->dev, "Failed to lock GPIO as interrupt\n"); + goto fail_free_desc; + } - if (pin <= 255) { - acpi_handle ev_handle; + irq = gpiod_to_irq(desc); + if (irq < 0) { + dev_err(chip->dev, "Failed to translate GPIO to IRQ\n"); + goto fail_unlock_irq; + } - sprintf(ev_name, "_%c%02X", - res->data.gpio.triggering ? 'E' : 'L', pin); - status = acpi_get_handle(handle, ev_name, &ev_handle); - if (ACPI_SUCCESS(status)) { - handler = acpi_gpio_irq_handler; - data = ev_handle; - } + irqflags = IRQF_ONESHOT; + if (agpio->triggering == ACPI_LEVEL_SENSITIVE) { + if (agpio->polarity == ACPI_ACTIVE_HIGH) + irqflags |= IRQF_TRIGGER_HIGH; + else + irqflags |= IRQF_TRIGGER_LOW; + } else { + switch (agpio->polarity) { + case ACPI_ACTIVE_HIGH: + irqflags |= IRQF_TRIGGER_RISING; + break; + case ACPI_ACTIVE_LOW: + irqflags |= IRQF_TRIGGER_FALLING; + break; + default: + irqflags |= IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING; + break; } - if (!handler) { - struct acpi_gpio_event *event; - - status = acpi_get_handle(handle, "_EVT", &evt_handle); - if (ACPI_FAILURE(status)) - continue + } - event = kzalloc(sizeof(*event), GFP_KERNEL); - if (!event) - continue; + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + goto fail_unlock_irq; - list_add_tail(&event->node, &acpi_gpio->events); - event->handle = evt_handle; - event->pin = pin; - event->irq = irq; - handler = acpi_gpio_irq_handler_evt; - data = event; - } - if (!handler) - continue; + event->handle = evt_handle; + event->irq = irq; + event->pin = pin; - /* Assume BIOS sets the triggering, so no flags */ - ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, - 0, "GPIO-signaled-ACPI-event", - data); - if (ret) - dev_err(chip->dev, - "Failed to request IRQ %d ACPI event handler\n", - irq); + ret = request_threaded_irq(event->irq, NULL, handler, irqflags, + "ACPI:Event", event); + if (ret) { + dev_err(chip->dev, "Failed to setup interrupt handler for %d\n", + event->irq); + goto fail_free_event; } + + list_add_tail(&event->node, &acpi_gpio->events); + return AE_OK; + +fail_free_event: + kfree(event); +fail_unlock_irq: + gpiod_unlock_as_irq(desc); +fail_free_desc: + gpiochip_free_own_desc(desc); + + return AE_ERROR; } /** - * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. + * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events * @acpi_gpio: ACPI GPIO chip * - * Free interrupts associated with the _EVT method for the given GPIO chip. + * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are + * handled by ACPI event methods which need to be called from the GPIO + * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which + * gpio pins have acpi event methods and assigns interrupt handlers that calls + * the acpi event methods for those pins. + */ +static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) +{ + struct gpio_chip *chip = acpi_gpio->chip; + + if (!chip->dev || !chip->to_irq) + return; + + INIT_LIST_HEAD(&acpi_gpio->events); + acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI", + acpi_gpiochip_request_interrupt, acpi_gpio); +} + +/** + * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts. + * @acpi_gpio: ACPI GPIO chip * - * The remaining ACPI event interrupts associated with the chip are freed - * automatically. + * Free interrupts associated with GPIO ACPI event method for the given + * GPIO chip. */ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) { @@ -206,7 +243,14 @@ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) return; list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { - devm_free_irq(chip->dev, event->irq, event); + struct gpio_desc *desc; + + free_irq(event->irq, event); + desc = gpiochip_get_desc(chip, event->pin); + if (WARN_ON(IS_ERR(desc))) + continue; + gpiod_unlock_as_irq(desc); + gpiochip_free_own_desc(desc); list_del(&event->node); kfree(event); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 8fbc67a..3707930 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1266,11 +1266,12 @@ int gpiochip_remove(struct gpio_chip *chip) int status = 0; unsigned id; + acpi_gpiochip_remove(chip); + spin_lock_irqsave(&gpio_lock, flags); gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); - acpi_gpiochip_remove(chip); for (id = 0; id < chip->ngpio; id++) { if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { -- cgit v1.1 From 23600969ff137cf4c3bc9098f77e381de334e3f7 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 11 Mar 2014 15:52:09 +0900 Subject: gpio: clamp returned values to the boolean range Nothing prevents GPIO drivers from returning values outside the boolean range, and as it turns out a few drivers are actually doing so. These values were passed as-is to unsuspecting consumers and created confusion. This patch makes the internal _gpiod_get_raw_value() function return a bool, effectively clamping the GPIO value to the boolean range no matter what the driver does. While we are at it, we also change the value parameter of _gpiod_set_raw_value() to bool type before drivers start doing funny things with it as well. Another way to fix this would be to change the prototypes of the driver interface to use bool directly, but this would require a huge cross-systems patch so this simpler solution is preferred. Changes since v1: - Change local variable type to bool as well, use boolean values in code - Also change prototype of open drain/open source setting functions since they are only called from _gpiod_set_raw_value() This probably calls for a larger booleanization of gpiolib, but let's keep that for a latter change - right now we need to address the issue of non-boolean values returned by drivers. Signed-off-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 3707930..584d2b4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2005,15 +2005,15 @@ EXPORT_SYMBOL_GPL(gpiod_is_active_low); * that the GPIO was actually requested. */ -static int _gpiod_get_raw_value(const struct gpio_desc *desc) +static bool _gpiod_get_raw_value(const struct gpio_desc *desc) { struct gpio_chip *chip; - int value; + bool value; int offset; chip = desc->chip; offset = gpio_chip_hwgpio(desc); - value = chip->get ? chip->get(chip, offset) : 0; + value = chip->get ? chip->get(chip, offset) : false; trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } @@ -2069,7 +2069,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) +static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value) { int err = 0; struct gpio_chip *chip = desc->chip; @@ -2096,7 +2096,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) +static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value) { int err = 0; struct gpio_chip *chip = desc->chip; @@ -2118,7 +2118,7 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) __func__, err); } -static void _gpiod_set_raw_value(struct gpio_desc *desc, int value) +static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value) { struct gpio_chip *chip; -- cgit v1.1 From 473ed7be0da041275d57ab0bde1c21a6f23e637f Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Fri, 14 Mar 2014 17:58:07 +0200 Subject: gpio / ACPI: Add support for ACPI GPIO operation regions GPIO operation regions is a new feature introduced in ACPI 5.0 specification. This feature adds a way for platform ASL code to call back to OS GPIO driver and toggle GPIO pins. An example ASL code from Lenovo Miix 2 tablet with only relevant part listed: Device (\_SB.GPO0) { Name (AVBL, Zero) Method (_REG, 2, NotSerialized) { If (LEqual (Arg0, 0x08)) { // Marks the region available Store (Arg1, AVBL) } } OperationRegion (GPOP, GeneralPurposeIo, Zero, 0x0C) Field (GPOP, ByteAcc, NoLock, Preserve) { Connection ( GpioIo (Exclusive, PullDefault, 0, 0, IoRestrictionOutputOnly, "\\_SB.GPO0", 0x00, ResourceConsumer,,) { 0x003B } ), SHD3, 1, } } Device (SHUB) { Method (_PS0, 0, Serialized) { If (LEqual (\_SB.GPO0.AVBL, One)) { Store (One, \_SB.GPO0.SHD3) Sleep (0x32) } } Method (_PS3, 0, Serialized) { If (LEqual (\_SB.GPO0.AVBL, One)) { Store (Zero, \_SB.GPO0.SHD3) } } } How this works is that whenever _PS0 or _PS3 method is run (typically when SHUB device is transitioned to D0 or D3 respectively), ASL code checks if the GPIO operation region is available (\_SB.GPO0.AVBL). If it is we go and store either 0 or 1 to \_SB.GPO0.SHD3. Now, when ACPICA notices ACPI GPIO operation region access (the store above) it will call acpi_gpio_adr_space_handler() that then toggles the GPIO accordingly using standard gpiolib interfaces. Implement the support by registering GPIO operation region handlers for all GPIO devices that have an ACPI handle. First time the GPIO is used by the ASL code we make sure that the GPIO stays requested until the GPIO chip driver itself is unloaded. If we find out that the GPIO is already requested we just toggle it according to the value got from ASL code. Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 163 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 092ea4e..bf0f8b4 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "gpiolib.h" @@ -26,7 +27,20 @@ struct acpi_gpio_event { unsigned int irq; }; +struct acpi_gpio_connection { + struct list_head node; + struct gpio_desc *desc; +}; + struct acpi_gpio_chip { + /* + * ACPICA requires that the first field of the context parameter + * passed to acpi_install_address_space_handler() is large enough + * to hold struct acpi_connection_info. + */ + struct acpi_connection_info conn_info; + struct list_head conns; + struct mutex conn_lock; struct gpio_chip *chip; struct list_head events; }; @@ -334,6 +348,153 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); } +static acpi_status +acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, + u32 bits, u64 *value, void *handler_context, + void *region_context) +{ + struct acpi_gpio_chip *achip = region_context; + struct gpio_chip *chip = achip->chip; + struct acpi_resource_gpio *agpio; + struct acpi_resource *ares; + acpi_status status; + bool pull_up; + int i; + + status = acpi_buffer_to_resource(achip->conn_info.connection, + achip->conn_info.length, &ares); + if (ACPI_FAILURE(status)) + return status; + + if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) { + ACPI_FREE(ares); + return AE_BAD_PARAMETER; + } + + agpio = &ares->data.gpio; + pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP; + + if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT && + function == ACPI_WRITE)) { + ACPI_FREE(ares); + return AE_BAD_PARAMETER; + } + + for (i = 0; i < agpio->pin_table_length; i++) { + unsigned pin = agpio->pin_table[i]; + struct acpi_gpio_connection *conn; + struct gpio_desc *desc; + bool found; + + desc = gpiochip_get_desc(chip, pin); + if (IS_ERR(desc)) { + status = AE_ERROR; + goto out; + } + + mutex_lock(&achip->conn_lock); + + found = false; + list_for_each_entry(conn, &achip->conns, node) { + if (conn->desc == desc) { + found = true; + break; + } + } + if (!found) { + int ret; + + ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion"); + if (ret) { + status = AE_ERROR; + mutex_unlock(&achip->conn_lock); + goto out; + } + + switch (agpio->io_restriction) { + case ACPI_IO_RESTRICT_INPUT: + gpiod_direction_input(desc); + break; + case ACPI_IO_RESTRICT_OUTPUT: + /* + * ACPI GPIO resources don't contain an + * initial value for the GPIO. Therefore we + * deduce that value from the pull field + * instead. If the pin is pulled up we + * assume default to be high, otherwise + * low. + */ + gpiod_direction_output(desc, pull_up); + break; + default: + /* + * Assume that the BIOS has configured the + * direction and pull accordingly. + */ + break; + } + + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) { + status = AE_NO_MEMORY; + gpiochip_free_own_desc(desc); + mutex_unlock(&achip->conn_lock); + goto out; + } + + conn->desc = desc; + list_add_tail(&conn->node, &achip->conns); + } + + mutex_unlock(&achip->conn_lock); + + if (function == ACPI_WRITE) + gpiod_set_raw_value(desc, !!((1 << i) & *value)); + else + *value |= gpiod_get_raw_value(desc) << i; + } + +out: + ACPI_FREE(ares); + return status; +} + +static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip) +{ + struct gpio_chip *chip = achip->chip; + acpi_handle handle = ACPI_HANDLE(chip->dev); + acpi_status status; + + INIT_LIST_HEAD(&achip->conns); + mutex_init(&achip->conn_lock); + status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO, + acpi_gpio_adr_space_handler, + NULL, achip); + if (ACPI_FAILURE(status)) + dev_err(chip->dev, "Failed to install GPIO OpRegion handler\n"); +} + +static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip) +{ + struct gpio_chip *chip = achip->chip; + acpi_handle handle = ACPI_HANDLE(chip->dev); + struct acpi_gpio_connection *conn, *tmp; + acpi_status status; + + status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO, + acpi_gpio_adr_space_handler); + if (ACPI_FAILURE(status)) { + dev_err(chip->dev, "Failed to remove GPIO OpRegion handler\n"); + return; + } + + list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) { + gpiochip_free_own_desc(conn->desc); + list_del(&conn->node); + kfree(conn); + } +} + void acpi_gpiochip_add(struct gpio_chip *chip) { struct acpi_gpio_chip *acpi_gpio; @@ -361,6 +522,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip) } acpi_gpiochip_request_interrupts(acpi_gpio); + acpi_gpiochip_request_regions(acpi_gpio); } void acpi_gpiochip_remove(struct gpio_chip *chip) @@ -379,6 +541,7 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) return; } + acpi_gpiochip_free_regions(acpi_gpio); acpi_gpiochip_free_interrupts(acpi_gpio); acpi_detach_data(handle, acpi_gpio_chip_dh); -- cgit v1.1 From 57ef04288abd27a717287a652d324f95cb77c3c6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 14 Mar 2014 18:16:20 +0100 Subject: gpio: switch drivers to use new callback This switches all GPIO and pin control drivers with irqchips that were using .startup() and .shutdown() callbacks to lock GPIO lines for IRQ usage over to using the .request_resources() and .release_resources() callbacks just introduced into the irqchip vtable. Cc: Thomas Gleixner Cc: Jean-Jacques Hiblot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adnp.c | 15 +++++++-------- drivers/gpio/gpio-bcm-kona.c | 14 +++++++------- drivers/gpio/gpio-dwapb.c | 14 +++++++------- drivers/gpio/gpio-em.c | 14 +++++++------- drivers/gpio/gpio-intel-mid.c | 14 +++++++------- drivers/gpio/gpio-lynxpoint.c | 14 +++++++------- drivers/gpio/gpio-mcp23s08.c | 14 +++++++------- drivers/gpio/gpio-pl061.c | 14 +++++++------- drivers/pinctrl/pinctrl-adi2.c | 1 + drivers/pinctrl/pinctrl-baytrail.c | 14 +++++++------- drivers/pinctrl/pinctrl-msm.c | 11 +++++------ drivers/pinctrl/pinctrl-nomadik.c | 25 +++++++++++++++++++++---- drivers/pinctrl/sirf/pinctrl-sirf.c | 14 +++++++------- 13 files changed, 97 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 6fc6206..b2239d6 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -408,24 +408,23 @@ static void adnp_irq_bus_unlock(struct irq_data *data) mutex_unlock(&adnp->irq_lock); } -static unsigned int adnp_irq_startup(struct irq_data *data) +static int adnp_irq_reqres(struct irq_data *data) { struct adnp *adnp = irq_data_get_irq_chip_data(data); - if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) + if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) { dev_err(adnp->gpio.dev, "unable to lock HW IRQ %lu for IRQ\n", data->hwirq); - /* Satisfy the .enable semantics by unmasking the line */ - adnp_irq_unmask(data); + return -EINVAL; + } return 0; } -static void adnp_irq_shutdown(struct irq_data *data) +static void adnp_irq_relres(struct irq_data *data) { struct adnp *adnp = irq_data_get_irq_chip_data(data); - adnp_irq_mask(data); gpio_unlock_as_irq(&adnp->gpio, data->hwirq); } @@ -436,8 +435,8 @@ static struct irq_chip adnp_irq_chip = { .irq_set_type = adnp_irq_set_type, .irq_bus_lock = adnp_irq_bus_lock, .irq_bus_sync_unlock = adnp_irq_bus_unlock, - .irq_startup = adnp_irq_startup, - .irq_shutdown = adnp_irq_shutdown, + .irq_request_resources = adnp_irq_reqres, + .irq_release_resources = adnp_irq_relres, }; static int adnp_irq_map(struct irq_domain *domain, unsigned int irq, diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 5622cfb..3f6b33c 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -466,23 +466,23 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } -static unsigned int bcm_kona_gpio_irq_startup(struct irq_data *d) +static int bcm_kona_gpio_irq_reqres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) + if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) { dev_err(kona_gpio->gpio_chip.dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); - bcm_kona_gpio_irq_unmask(d); + return -EINVAL; + } return 0; } -static void bcm_kona_gpio_irq_shutdown(struct irq_data *d) +static void bcm_kona_gpio_irq_relres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - bcm_kona_gpio_irq_mask(d); gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq); } @@ -492,8 +492,8 @@ static struct irq_chip bcm_gpio_irq_chip = { .irq_mask = bcm_kona_gpio_irq_mask, .irq_unmask = bcm_kona_gpio_irq_unmask, .irq_set_type = bcm_kona_gpio_irq_set_type, - .irq_startup = bcm_kona_gpio_irq_startup, - .irq_shutdown = bcm_kona_gpio_irq_shutdown, + .irq_request_resources = bcm_kona_gpio_irq_reqres, + .irq_release_resources = bcm_kona_gpio_irq_relres, }; static struct __initconst of_device_id bcm_kona_gpio_of_match[] = { diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 2797fbb..ed5711f 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -136,26 +136,26 @@ static void dwapb_irq_disable(struct irq_data *d) spin_unlock_irqrestore(&bgc->lock, flags); } -static unsigned int dwapb_irq_startup(struct irq_data *d) +static int dwapb_irq_reqres(struct irq_data *d) { struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); struct dwapb_gpio *gpio = igc->private; struct bgpio_chip *bgc = &gpio->ports[0].bgc; - if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) { dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - dwapb_irq_enable(d); + return -EINVAL; + } return 0; } -static void dwapb_irq_shutdown(struct irq_data *d) +static void dwapb_irq_relres(struct irq_data *d) { struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); struct dwapb_gpio *gpio = igc->private; struct bgpio_chip *bgc = &gpio->ports[0].bgc; - dwapb_irq_disable(d); gpio_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d)); } @@ -255,8 +255,8 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, ct->chip.irq_set_type = dwapb_irq_set_type; ct->chip.irq_enable = dwapb_irq_enable; ct->chip.irq_disable = dwapb_irq_disable; - ct->chip.irq_startup = dwapb_irq_startup; - ct->chip.irq_shutdown = dwapb_irq_shutdown; + ct->chip.irq_request_resources = dwapb_irq_reqres; + ct->chip.irq_release_resources = dwapb_irq_relres; ct->regs.ack = GPIO_PORTA_EOI; ct->regs.mask = GPIO_INTMASK; diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 1e98a98..8765bd6 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -99,23 +99,23 @@ static void em_gio_irq_enable(struct irq_data *d) em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d))); } -static unsigned int em_gio_irq_startup(struct irq_data *d) +static int em_gio_irq_reqres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) { dev_err(p->gpio_chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - em_gio_irq_enable(d); + return -EINVAL; + } return 0; } -static void em_gio_irq_shutdown(struct irq_data *d) +static void em_gio_irq_relres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); - em_gio_irq_disable(d); gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)); } @@ -359,8 +359,8 @@ static int em_gio_probe(struct platform_device *pdev) 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; - irq_chip->irq_startup = em_gio_irq_startup; - irq_chip->irq_shutdown = em_gio_irq_shutdown; + irq_chip->irq_request_resources = em_gio_irq_reqres; + irq_chip->irq_release_resources = em_gio_irq_relres; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index 3a34bb15..118a6bf 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -231,23 +231,23 @@ static void intel_mid_irq_mask(struct irq_data *d) { } -static unsigned int intel_mid_irq_startup(struct irq_data *d) +static int intel_mid_irq_reqres(struct irq_data *d) { struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) { dev_err(priv->chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - intel_mid_irq_unmask(d); + return -EINVAL; + } return 0; } -static void intel_mid_irq_shutdown(struct irq_data *d) +static void intel_mid_irq_relres(struct irq_data *d) { struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); - intel_mid_irq_mask(d); gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d)); } @@ -256,8 +256,8 @@ static struct irq_chip intel_mid_irqchip = { .irq_mask = intel_mid_irq_mask, .irq_unmask = intel_mid_irq_unmask, .irq_set_type = intel_mid_irq_type, - .irq_startup = intel_mid_irq_startup, - .irq_shutdown = intel_mid_irq_shutdown, + .irq_request_resources = intel_mid_irq_reqres, + .irq_release_resources = intel_mid_irq_relres, }; static const struct intel_mid_gpio_ddata gpio_lincroft = { diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 66b1853..41f79cb 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -301,23 +301,23 @@ static void lp_irq_disable(struct irq_data *d) spin_unlock_irqrestore(&lg->lock, flags); } -static unsigned int lp_irq_startup(struct irq_data *d) +static int lp_irq_reqres(struct irq_data *d) { struct lp_gpio *lg = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) { dev_err(lg->chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - lp_irq_enable(d); + return -EINVAL; + } return 0; } -static void lp_irq_shutdown(struct irq_data *d) +static void lp_irq_relres(struct irq_data *d) { struct lp_gpio *lg = irq_data_get_irq_chip_data(d); - lp_irq_disable(d); gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d)); } @@ -328,8 +328,8 @@ static struct irq_chip lp_irqchip = { .irq_enable = lp_irq_enable, .irq_disable = lp_irq_disable, .irq_set_type = lp_irq_type, - .irq_startup = lp_irq_startup, - .irq_shutdown = lp_irq_shutdown, + .irq_request_resources = lp_irq_reqres, + .irq_release_resources = lp_irq_relres, .flags = IRQCHIP_SKIP_SET_WAKE, }; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index e1734c1..99a6831 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -440,24 +440,24 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data) mutex_unlock(&mcp->irq_lock); } -static unsigned int mcp23s08_irq_startup(struct irq_data *data) +static int mcp23s08_irq_reqres(struct irq_data *data) { struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) + if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) { dev_err(mcp->chip.dev, "unable to lock HW IRQ %lu for IRQ usage\n", data->hwirq); + return -EINVAL; + } - mcp23s08_irq_unmask(data); return 0; } -static void mcp23s08_irq_shutdown(struct irq_data *data) +static void mcp23s08_irq_relres(struct irq_data *data) { struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - mcp23s08_irq_mask(data); gpio_unlock_as_irq(&mcp->chip, data->hwirq); } @@ -468,8 +468,8 @@ static struct irq_chip mcp23s08_irq_chip = { .irq_set_type = mcp23s08_irq_set_type, .irq_bus_lock = mcp23s08_irq_bus_lock, .irq_bus_sync_unlock = mcp23s08_irq_bus_unlock, - .irq_startup = mcp23s08_irq_startup, - .irq_shutdown = mcp23s08_irq_shutdown, + .irq_request_resources = mcp23s08_irq_reqres, + .irq_release_resources = mcp23s08_irq_relres, }; static int mcp23s08_irq_setup(struct mcp23s08 *mcp) diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 391766e..d2a0ad5 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -233,23 +233,23 @@ static void pl061_irq_unmask(struct irq_data *d) spin_unlock(&chip->lock); } -static unsigned int pl061_irq_startup(struct irq_data *d) +static int pl061_irq_reqres(struct irq_data *d) { struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&chip->gc, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&chip->gc, irqd_to_hwirq(d))) { dev_err(chip->gc.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - pl061_irq_unmask(d); + return -EINVAL; + } return 0; } -static void pl061_irq_shutdown(struct irq_data *d) +static void pl061_irq_relres(struct irq_data *d) { struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - pl061_irq_mask(d); gpio_unlock_as_irq(&chip->gc, irqd_to_hwirq(d)); } @@ -258,8 +258,8 @@ static struct irq_chip pl061_irqchip = { .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, - .irq_startup = pl061_irq_startup, - .irq_shutdown = pl061_irq_shutdown, + .irq_request_resources = pl061_irq_reqres, + .irq_release_resources = pl061_irq_relres, }; static int pl061_irq_map(struct irq_domain *d, unsigned int irq, diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c index 7a39562..94138bc 100644 --- a/drivers/pinctrl/pinctrl-adi2.c +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -324,6 +324,7 @@ static unsigned int adi_gpio_irq_startup(struct irq_data *d) if (!port) { pr_err("GPIO IRQ %d :Not exist\n", d->irq); + /* FIXME: negative return code will be ignored */ return -ENODEV; } diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c index 665b96b..9a4abd9 100644 --- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -371,23 +371,23 @@ static void byt_irq_mask(struct irq_data *d) { } -static unsigned int byt_irq_startup(struct irq_data *d) +static int byt_irq_reqres(struct irq_data *d) { struct byt_gpio *vg = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d))) { dev_err(vg->chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - byt_irq_unmask(d); + return -EINVAL; + } return 0; } -static void byt_irq_shutdown(struct irq_data *d) +static void byt_irq_relres(struct irq_data *d) { struct byt_gpio *vg = irq_data_get_irq_chip_data(d); - byt_irq_mask(d); gpio_unlock_as_irq(&vg->chip, irqd_to_hwirq(d)); } @@ -396,8 +396,8 @@ static struct irq_chip byt_irqchip = { .irq_mask = byt_irq_mask, .irq_unmask = byt_irq_unmask, .irq_set_type = byt_irq_type, - .irq_startup = byt_irq_startup, - .irq_shutdown = byt_irq_shutdown, + .irq_request_resources = byt_irq_reqres, + .irq_release_resources = byt_irq_relres, }; static void byt_gpio_irq_init_hw(struct byt_gpio *vg) diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c index ef2bf31..81ecd6b 100644 --- a/drivers/pinctrl/pinctrl-msm.c +++ b/drivers/pinctrl/pinctrl-msm.c @@ -805,23 +805,22 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) return 0; } -static unsigned int msm_gpio_irq_startup(struct irq_data *d) +static int msm_gpio_irq_reqres(struct irq_data *d) { struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); if (gpio_lock_as_irq(&pctrl->chip, d->hwirq)) { dev_err(pctrl->dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); + return -EINVAL; } - msm_gpio_irq_unmask(d); return 0; } -static void msm_gpio_irq_shutdown(struct irq_data *d) +static void msm_gpio_irq_relres(struct irq_data *d) { struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d); - msm_gpio_irq_mask(d); gpio_unlock_as_irq(&pctrl->chip, d->hwirq); } @@ -832,8 +831,8 @@ static struct irq_chip msm_gpio_irq_chip = { .irq_ack = msm_gpio_irq_ack, .irq_set_type = msm_gpio_irq_set_type, .irq_set_wake = msm_gpio_irq_set_wake, - .irq_startup = msm_gpio_irq_startup, - .irq_shutdown = msm_gpio_irq_shutdown, + .irq_request_resources = msm_gpio_irq_reqres, + .irq_release_resources = msm_gpio_irq_relres, }; static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 53a1111..2ea3f37 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -848,10 +848,6 @@ static unsigned int nmk_gpio_irq_startup(struct irq_data *d) { struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) - dev_err(nmk_chip->chip.dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); clk_enable(nmk_chip->clk); nmk_gpio_irq_unmask(d); return 0; @@ -863,6 +859,25 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d) nmk_gpio_irq_mask(d); clk_disable(nmk_chip->clk); +} + +static int nmk_gpio_irq_reqres(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) { + dev_err(nmk_chip->chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void nmk_gpio_irq_relres(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq); } @@ -875,6 +890,8 @@ static struct irq_chip nmk_gpio_irq_chip = { .irq_set_wake = nmk_gpio_irq_set_wake, .irq_startup = nmk_gpio_irq_startup, .irq_shutdown = nmk_gpio_irq_shutdown, + .irq_request_resources = nmk_gpio_irq_reqres, + .irq_release_resources = nmk_gpio_irq_relres, .flags = IRQCHIP_MASK_ON_SUSPEND, }; diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 617a491..3ce6e25 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -594,23 +594,23 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type) return 0; } -static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d) +static int sirfsoc_gpio_irq_reqres(struct irq_data *d) { struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE)) + if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE)) { dev_err(bank->chip.gc.dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); - sirfsoc_gpio_irq_unmask(d); + return -EINVAL; + } return 0; } -static void sirfsoc_gpio_irq_shutdown(struct irq_data *d) +static void sirfsoc_gpio_irq_relres(struct irq_data *d) { struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d); - sirfsoc_gpio_irq_mask(d); gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE); } @@ -620,8 +620,8 @@ static struct irq_chip sirfsoc_irq_chip = { .irq_mask = sirfsoc_gpio_irq_mask, .irq_unmask = sirfsoc_gpio_irq_unmask, .irq_set_type = sirfsoc_gpio_irq_type, - .irq_startup = sirfsoc_gpio_irq_startup, - .irq_shutdown = sirfsoc_gpio_irq_shutdown, + .irq_request_resources = sirfsoc_gpio_irq_reqres, + .irq_release_resources = sirfsoc_gpio_irq_relres, }; static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) -- cgit v1.1 From 8c1d50a6a7aa29a45a43b6073cf540eb7ee028a5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 14 Mar 2014 18:24:30 +0100 Subject: pinctrl: coh901: move irq line locking to resource callbacks This switches the COH901 GPIO driver over to using the .request_resources() and .release_resources() callbacks from the irqchip vtable and separate the calls from the .enable() and .disable() callbacks as the latter cannot really say no to a request, whereas the resource callbacks can. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-coh901.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 162ac0d..749db59 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -529,10 +529,6 @@ static void u300_gpio_irq_enable(struct irq_data *d) dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", d->hwirq, port->name, offset); - if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) - dev_err(gpio->dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -551,6 +547,27 @@ static void u300_gpio_irq_disable(struct irq_data *d) val = readl(U300_PIN_REG(offset, ien)); writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); local_irq_restore(flags); +} + +static int u300_gpio_irq_reqres(struct irq_data *d) +{ + struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = port->gpio; + + if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) { + dev_err(gpio->dev, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void u300_gpio_irq_relres(struct irq_data *d) +{ + struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = port->gpio; + gpio_unlock_as_irq(&gpio->chip, d->hwirq); } @@ -559,7 +576,8 @@ static struct irq_chip u300_gpio_irqchip = { .irq_enable = u300_gpio_irq_enable, .irq_disable = u300_gpio_irq_disable, .irq_set_type = u300_gpio_irq_type, - + .irq_request_resources = u300_gpio_irq_reqres, + .irq_release_resources = u300_gpio_irq_relres, }; static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) -- cgit v1.1 From 193385305b71b329b8fbec2c0465d4afd3f946b8 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 16 Mar 2014 09:10:34 +0400 Subject: gpio: generic: Use platform_device_id->driver_data field for driver flags Signed-off-by: Alexander Shiyan Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index d815dd2..b5dff9e 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -488,7 +488,7 @@ static int bgpio_pdev_probe(struct platform_device *pdev) void __iomem *dirout; void __iomem *dirin; unsigned long sz; - unsigned long flags = 0; + unsigned long flags = pdev->id_entry->driver_data; int err; struct bgpio_chip *bgc; struct bgpio_pdata *pdata = dev_get_platdata(dev); @@ -519,9 +519,6 @@ static int bgpio_pdev_probe(struct platform_device *pdev) if (err) return err; - if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be")) - flags |= BGPIOF_BIG_ENDIAN; - bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); if (!bgc) return -ENOMEM; @@ -551,9 +548,14 @@ static int bgpio_pdev_remove(struct platform_device *pdev) } static const struct platform_device_id bgpio_id_table[] = { - { "basic-mmio-gpio", }, - { "basic-mmio-gpio-be", }, - {}, + { + .name = "basic-mmio-gpio", + .driver_data = 0, + }, { + .name = "basic-mmio-gpio-be", + .driver_data = BGPIOF_BIG_ENDIAN, + }, + { } }; MODULE_DEVICE_TABLE(platform, bgpio_id_table); -- cgit v1.1 From 6a8a0c1d87377c6ce97de2fedc0762c2fa8233ac Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Tue, 11 Mar 2014 21:55:14 +0400 Subject: gpio: Driver for SYSCON-based GPIOs SYSCON driver was designed for using memory areas (registers) that are used in several subsystems. There are systems (CPUs) which use bits in one register for various purposes and thus should be handled by various kernel subsystems. This driver allows you to use the individual SYSCON bits as GPIOs. ARM CLPS711X SYSFLG1 input lines has been added as first user of this driver. Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 6 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-syscon.c | 191 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 drivers/gpio/gpio-syscon.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8ca94e1..2e461e4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -290,6 +290,12 @@ config GPIO_STA2X11 Say yes here to support the STA2x11/ConneXt GPIO device. The GPIO module has 128 GPIO pins with alternate functions. +config GPIO_SYSCON + tristate "GPIO based on SYSCON" + depends on MFD_SYSCON && OF + help + Say yes here to support GPIO functionality though SYSCON driver. + config GPIO_TS5500 tristate "TS-5500 DIO blocks and compatibles" depends on TS5500 || COMPILE_TEST diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index aaff7ff..6309aff 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o +obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c new file mode 100644 index 0000000..b50fe12 --- /dev/null +++ b/drivers/gpio/gpio-syscon.c @@ -0,0 +1,191 @@ +/* + * SYSCON GPIO driver + * + * Copyright (C) 2014 Alexander Shiyan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_SYSCON_FEAT_IN BIT(0) +#define GPIO_SYSCON_FEAT_OUT BIT(1) +#define GPIO_SYSCON_FEAT_DIR BIT(2) + +/* SYSCON driver is designed to use 32-bit wide registers */ +#define SYSCON_REG_SIZE (4) +#define SYSCON_REG_BITS (SYSCON_REG_SIZE * 8) + +/** + * struct syscon_gpio_data - Configuration for the device. + * compatible: SYSCON driver compatible string. + * flags: Set of GPIO_SYSCON_FEAT_ flags: + * GPIO_SYSCON_FEAT_IN: GPIOs supports input, + * GPIO_SYSCON_FEAT_OUT: GPIOs supports output, + * GPIO_SYSCON_FEAT_DIR: GPIOs supports switch direction. + * bit_count: Number of bits used as GPIOs. + * dat_bit_offset: Offset (in bits) to the first GPIO bit. + * dir_bit_offset: Optional offset (in bits) to the first bit to switch + * GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag). + */ + +struct syscon_gpio_data { + const char *compatible; + unsigned int flags; + unsigned int bit_count; + unsigned int dat_bit_offset; + unsigned int dir_bit_offset; +}; + +struct syscon_gpio_priv { + struct gpio_chip chip; + struct regmap *syscon; + const struct syscon_gpio_data *data; +}; + +static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct syscon_gpio_priv, chip); +} + +static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + unsigned int val, offs = priv->data->dat_bit_offset + offset; + int ret; + + ret = regmap_read(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val); + if (ret) + return ret; + + return !!(val & BIT(offs % SYSCON_REG_BITS)); +} + +static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + unsigned int offs = priv->data->dat_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), + val ? BIT(offs % SYSCON_REG_BITS) : 0); +} + +static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + + if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { + unsigned int offs = priv->data->dir_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), 0); + } + + return 0; +} + +static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + + if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { + unsigned int offs = priv->data->dir_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), + BIT(offs % SYSCON_REG_BITS)); + } + + syscon_gpio_set(chip, offset, val); + + return 0; +} + +static const struct syscon_gpio_data clps711x_mctrl_gpio = { + /* ARM CLPS711X SYSFLG1 Bits 8-10 */ + .compatible = "cirrus,clps711x-syscon1", + .flags = GPIO_SYSCON_FEAT_IN, + .bit_count = 3, + .dat_bit_offset = 0x40 * 8 + 8, +}; + +static const struct of_device_id syscon_gpio_ids[] = { + { + .compatible = "cirrus,clps711x-mctrl-gpio", + .data = &clps711x_mctrl_gpio, + }, + { } +}; +MODULE_DEVICE_TABLE(of, syscon_gpio_ids); + +static int syscon_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); + struct syscon_gpio_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_id->data; + + priv->syscon = + syscon_regmap_lookup_by_compatible(priv->data->compatible); + if (IS_ERR(priv->syscon)) + return PTR_ERR(priv->syscon); + + priv->chip.dev = dev; + priv->chip.owner = THIS_MODULE; + priv->chip.label = dev_name(dev); + priv->chip.base = -1; + priv->chip.ngpio = priv->data->bit_count; + priv->chip.get = syscon_gpio_get; + if (priv->data->flags & GPIO_SYSCON_FEAT_IN) + priv->chip.direction_input = syscon_gpio_dir_in; + if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) { + priv->chip.set = syscon_gpio_set; + priv->chip.direction_output = syscon_gpio_dir_out; + } + + platform_set_drvdata(pdev, priv); + + return gpiochip_add(&priv->chip); +} + +static int syscon_gpio_remove(struct platform_device *pdev) +{ + struct syscon_gpio_priv *priv = platform_get_drvdata(pdev); + + return gpiochip_remove(&priv->chip); +} + +static struct platform_driver syscon_gpio_driver = { + .driver = { + .name = "gpio-syscon", + .owner = THIS_MODULE, + .of_match_table = syscon_gpio_ids, + }, + .probe = syscon_gpio_probe, + .remove = syscon_gpio_remove, +}; +module_platform_driver(syscon_gpio_driver); + +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("SYSCON GPIO driver"); +MODULE_LICENSE("GPL"); -- cgit v1.1 From 194e15ba00d90a6e8779b9cd87f1feec0d55427f Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 21 Mar 2014 10:24:42 +0100 Subject: pinctrl: nomadik: rename secondary to latent The "secondary irq" in the nomadik pin control driver is actually not secondary (as in: can occur any time alongside the ordinary irq), it is a latent IRQ. It is an IRQ that has occurred when the system was in sleep state and has been cached in a special register flagged from the low power management unit (PRCM). Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-nomadik.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 2ea3f37..41e808d 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -254,7 +254,7 @@ struct nmk_gpio_platform_data { int first_gpio; int first_irq; int num_gpio; - u32 (*get_secondary_status)(unsigned int bank); + u32 (*get_latent_status)(unsigned int bank); void (*set_ioforce)(bool enable); bool supports_sleepmode; }; @@ -266,8 +266,8 @@ struct nmk_gpio_chip { struct clk *clk; unsigned int bank; unsigned int parent_irq; - int secondary_parent_irq; - u32 (*get_secondary_status)(unsigned int bank); + int latent_parent_irq; + u32 (*get_latent_status)(unsigned int bank); void (*set_ioforce)(bool enable); spinlock_t lock; bool sleepmode; @@ -926,11 +926,11 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) __nmk_gpio_irq_handler(irq, desc, status); } -static void nmk_gpio_secondary_irq_handler(unsigned int irq, +static void nmk_gpio_latent_irq_handler(unsigned int irq, struct irq_desc *desc) { struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); - u32 status = nmk_chip->get_secondary_status(nmk_chip->bank); + u32 status = nmk_chip->get_latent_status(nmk_chip->bank); __nmk_gpio_irq_handler(irq, desc, status); } @@ -940,10 +940,10 @@ static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip) irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler); irq_set_handler_data(nmk_chip->parent_irq, nmk_chip); - if (nmk_chip->secondary_parent_irq >= 0) { - irq_set_chained_handler(nmk_chip->secondary_parent_irq, - nmk_gpio_secondary_irq_handler); - irq_set_handler_data(nmk_chip->secondary_parent_irq, nmk_chip); + if (nmk_chip->latent_parent_irq >= 0) { + irq_set_chained_handler(nmk_chip->latent_parent_irq, + nmk_gpio_latent_irq_handler); + irq_set_handler_data(nmk_chip->latent_parent_irq, nmk_chip); } return 0; @@ -1263,7 +1263,7 @@ static int nmk_gpio_probe(struct platform_device *dev) struct gpio_chip *chip; struct resource *res; struct clk *clk; - int secondary_irq; + int latent_irq; void __iomem *base; int irq; int ret; @@ -1287,8 +1287,8 @@ static int nmk_gpio_probe(struct platform_device *dev) if (irq < 0) return irq; - secondary_irq = platform_get_irq(dev, 1); - if (secondary_irq >= 0 && !pdata->get_secondary_status) + latent_irq = platform_get_irq(dev, 1); + if (latent_irq >= 0 && !pdata->get_latent_status) return -EINVAL; res = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -1314,8 +1314,8 @@ static int nmk_gpio_probe(struct platform_device *dev) nmk_chip->addr = base; nmk_chip->chip = nmk_gpio_template; nmk_chip->parent_irq = irq; - nmk_chip->secondary_parent_irq = secondary_irq; - nmk_chip->get_secondary_status = pdata->get_secondary_status; + nmk_chip->latent_parent_irq = latent_irq; + nmk_chip->get_latent_status = pdata->get_latent_status; nmk_chip->set_ioforce = pdata->set_ioforce; nmk_chip->sleepmode = pdata->supports_sleepmode; spin_lock_init(&nmk_chip->lock); -- cgit v1.1 From 8f18bcfcd2bc30cb9a5924a6b4af49c8388bc785 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 21 Mar 2014 10:40:24 +0100 Subject: pinctrl: nomadik: factor in platform data container The old platform data struct is just a leftover from the times when the driver was not probed exclusively from the device tree. Factor this into the general state container and simplify the probe path. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-nomadik.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 41e808d..98a36a0 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -246,19 +246,6 @@ enum nmk_gpio_slpm { NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE, }; -/* - * Platform data to register a block: only the initial gpio/irq number. - */ -struct nmk_gpio_platform_data { - char *name; - int first_gpio; - int first_irq; - int num_gpio; - u32 (*get_latent_status)(unsigned int bank); - void (*set_ioforce)(bool enable); - bool supports_sleepmode; -}; - struct nmk_gpio_chip { struct gpio_chip chip; struct irq_domain *domain; @@ -1257,39 +1244,33 @@ static const struct irq_domain_ops nmk_gpio_irq_simple_ops = { static int nmk_gpio_probe(struct platform_device *dev) { - struct nmk_gpio_platform_data *pdata; struct device_node *np = dev->dev.of_node; struct nmk_gpio_chip *nmk_chip; struct gpio_chip *chip; struct resource *res; struct clk *clk; int latent_irq; + bool supports_sleepmode; void __iomem *base; int irq; int ret; - pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - if (of_get_property(np, "st,supports-sleepmode", NULL)) - pdata->supports_sleepmode = true; + supports_sleepmode = true; + else + supports_sleepmode = false; if (of_property_read_u32(np, "gpio-bank", &dev->id)) { dev_err(&dev->dev, "gpio-bank property not found\n"); return -EINVAL; } - pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP; - pdata->num_gpio = NMK_GPIO_PER_CHIP; - irq = platform_get_irq(dev, 0); if (irq < 0) return irq; + /* It's OK for this IRQ not to be present */ latent_irq = platform_get_irq(dev, 1); - if (latent_irq >= 0 && !pdata->get_latent_status) - return -EINVAL; res = platform_get_resource(dev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&dev->dev, res); @@ -1315,15 +1296,13 @@ static int nmk_gpio_probe(struct platform_device *dev) nmk_chip->chip = nmk_gpio_template; nmk_chip->parent_irq = irq; nmk_chip->latent_parent_irq = latent_irq; - nmk_chip->get_latent_status = pdata->get_latent_status; - nmk_chip->set_ioforce = pdata->set_ioforce; - nmk_chip->sleepmode = pdata->supports_sleepmode; + nmk_chip->sleepmode = supports_sleepmode; spin_lock_init(&nmk_chip->lock); chip = &nmk_chip->chip; - chip->base = pdata->first_gpio; - chip->ngpio = pdata->num_gpio; - chip->label = pdata->name ?: dev_name(&dev->dev); + chip->base = dev->id * NMK_GPIO_PER_CHIP; + chip->ngpio = NMK_GPIO_PER_CHIP; + chip->label = dev_name(&dev->dev); chip->dev = &dev->dev; chip->owner = THIS_MODULE; -- cgit v1.1 From 1425052097b53de841e064dc190a9009480c208c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 25 Mar 2014 10:40:18 +0100 Subject: gpio: add IRQ chip helpers in gpiolib This provides a function gpiochip_irqchip_add() to set up an irqchip for a GPIO controller, and a function gpiochip_set_chained_irqchip() to chain it to a parent irqchip. Most GPIOs are of the type where a number of lines form a cascaded interrupt controller chained onto the primary system interrupt controller (or further down the chain) so let's add this helper and factor the code to request the lines to be used as IRQs, the .to_irq() function and the irqdomain into the core as well. Acked-by: Thomas Gleixner Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 3 + drivers/gpio/gpiolib.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2e461e4..51c7825 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -55,6 +55,9 @@ config GPIO_ACPI def_bool y depends on ACPI +config GPIOLIB_IRQCHIP + bool + config DEBUG_GPIO bool "Debug GPIO calls" depends on DEBUG_KERNEL diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 584d2b4..f41cb4f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1254,6 +1254,9 @@ fail: } EXPORT_SYMBOL_GPL(gpiochip_add); +/* Forward-declaration */ +static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); + /** * gpiochip_remove() - unregister a gpio_chip * @chip: the chip to unregister @@ -1270,6 +1273,7 @@ int gpiochip_remove(struct gpio_chip *chip) spin_lock_irqsave(&gpio_lock, flags); + gpiochip_irqchip_remove(chip); gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); @@ -1339,6 +1343,190 @@ static struct gpio_chip *find_chip_by_name(const char *name) return gpiochip_find((void *)name, gpiochip_match_name); } +#ifdef CONFIG_GPIOLIB_IRQCHIP + +/* + * The following is irqchip helper code for gpiochips. + */ + +/** + * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip + * @gpiochip: the gpiochip to add the irqchip to + * @irqchip: the irqchip to add to the gpiochip + * @parent_irq: the irq number corresponding to the parent IRQ for this + * chained irqchip + * @parent_handler: the parent interrupt handler for the accumulated IRQ + * coming out of the gpiochip + */ +void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + int parent_irq, + irq_flow_handler_t parent_handler) +{ + irq_set_chained_handler(parent_irq, parent_handler); + /* + * The parent irqchip is already using the chip_data for this + * irqchip, so our callbacks simply use the handler_data. + */ + irq_set_handler_data(parent_irq, gpiochip); +} +EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); + +/** + * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip + * @d: the irqdomain used by this irqchip + * @irq: the global irq number used by this GPIO irqchip irq + * @hwirq: the local IRQ/GPIO line offset on this gpiochip + * + * This function will set up the mapping for a certain IRQ line on a + * gpiochip by assigning the gpiochip as chip data, and using the irqchip + * stored inside the gpiochip. + */ +static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct gpio_chip *chip = d->host_data; + + irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); + irq_set_chip_data(irq, chip); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + irq_set_irq_type(irq, chip->irq_default_type); + + return 0; +} + +static const struct irq_domain_ops gpiochip_domain_ops = { + .map = gpiochip_irq_map, + /* Virtually all GPIO irqchips are twocell:ed */ + .xlate = irq_domain_xlate_twocell, +}; + +static int gpiochip_irq_reqres(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(chip, d->hwirq)) { + chip_err(chip, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void gpiochip_irq_relres(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + gpio_unlock_as_irq(chip, d->hwirq); +} + +static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return irq_find_mapping(chip->irqdomain, offset); +} + +/** + * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip + * @gpiochip: the gpiochip to remove the irqchip from + * + * This is called only from gpiochip_remove() + */ +static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) +{ + if (gpiochip->irqdomain) + irq_domain_remove(gpiochip->irqdomain); + + if (gpiochip->irqchip) { + gpiochip->irqchip->irq_request_resources = NULL; + gpiochip->irqchip->irq_release_resources = NULL; + gpiochip->irqchip = NULL; + } +} + +/** + * gpiochip_irqchip_add() - adds an irqchip to a gpiochip + * @gpiochip: the gpiochip to add the irqchip to + * @irqchip: the irqchip to add to the gpiochip + * @first_irq: if not dynamically assigned, the base (first) IRQ to + * allocate gpiochip irqs from + * @handler: the irq handler to use (often a predefined irq core function) + * @type: the default type for IRQs on this irqchip + * + * This function closely associates a certain irqchip with a certain + * gpiochip, providing an irq domain to translate the local IRQs to + * global irqs in the gpiolib core, and making sure that the gpiochip + * is passed as chip data to all related functions. Driver callbacks + * need to use container_of() to get their local state containers back + * from the gpiochip passed as chip data. An irqdomain will be stored + * in the gpiochip that shall be used by the driver to handle IRQ number + * translation. The gpiochip will need to be initialized and registered + * before calling this function. + * + * This function will handle two cell:ed simple IRQs. Everything else + * need to be open coded. + */ +int gpiochip_irqchip_add(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + unsigned int first_irq, + irq_flow_handler_t handler, + unsigned int type) +{ + struct device_node *of_node; + unsigned int offset; + + if (!gpiochip || !irqchip) + return -EINVAL; + + if (!gpiochip->dev) { + pr_err("missing gpiochip .dev parent pointer\n"); + return -EINVAL; + } + of_node = gpiochip->dev->of_node; +#ifdef CONFIG_OF_GPIO + /* + * If the gpiochip has an assigned OF node this takes precendence + * FIXME: get rid of this and use gpiochip->dev->of_node everywhere + */ + if (gpiochip->of_node) + of_node = gpiochip->of_node; +#endif + gpiochip->irqchip = irqchip; + gpiochip->irq_handler = handler; + gpiochip->irq_default_type = type; + gpiochip->to_irq = gpiochip_to_irq; + gpiochip->irqdomain = irq_domain_add_simple(of_node, + gpiochip->ngpio, first_irq, + &gpiochip_domain_ops, gpiochip); + if (!gpiochip->irqdomain) { + gpiochip->irqchip = NULL; + return -EINVAL; + } + irqchip->irq_request_resources = gpiochip_irq_reqres; + irqchip->irq_release_resources = gpiochip_irq_relres; + + /* + * Prepare the mapping since the irqchip shall be orthogonal to + * any gpiochip calls. If the first_irq was zero, this is + * necessary to allocate descriptors for all IRQs. + */ + for (offset = 0; offset < gpiochip->ngpio; offset++) + irq_create_mapping(gpiochip->irqdomain, offset); + + return 0; +} +EXPORT_SYMBOL_GPL(gpiochip_irqchip_add); + +#else /* CONFIG_GPIOLIB_IRQCHIP */ + +static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} + +#endif /* CONFIG_GPIOLIB_IRQCHIP */ + #ifdef CONFIG_PINCTRL /** -- cgit v1.1 From 8d5b24bd30c23930e666813ea0adc4672ea58c62 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 25 Mar 2014 10:42:35 +0100 Subject: gpio: pl061: convert driver to use gpiolib irqchip This converts the PL061 driver to register its chained irq handler and irqchip using the helpers in the gpiolib core. Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-pl061.c | 80 +++++++++++------------------------------------ 2 files changed, 19 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 51c7825..92d8e9a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -247,6 +247,7 @@ config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA select IRQ_DOMAIN + select GPIOLIB_IRQCHIP help Say yes here to support the PrimeCell PL061 GPIO device diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index d2a0ad5..b0f4752 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -53,7 +52,6 @@ struct pl061_gpio { spinlock_t lock; void __iomem *base; - struct irq_domain *domain; struct gpio_chip gc; #ifdef CONFIG_PM @@ -137,16 +135,10 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) writeb(!!value << offset, chip->base + (1 << (offset + 2))); } -static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - - return irq_create_mapping(chip->domain, offset); -} - static int pl061_irq_type(struct irq_data *d, unsigned trigger) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); int offset = irqd_to_hwirq(d); unsigned long flags; u8 gpiois, gpioibe, gpioiev; @@ -194,7 +186,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) { unsigned long pending; int offset; - struct pl061_gpio *chip = irq_desc_get_handler_data(desc); + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); struct irq_chip *irqchip = irq_desc_get_chip(desc); chained_irq_enter(irqchip, desc); @@ -203,7 +196,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) writeb(pending, chip->base + GPIOIC); if (pending) { for_each_set_bit(offset, &pending, PL061_GPIO_NR) - generic_handle_irq(pl061_to_irq(&chip->gc, offset)); + generic_handle_irq(irq_find_mapping(gc->irqdomain, + offset)); } chained_irq_exit(irqchip, desc); @@ -211,7 +205,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) static void pl061_irq_mask(struct irq_data *d) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; @@ -223,7 +218,8 @@ static void pl061_irq_mask(struct irq_data *d) static void pl061_irq_unmask(struct irq_data *d) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; @@ -233,50 +229,11 @@ static void pl061_irq_unmask(struct irq_data *d) spin_unlock(&chip->lock); } -static int pl061_irq_reqres(struct irq_data *d) -{ - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - - if (gpio_lock_as_irq(&chip->gc, irqd_to_hwirq(d))) { - dev_err(chip->gc.dev, - "unable to lock HW IRQ %lu for IRQ\n", - irqd_to_hwirq(d)); - return -EINVAL; - } - return 0; -} - -static void pl061_irq_relres(struct irq_data *d) -{ - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - - gpio_unlock_as_irq(&chip->gc, irqd_to_hwirq(d)); -} - static struct irq_chip pl061_irqchip = { .name = "pl061", .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, - .irq_request_resources = pl061_irq_reqres, - .irq_release_resources = pl061_irq_relres, -}; - -static int pl061_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct pl061_gpio *chip = d->host_data; - - irq_set_chip_and_handler(irq, &pl061_irqchip, handle_simple_irq); - irq_set_chip_data(irq, chip); - irq_set_irq_type(irq, IRQ_TYPE_NONE); - - return 0; -} - -static const struct irq_domain_ops pl061_domain_ops = { - .map = pl061_irq_map, - .xlate = irq_domain_xlate_twocell, }; static int pl061_probe(struct amba_device *adev, const struct amba_id *id) @@ -314,7 +271,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) chip->gc.direction_output = pl061_direction_output; chip->gc.get = pl061_get_value; chip->gc.set = pl061_set_value; - chip->gc.to_irq = pl061_to_irq; chip->gc.ngpio = PL061_GPIO_NR; chip->gc.label = dev_name(dev); chip->gc.dev = dev; @@ -334,15 +290,15 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) return -ENODEV; } - irq_set_chained_handler(irq, pl061_irq_handler); - irq_set_handler_data(irq, chip); - - chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR, - irq_base, &pl061_domain_ops, chip); - if (!chip->domain) { - dev_err(&adev->dev, "no irq domain\n"); - return -ENODEV; + ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip, + irq_base, handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_info(&adev->dev, "could not add irqchip\n"); + return ret; } + gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip, + irq, pl061_irq_handler); for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { -- cgit v1.1 From e0bc34a3dada03a48ff5501381ff7fdef885ed25 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 25 Mar 2014 10:44:09 +0100 Subject: pinctrl: nomadik: convert driver to use gpiolib irqchip This converts the Nomadik pin control driver to register its chained irq handler and irqchip using the helpers in the gpiolib core. Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 3 + drivers/pinctrl/pinctrl-nomadik.c | 123 ++++++++++---------------------------- 2 files changed, 36 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 1e4e693..a05087b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -235,6 +235,9 @@ config PINCTRL_NOMADIK depends on ARCH_U8500 || ARCH_NOMADIK select PINMUX select PINCONF + select GPIOLIB + select OF_GPIO + select GPIOLIB_IRQCHIP config PINCTRL_STN8815 bool "STN8815 pin controller driver" diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 98a36a0..db0cc30 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -21,9 +21,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -248,7 +245,6 @@ enum nmk_gpio_slpm { struct nmk_gpio_chip { struct gpio_chip chip; - struct irq_domain *domain; void __iomem *addr; struct clk *clk; unsigned int bank; @@ -419,7 +415,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) u32 falling = nmk_chip->fimsc & BIT(offset); u32 rising = nmk_chip->rimsc & BIT(offset); int gpio = nmk_chip->chip.base + offset; - int irq = irq_find_mapping(nmk_chip->domain, offset); + int irq = irq_find_mapping(nmk_chip->chip.irqdomain, offset); struct irq_data *d = irq_get_irq_data(irq); if (!rising && !falling) @@ -647,11 +643,8 @@ static inline int nmk_gpio_get_bitmask(int gpio) static void nmk_gpio_irq_ack(struct irq_data *d) { - struct nmk_gpio_chip *nmk_chip; - - nmk_chip = irq_data_get_irq_chip_data(d); - if (!nmk_chip) - return; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); clk_enable(nmk_chip->clk); writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC); @@ -848,26 +841,6 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d) clk_disable(nmk_chip->clk); } -static int nmk_gpio_irq_reqres(struct irq_data *d) -{ - struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); - - if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq)) { - dev_err(nmk_chip->chip.dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); - return -EINVAL; - } - return 0; -} - -static void nmk_gpio_irq_relres(struct irq_data *d) -{ - struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); - - gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq); -} - static struct irq_chip nmk_gpio_irq_chip = { .name = "Nomadik-GPIO", .irq_ack = nmk_gpio_irq_ack, @@ -877,24 +850,21 @@ static struct irq_chip nmk_gpio_irq_chip = { .irq_set_wake = nmk_gpio_irq_set_wake, .irq_startup = nmk_gpio_irq_startup, .irq_shutdown = nmk_gpio_irq_shutdown, - .irq_request_resources = nmk_gpio_irq_reqres, - .irq_release_resources = nmk_gpio_irq_relres, .flags = IRQCHIP_MASK_ON_SUSPEND, }; static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, u32 status) { - struct nmk_gpio_chip *nmk_chip; struct irq_chip *host_chip = irq_get_chip(irq); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); chained_irq_enter(host_chip, desc); - nmk_chip = irq_get_handler_data(irq); while (status) { int bit = __ffs(status); - generic_handle_irq(irq_find_mapping(nmk_chip->domain, bit)); + generic_handle_irq(irq_find_mapping(chip->irqdomain, bit)); status &= ~BIT(bit); } @@ -903,9 +873,11 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); u32 status; + pr_err("PLONK IRQ %d\n", irq); clk_enable(nmk_chip->clk); status = readl(nmk_chip->addr + NMK_GPIO_IS); clk_disable(nmk_chip->clk); @@ -916,26 +888,13 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) static void nmk_gpio_latent_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); + struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); u32 status = nmk_chip->get_latent_status(nmk_chip->bank); __nmk_gpio_irq_handler(irq, desc, status); } -static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip) -{ - irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler); - irq_set_handler_data(nmk_chip->parent_irq, nmk_chip); - - if (nmk_chip->latent_parent_irq >= 0) { - irq_set_chained_handler(nmk_chip->latent_parent_irq, - nmk_gpio_latent_irq_handler); - irq_set_handler_data(nmk_chip->latent_parent_irq, nmk_chip); - } - - return 0; -} - /* I/O Functions */ static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -1014,14 +973,6 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, return 0; } -static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct nmk_gpio_chip *nmk_chip = - container_of(chip, struct nmk_gpio_chip, chip); - - return irq_create_mapping(nmk_chip->domain, offset); -} - #ifdef CONFIG_DEBUG_FS #include @@ -1120,7 +1071,6 @@ static struct gpio_chip nmk_gpio_template = { .get = nmk_gpio_get_input, .direction_output = nmk_gpio_make_output, .set = nmk_gpio_set_output, - .to_irq = nmk_gpio_to_irq, .dbg_show = nmk_gpio_dbg_show, .can_sleep = false, }; @@ -1221,27 +1171,6 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up) } } -static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct nmk_gpio_chip *nmk_chip = d->host_data; - - if (!nmk_chip) - return -EINVAL; - - irq_set_chip_and_handler(irq, &nmk_gpio_irq_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID); - irq_set_chip_data(irq, nmk_chip); - irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING); - - return 0; -} - -static const struct irq_domain_ops nmk_gpio_irq_simple_ops = { - .map = nmk_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - static int nmk_gpio_probe(struct platform_device *dev) { struct device_node *np = dev->dev.of_node; @@ -1321,17 +1250,31 @@ static int nmk_gpio_probe(struct platform_device *dev) platform_set_drvdata(dev, nmk_chip); - nmk_chip->domain = irq_domain_add_simple(np, - NMK_GPIO_PER_CHIP, 0, - &nmk_gpio_irq_simple_ops, nmk_chip); - if (!nmk_chip->domain) { - dev_err(&dev->dev, "failed to create irqdomain\n"); - /* Just do this, no matter if it fails */ + /* + * Let the generic code handle this edge IRQ, the the chained + * handler will perform the actual work of handling the parent + * interrupt. + */ + ret = gpiochip_irqchip_add(&nmk_chip->chip, + &nmk_gpio_irq_chip, + 0, + handle_edge_irq, + IRQ_TYPE_EDGE_FALLING); + if (ret) { + dev_err(&dev->dev, "could not add irqchip\n"); ret = gpiochip_remove(&nmk_chip->chip); - return -ENOSYS; + return -ENODEV; } - - nmk_gpio_init_irq(nmk_chip); + /* Then register the chain on the parent IRQ */ + gpiochip_set_chained_irqchip(&nmk_chip->chip, + &nmk_gpio_irq_chip, + nmk_chip->parent_irq, + nmk_gpio_irq_handler); + if (nmk_chip->latent_parent_irq > 0) + gpiochip_set_chained_irqchip(&nmk_chip->chip, + &nmk_gpio_irq_chip, + nmk_chip->latent_parent_irq, + nmk_gpio_latent_irq_handler); dev_info(&dev->dev, "at address %p\n", nmk_chip->addr); -- cgit v1.1 From 523dcce72c72e829b9d391f8020277038c6aab82 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 25 Mar 2014 13:37:17 +0100 Subject: pinctrl: coh901: convert driver to use gpiolib irqchip This converts the COH901 pin control driver to register its chained irq handler and irqchip using the helpers in the gpiolib core. Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/pinctrl-coh901.c | 204 ++++++++++----------------------------- 2 files changed, 54 insertions(+), 151 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index a05087b..0c6eb33 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -324,6 +324,7 @@ config PINCTRL_U300 config PINCTRL_COH901 bool "ST-Ericsson U300 COH 901 335/571 GPIO" depends on GPIOLIB && ARCH_U300 && PINCTRL_U300 + select GPIOLIB_IRQCHIP help Say yes here to support GPIO interface on ST-Ericsson U300. The names of the two IP block variants supported are diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 749db59..d182fdd2 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -8,17 +8,14 @@ * Author: Jonas Aaberg */ #include -#include #include #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -61,9 +58,17 @@ #define U300_GPIO_PINS_PER_PORT 8 #define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS) +struct u300_gpio_port { + struct u300_gpio *gpio; + char name[8]; + int irq; + int number; + u8 toggle_edge_mode; +}; + struct u300_gpio { struct gpio_chip chip; - struct list_head port_list; + struct u300_gpio_port ports[U300_GPIO_NUM_PORTS]; struct clk *clk; void __iomem *base; struct device *dev; @@ -78,16 +83,6 @@ struct u300_gpio { u32 iev; }; -struct u300_gpio_port { - struct list_head node; - struct u300_gpio *gpio; - char name[8]; - struct irq_domain *domain; - int irq; - int number; - u8 toggle_edge_mode; -}; - /* * Macro to expand to read a specific register found in the "gpio" * struct. It requires the struct u300_gpio *gpio variable to exist in @@ -308,39 +303,6 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, return 0; } -static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct u300_gpio *gpio = to_u300_gpio(chip); - int portno = offset >> 3; - struct u300_gpio_port *port = NULL; - struct list_head *p; - int retirq; - bool found = false; - - list_for_each(p, &gpio->port_list) { - port = list_entry(p, struct u300_gpio_port, node); - if (port->number == portno) { - found = true; - break; - } - } - if (!found) { - dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n", - offset); - return -EINVAL; - } - - /* - * The local hwirqs on the port are the lower three bits, there - * are exactly 8 IRQs per port since they are 8-bit - */ - retirq = irq_find_mapping(port->domain, (offset & 0x7)); - - dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n", - offset, retirq, port->number); - return retirq; -} - /* Returning -EINVAL means "supported but not available" */ int u300_gpio_config_get(struct gpio_chip *chip, unsigned offset, @@ -461,7 +423,6 @@ static struct gpio_chip u300_gpio_chip = { .set = u300_gpio_set, .direction_input = u300_gpio_direction_input, .direction_output = u300_gpio_direction_output, - .to_irq = u300_gpio_to_irq, }; static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset) @@ -485,9 +446,10 @@ static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset) static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) { - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - int offset = (port->number << 3) + d->hwirq; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = to_u300_gpio(chip); + struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3]; + int offset = d->hwirq; u32 val; if ((trigger & IRQF_TRIGGER_RISING) && @@ -521,9 +483,10 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) static void u300_gpio_irq_enable(struct irq_data *d) { - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - int offset = (port->number << 3) + d->hwirq; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = to_u300_gpio(chip); + struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3]; + int offset = d->hwirq; u32 val; unsigned long flags; @@ -537,9 +500,9 @@ static void u300_gpio_irq_enable(struct irq_data *d) static void u300_gpio_irq_disable(struct irq_data *d) { - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - int offset = (port->number << 3) + d->hwirq; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = to_u300_gpio(chip); + int offset = d->hwirq; u32 val; unsigned long flags; @@ -549,45 +512,24 @@ static void u300_gpio_irq_disable(struct irq_data *d) local_irq_restore(flags); } -static int u300_gpio_irq_reqres(struct irq_data *d) -{ - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - - if (gpio_lock_as_irq(&gpio->chip, d->hwirq)) { - dev_err(gpio->dev, - "unable to lock HW IRQ %lu for IRQ\n", - d->hwirq); - return -EINVAL; - } - return 0; -} - -static void u300_gpio_irq_relres(struct irq_data *d) -{ - struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); - struct u300_gpio *gpio = port->gpio; - - gpio_unlock_as_irq(&gpio->chip, d->hwirq); -} - static struct irq_chip u300_gpio_irqchip = { .name = "u300-gpio-irqchip", .irq_enable = u300_gpio_irq_enable, .irq_disable = u300_gpio_irq_disable, .irq_set_type = u300_gpio_irq_type, - .irq_request_resources = u300_gpio_irq_reqres, - .irq_release_resources = u300_gpio_irq_relres, }; static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - struct u300_gpio_port *port = irq_get_handler_data(irq); - struct u300_gpio *gpio = port->gpio; + struct irq_chip *parent_chip = irq_get_chip(irq); + struct gpio_chip *chip = irq_get_handler_data(irq); + struct u300_gpio *gpio = to_u300_gpio(chip); + struct u300_gpio_port *port = &gpio->ports[irq - chip->base]; int pinoffset = port->number << 3; /* get the right stride */ unsigned long val; - desc->irq_data.chip->irq_ack(&desc->irq_data); + chained_irq_enter(parent_chip, desc); + /* Read event register */ val = readl(U300_PIN_REG(pinoffset, iev)); /* Mask relevant bits */ @@ -600,8 +542,8 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) int irqoffset; for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { - int pin_irq = irq_find_mapping(port->domain, irqoffset); int offset = pinoffset + irqoffset; + int pin_irq = irq_find_mapping(chip->irqdomain, offset); dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n", pin_irq, offset); @@ -615,7 +557,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) } } - desc->irq_data.chip->irq_unmask(&desc->irq_data); + chained_irq_exit(parent_chip, desc); } static void __init u300_gpio_init_pin(struct u300_gpio *gpio, @@ -666,20 +608,6 @@ static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio) } } -static inline void u300_gpio_free_ports(struct u300_gpio *gpio) -{ - struct u300_gpio_port *port; - struct list_head *p, *n; - - list_for_each_safe(p, n, &gpio->port_list) { - port = list_entry(p, struct u300_gpio_port, node); - list_del(&port->node); - if (port->domain) - irq_domain_remove(port->domain); - kfree(port); - } -} - /* * Here we map a GPIO in the local gpio_chip pin space to a pin in * the local pinctrl pin space. The pin controller used is @@ -770,17 +698,28 @@ static int __init u300_gpio_probe(struct platform_device *pdev) gpio->base + U300_GPIO_CR); u300_gpio_init_coh901571(gpio); +#ifdef CONFIG_OF_GPIO + gpio->chip.of_node = pdev->dev.of_node; +#endif + err = gpiochip_add(&gpio->chip); + if (err) { + dev_err(gpio->dev, "unable to add gpiochip: %d\n", err); + goto err_no_chip; + } + + err = gpiochip_irqchip_add(&gpio->chip, + &u300_gpio_irqchip, + 0, + handle_simple_irq, + IRQ_TYPE_EDGE_FALLING); + if (err) { + dev_err(gpio->dev, "no GPIO irqchip\n"); + goto err_no_irqchip; + } + /* Add each port with its IRQ separately */ - INIT_LIST_HEAD(&gpio->port_list); for (portno = 0 ; portno < U300_GPIO_NUM_PORTS; portno++) { - struct u300_gpio_port *port = - kmalloc(sizeof(struct u300_gpio_port), GFP_KERNEL); - - if (!port) { - dev_err(gpio->dev, "out of memory\n"); - err = -ENOMEM; - goto err_no_port; - } + struct u300_gpio_port *port = &gpio->ports[portno]; snprintf(port->name, 8, "gpio%d", portno); port->number = portno; @@ -788,50 +727,16 @@ static int __init u300_gpio_probe(struct platform_device *pdev) port->irq = platform_get_irq(pdev, portno); - dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq, - port->name); - - port->domain = irq_domain_add_linear(pdev->dev.of_node, - U300_GPIO_PINS_PER_PORT, - &irq_domain_simple_ops, - port); - if (!port->domain) { - err = -ENOMEM; - goto err_no_domain; - } - - irq_set_chained_handler(port->irq, u300_gpio_irq_handler); - irq_set_handler_data(port->irq, port); - - /* For each GPIO pin set the unique IRQ handler */ - for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { - int irqno = irq_create_mapping(port->domain, i); - - dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n", - gpio->chip.base + (port->number << 3) + i, - port->name, irqno); - irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, - handle_simple_irq); - set_irq_flags(irqno, IRQF_VALID); - irq_set_chip_data(irqno, port); - } + gpiochip_set_chained_irqchip(&gpio->chip, + &u300_gpio_irqchip, + port->irq, + u300_gpio_irq_handler); /* Turns off irq force (test register) for this port */ writel(0x0, gpio->base + portno * gpio->stride + ifr); - - list_add_tail(&port->node, &gpio->port_list); } dev_dbg(gpio->dev, "initialized %d GPIO ports\n", portno); -#ifdef CONFIG_OF_GPIO - gpio->chip.of_node = pdev->dev.of_node; -#endif - err = gpiochip_add(&gpio->chip); - if (err) { - dev_err(gpio->dev, "unable to add gpiochip: %d\n", err); - goto err_no_chip; - } - /* * Add pinctrl pin ranges, the pin controller must be registered * at this point @@ -850,12 +755,10 @@ static int __init u300_gpio_probe(struct platform_device *pdev) return 0; err_no_range: +err_no_irqchip: if (gpiochip_remove(&gpio->chip)) dev_err(&pdev->dev, "failed to remove gpio chip\n"); err_no_chip: -err_no_domain: -err_no_port: - u300_gpio_free_ports(gpio); clk_disable_unprepare(gpio->clk); dev_err(&pdev->dev, "module ERROR:%d\n", err); return err; @@ -874,7 +777,6 @@ static int __exit u300_gpio_remove(struct platform_device *pdev) dev_err(gpio->dev, "unable to remove gpiochip: %d\n", err); return err; } - u300_gpio_free_ports(gpio); clk_disable_unprepare(gpio->clk); return 0; } -- cgit v1.1 From 138d876e30353da34495e463d20c9bd7c0fd4ba0 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 18 Mar 2014 10:58:33 +0100 Subject: gpio: iop: fix devm_ioremap_resource() return value checking devm_ioremap_resource() returns a pointer to the remapped memory or an ERR_PTR() encoded error code on failure. Fix the check inside iop3xx_gpio_probe() accordingly. Cc: Lennert Buytenhek Cc: Mikael Pettersson Cc: Aaro Koskinen Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Alexandre Courbot Acked-by: Dan Williams Signed-off-by: Linus Walleij --- drivers/gpio/gpio-iop.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c index c22a61b..0a5e9d3 100644 --- a/drivers/gpio/gpio-iop.c +++ b/drivers/gpio/gpio-iop.c @@ -111,6 +111,8 @@ static int iop3xx_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); return gpiochip_add(&iop3xx_chip); } -- cgit v1.1 From fd0f885b79d1eac9b8aed7e04fe641b8cfd4ebf0 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Mar 2014 12:32:15 +0400 Subject: gpio: twl4030: Remove redundant assignment Variable "status" is never used, so remove it and add warning if any error happen. Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-twl4030.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 8b88ca2..3ebb1a5 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -139,7 +139,6 @@ static u8 cached_leden; static void twl4030_led_set_value(int led, int value) { u8 mask = LEDEN_LEDAON | LEDEN_LEDAPWM; - int status; if (led) mask <<= 1; @@ -148,8 +147,9 @@ static void twl4030_led_set_value(int led, int value) cached_leden &= ~mask; else cached_leden |= mask; - status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, - TWL4030_LED_LEDEN_REG); + + WARN_ON_ONCE(twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, + TWL4030_LED_LEDEN_REG)); } static int twl4030_set_gpio_direction(int gpio, int is_input) -- cgit v1.1 From 24016ab6a857fef060b29a9714649dcb80dc77c1 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Mar 2014 12:35:22 +0400 Subject: gpio: samsung: Add missing "break" statement Signed-off-by: Alexander Shiyan Signed-off-by: Linus Walleij --- drivers/gpio/gpio-samsung.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index a85e00b..07105ee 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -379,6 +379,7 @@ static int s5p64x0_gpio_setcfg_rbank(struct samsung_gpio_chip *chip, case 6: shift = ((off + 1) & 7) * 4; reg -= 4; + break; default: shift = ((off + 1) & 7) * 4; break; -- cgit v1.1 From a585f87c863e4e1d496459d382b802bf5ebe3717 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 24 Mar 2014 03:38:10 +0100 Subject: gpio: mxs: Allow for recursive enable_irq_wake() call The scenario here is that someone calls enable_irq_wake() from somewhere in the code. This will result in the lockdep producing a backtrace as can be seen below. In my case, this problem is triggered when using the wl1271 (TI WlCore) driver found in drivers/net/wireless/ti/ . The problem cause is rather obvious from the backtrace, but let's outline the dependency. enable_irq_wake() grabs the IRQ buslock in irq_set_irq_wake(), which in turns calls mxs_gpio_set_wake_irq() . But mxs_gpio_set_wake_irq() calls enable_irq_wake() again on the one-level-higher IRQ , thus it tries to grab the IRQ buslock again in irq_set_irq_wake() . Because the spinlock in irq_set_irq_wake()->irq_get_desc_buslock()->__irq_get_desc_lock() is not marked as recursive, lockdep will spew the stuff below. We know we can safely re-enter the lock, so use IRQ_GC_INIT_NESTED_LOCK to fix the spew. ============================================= [ INFO: possible recursive locking detected ] 3.10.33-00012-gf06b763-dirty #61 Not tainted --------------------------------------------- kworker/0:1/18 is trying to acquire lock: (&irq_desc_lock_class){-.-...}, at: [] __irq_get_desc_lock+0x48/0x88 but task is already holding lock: (&irq_desc_lock_class){-.-...}, at: [] __irq_get_desc_lock+0x48/0x88 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&irq_desc_lock_class); lock(&irq_desc_lock_class); *** DEADLOCK *** May be due to missing lock nesting notation 3 locks held by kworker/0:1/18: #0: (events){.+.+.+}, at: [] process_one_work+0x134/0x4a4 #1: ((&fw_work->work)){+.+.+.}, at: [] process_one_work+0x134/0x4a4 #2: (&irq_desc_lock_class){-.-...}, at: [] __irq_get_desc_lock+0x48/0x88 stack backtrace: CPU: 0 PID: 18 Comm: kworker/0:1 Not tainted 3.10.33-00012-gf06b763-dirty #61 Workqueue: events request_firmware_work_func [] (unwind_backtrace+0x0/0xf0) from [] (show_stack+0x10/0x14) [] (show_stack+0x10/0x14) from [] (__lock_acquire+0x140c/0x1a64) [] (__lock_acquire+0x140c/0x1a64) from [] (lock_acquire+0x9c/0x104) [] (lock_acquire+0x9c/0x104) from [] (_raw_spin_lock_irqsave+0x44/0x58) [] (_raw_spin_lock_irqsave+0x44/0x58) from [] (__irq_get_desc_lock+0x48/0x88) [] (__irq_get_desc_lock+0x48/0x88) from [] (irq_set_irq_wake+0x20/0xf4) [] (irq_set_irq_wake+0x20/0xf4) from [] (mxs_gpio_set_wake_irq+0x1c/0x24) [] (mxs_gpio_set_wake_irq+0x1c/0x24) from [] (set_irq_wake_real+0x30/0x44) [] (set_irq_wake_real+0x30/0x44) from [] (irq_set_irq_wake+0x8c/0xf4) [] (irq_set_irq_wake+0x8c/0xf4) from [] (wlcore_nvs_cb+0x10c/0x97c) [] (wlcore_nvs_cb+0x10c/0x97c) from [] (request_firmware_work_func+0x38/0x58) [] (request_firmware_work_func+0x38/0x58) from [] (process_one_work+0x1c0/0x4a4) [] (process_one_work+0x1c0/0x4a4) from [] (worker_thread+0x138/0x394) [] (worker_thread+0x138/0x394) from [] (kthread+0xa4/0xb0) [] (kthread+0xa4/0xb0) from [] (ret_from_fork+0x14/0x34) wlcore: loaded Cc: stable@vger.kernel.org Signed-off-by: Marek Vasut Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mxs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 532bcb3..8ffdd7d 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -214,7 +214,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR; ct->regs.mask = PINCTRL_IRQEN(port); - irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0); + irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, + IRQ_NOREQUEST, 0); } static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -- cgit v1.1 From c9e8dbadb0528d872c5734858dbf76aa4cb31df9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Mar 2014 10:43:33 +0800 Subject: gpio: moxart: Avoid forward declaration Slightly adjust the code to avoid forward declaration as we need to call moxart_gpio_set() in moxart_gpio_direction_output() to properly set the output state. Signed-off-by: Axel Lin Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-moxart.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c index 2af9900..a19a14d 100644 --- a/drivers/gpio/gpio-moxart.c +++ b/drivers/gpio/gpio-moxart.c @@ -48,25 +48,6 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) pinctrl_free_gpio(offset); } -static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - writel(readl(ioaddr) & ~BIT(offset), ioaddr); - return 0; -} - -static int moxart_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - writel(readl(ioaddr) | BIT(offset), ioaddr); - return 0; -} - static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct moxart_gpio_chip *gc = to_moxart_gpio(chip); @@ -78,7 +59,6 @@ static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) else reg = reg & ~BIT(offset); - writel(reg, ioaddr); } @@ -93,6 +73,25 @@ static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset)); } +static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; + + writel(readl(ioaddr) & ~BIT(offset), ioaddr); + return 0; +} + +static int moxart_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; + + writel(readl(ioaddr) | BIT(offset), ioaddr); + return 0; +} + static struct gpio_chip moxart_template_chip = { .label = "moxart-gpio", .request = moxart_gpio_request, -- cgit v1.1 From fc860356aca3dd7cd3eed74ede29a84c55992d27 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Mar 2014 10:44:19 +0800 Subject: gpio: moxart: Actually set output state in moxart_gpio_direction_output() moxart_gpio_direction_output() ignored the state passed into it. Fix it. Signed-off-by: Axel Lin Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-moxart.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c index a19a14d..ccd4570 100644 --- a/drivers/gpio/gpio-moxart.c +++ b/drivers/gpio/gpio-moxart.c @@ -88,6 +88,7 @@ static int moxart_gpio_direction_output(struct gpio_chip *chip, struct moxart_gpio_chip *gc = to_moxart_gpio(chip); void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; + moxart_gpio_set(chip, offset, value); writel(readl(ioaddr) | BIT(offset), ioaddr); return 0; } -- cgit v1.1 From 2ddf6cd67cc561e40454d60126a8a7cb32f3328f Mon Sep 17 00:00:00 2001 From: Daniel Krueger Date: Tue, 25 Mar 2014 10:32:47 +0100 Subject: pch_gpio: set value before enabling output direction This ensures that the output signal does not toggle if set to high. Signed-off-by: Daniel Krueger Signed-off-by: Alexander Stein Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pch.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 9656c19..83a1563 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -138,9 +138,6 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); - pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); - pm |= (1 << nr); - iowrite32(pm, &chip->reg->pm); reg_val = ioread32(&chip->reg->po); if (val) @@ -148,6 +145,11 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, else reg_val &= ~(1 << nr); iowrite32(reg_val, &chip->reg->po); + + pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); + pm |= (1 << nr); + iowrite32(pm, &chip->reg->pm); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; -- cgit v1.1 From c3626fdea044cc97bfc035ebb048f7619acb6736 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 28 Mar 2014 20:42:01 +0100 Subject: gpio: unmap gpio irqs properly When using the irqchip helper inside the gpiolib, make sure the IRQs are unmapped/disposed before the irqdomain is removed as part of removing the gpiochip. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f41cb4f..761013f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1399,8 +1399,18 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, return 0; } +static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) +{ +#ifdef CONFIG_ARM + set_irq_flags(irq, 0); +#endif + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + static const struct irq_domain_ops gpiochip_domain_ops = { .map = gpiochip_irq_map, + .unmap = gpiochip_irq_unmap, /* Virtually all GPIO irqchips are twocell:ed */ .xlate = irq_domain_xlate_twocell, }; @@ -1438,8 +1448,14 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) */ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) { - if (gpiochip->irqdomain) + unsigned int offset; + + /* Remove all IRQ mappings and delete the domain */ + if (gpiochip->irqdomain) { + for (offset = 0; offset < gpiochip->ngpio; offset++) + irq_dispose_mapping(gpiochip->irq_base + offset); irq_domain_remove(gpiochip->irqdomain); + } if (gpiochip->irqchip) { gpiochip->irqchip->irq_request_resources = NULL; @@ -1467,7 +1483,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) * translation. The gpiochip will need to be initialized and registered * before calling this function. * - * This function will handle two cell:ed simple IRQs. Everything else + * This function will handle two cell:ed simple IRQs and assumes all + * the pins on the gpiochip can generate a unique IRQ. Everything else * need to be open coded. */ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, @@ -1478,6 +1495,7 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, { struct device_node *of_node; unsigned int offset; + unsigned irq_base = 0; if (!gpiochip || !irqchip) return -EINVAL; @@ -1514,8 +1532,15 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, * any gpiochip calls. If the first_irq was zero, this is * necessary to allocate descriptors for all IRQs. */ - for (offset = 0; offset < gpiochip->ngpio; offset++) - irq_create_mapping(gpiochip->irqdomain, offset); + for (offset = 0; offset < gpiochip->ngpio; offset++) { + irq_base = irq_create_mapping(gpiochip->irqdomain, offset); + if (offset == 0) + /* + * Store the base into the gpiochip to be used when + * unmapping the irqs. + */ + gpiochip->irq_base = irq_base; + } return 0; } -- cgit v1.1 From 8650ea1ebc31e9b0ab17c31d844dc106e60269db Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Thu, 27 Mar 2014 15:02:08 +0200 Subject: gpio-lynxpoint: force gpio_get() to return "1" and "0" only Don't return the IN_LVL_BIT directly, a high gpio line returned value "1073741824" intestead of "1" because IN_LVL_BIT is BIT(30) Tested-by: Jerome Blin Signed-off-by: Mathias Nyman Signed-off-by: Linus Walleij --- drivers/gpio/gpio-lynxpoint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 41f79cb..9a82a90 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -188,7 +188,7 @@ static int lp_irq_type(struct irq_data *d, unsigned type) static int lp_gpio_get(struct gpio_chip *chip, unsigned offset) { unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); - return inl(reg) & IN_LVL_BIT; + return !!(inl(reg) & IN_LVL_BIT); } static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -- cgit v1.1 From b22978fc33dec72e5f8e17f90eb63ea9137aafd5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 27 Mar 2014 21:47:36 +0100 Subject: gpio: rcar: Add helper variable dev = &pdev->dev Signed-off-by: Geert Uytterhoeven Cc: linux-gpio@vger.kernel.org Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index ca76ce7..03c9148 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -356,12 +356,13 @@ static int gpio_rcar_probe(struct platform_device *pdev) struct resource *io, *irq; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; - const char *name = dev_name(&pdev->dev); + struct device *dev = &pdev->dev; + const char *name = dev_name(dev); int ret; - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); if (!p) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); + dev_err(dev, "failed to allocate driver data\n"); ret = -ENOMEM; goto err0; } @@ -380,15 +381,14 @@ static int gpio_rcar_probe(struct platform_device *pdev) irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!io || !irq) { - dev_err(&pdev->dev, "missing IRQ or IOMEM\n"); + dev_err(dev, "missing IRQ or IOMEM\n"); ret = -EINVAL; goto err0; } - p->base = devm_ioremap_nocache(&pdev->dev, io->start, - resource_size(io)); + p->base = devm_ioremap_nocache(dev, io->start, resource_size(io)); if (!p->base) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); + dev_err(dev, "failed to remap I/O memory\n"); ret = -ENXIO; goto err0; } @@ -402,7 +402,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip->set = gpio_rcar_set; gpio_chip->to_irq = gpio_rcar_to_irq; gpio_chip->label = name; - gpio_chip->dev = &pdev->dev; + gpio_chip->dev = dev; gpio_chip->owner = THIS_MODULE; gpio_chip->base = p->config.gpio_base; gpio_chip->ngpio = p->config.number_of_pins; @@ -421,30 +421,30 @@ static int gpio_rcar_probe(struct platform_device *pdev) &gpio_rcar_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; - dev_err(&pdev->dev, "cannot initialize irq domain\n"); + dev_err(dev, "cannot initialize irq domain\n"); goto err0; } - if (devm_request_irq(&pdev->dev, irq->start, - gpio_rcar_irq_handler, IRQF_SHARED, name, p)) { - dev_err(&pdev->dev, "failed to request IRQ\n"); + if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, + IRQF_SHARED, name, p)) { + dev_err(dev, "failed to request IRQ\n"); ret = -ENOENT; goto err1; } ret = gpiochip_add(gpio_chip); if (ret) { - dev_err(&pdev->dev, "failed to add GPIO controller\n"); + dev_err(dev, "failed to add GPIO controller\n"); goto err1; } - dev_info(&pdev->dev, "driving %d GPIOs\n", p->config.number_of_pins); + dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins); /* warn in case of mismatch if irq base is specified */ if (p->config.irq_base) { ret = irq_find_mapping(p->irq_domain, 0); if (p->config.irq_base != ret) - dev_warn(&pdev->dev, "irq base mismatch (%u/%u)\n", + dev_warn(dev, "irq base mismatch (%u/%u)\n", p->config.irq_base, ret); } @@ -452,7 +452,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0, gpio_chip->base, gpio_chip->ngpio); if (ret < 0) - dev_warn(&pdev->dev, "failed to add pin range\n"); + dev_warn(dev, "failed to add pin range\n"); } return 0; -- cgit v1.1