diff options
Diffstat (limited to 'drivers/gpio')
29 files changed, 1724 insertions, 687 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b6ed304863eb..92e258c58638 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -129,7 +129,7 @@ config GPIO_IT8761E config GPIO_EM tristate "Emma Mobile GPIO" - depends on ARM + depends on ARM && OF_GPIO help Say yes here to support GPIO on Renesas Emma Mobile SoCs. @@ -320,6 +320,15 @@ config GPIO_ICH If unsure, say N. +config GPIO_IOP + tristate "Intel IOP GPIO" + depends on ARM && (ARCH_IOP32X || ARCH_IOP33X) + help + Say yes here to support the GPIO functionality of a number of Intel + IOP32X or IOP33X. + + If unsure, say N. + config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" depends on PCI @@ -612,12 +621,12 @@ config GPIO_AMD8111 If unsure, say N -config GPIO_LANGWELL - bool "Intel Langwell/Penwell GPIO support" +config GPIO_INTEL_MID + bool "Intel Mid GPIO support" depends on PCI && X86 select IRQ_DOMAIN help - Say Y here to support Intel Langwell/Penwell GPIO. + Say Y here to support Intel Mid GPIO. config GPIO_PCH tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO" @@ -703,7 +712,7 @@ config GPIO_74X164 comment "AC97 GPIO expanders:" config GPIO_UCB1400 - bool "Philips UCB1400 GPIO" + tristate "Philips UCB1400 GPIO" depends on UCB1400_CORE help This enables support for the Philips UCB1400 GPIO pins. @@ -759,6 +768,12 @@ config GPIO_MSIC Enable support for GPIO on intel MSIC controllers found in intel MID devices +config GPIO_BCM_KONA + bool "Broadcom Kona GPIO" + depends on OF_GPIO + help + Turn on GPIO support for Broadcom "Kona" chips. + comment "USB GPIO expanders:" config GPIO_VIPERBOARD diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 98e23ebba2cf..7655a369e2b7 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o @@ -28,11 +29,12 @@ obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o +obj-$(CONFIG_GPIO_IOP) += gpio-iop.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o -obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o +obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 5d518d5db7a0..1e04bf91328d 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -176,7 +176,6 @@ static int gen_74x164_probe(struct spi_device *spi) return ret; exit_destroy: - spi_set_drvdata(spi, NULL); mutex_destroy(&chip->lock); return ret; } @@ -190,8 +189,6 @@ static int gen_74x164_remove(struct spi_device *spi) if (chip == NULL) return -ENODEV; - spi_set_drvdata(spi, NULL); - ret = gpiochip_remove(&chip->gpio_chip); if (!ret) mutex_destroy(&chip->lock); @@ -212,7 +209,7 @@ static struct spi_driver gen_74x164_driver = { .driver = { .name = "74x164", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(gen_74x164_dt_ids), + .of_match_table = gen_74x164_dt_ids, }, .probe = gen_74x164_probe, .remove = gen_74x164_remove, diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index c0f3fc44ab0e..b204033acaeb 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -325,9 +325,9 @@ static irqreturn_t adnp_irq(int irq, void *data) pending &= isr & ier; for_each_set_bit(bit, &pending, 8) { - unsigned int virq; - virq = irq_find_mapping(adnp->domain, base + bit); - handle_nested_irq(virq); + unsigned int child_irq; + child_irq = irq_find_mapping(adnp->domain, base + bit); + handle_nested_irq(child_irq); } } @@ -594,7 +594,7 @@ static struct i2c_driver adnp_i2c_driver = { .driver = { .name = "gpio-adnp", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(adnp_of_match), + .of_match_table = adnp_of_match, }, .probe = adnp_i2c_probe, .remove = adnp_i2c_remove, diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index fa8b6a762761..dceb5dcf9d16 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -109,10 +109,14 @@ static int arizona_gpio_probe(struct platform_device *pdev) arizona_gpio->arizona = arizona; arizona_gpio->gpio_chip = template_chip; arizona_gpio->gpio_chip.dev = &pdev->dev; +#ifdef CONFIG_OF_GPIO + arizona_gpio->gpio_chip.of_node = arizona->dev->of_node; +#endif switch (arizona->type) { case WM5102: case WM5110: + case WM8997: arizona_gpio->gpio_chip.ngpio = 5; break; default: diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c new file mode 100644 index 000000000000..b3d0f8163277 --- /dev/null +++ b/drivers/gpio/gpio-bcm-kona.c @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2012-2013 Broadcom Corporation + * + * 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 <linux/bitops.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/module.h> +#include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> + +#define BCM_GPIO_PASSWD 0x00a5a501 +#define GPIO_PER_BANK 32 +#define GPIO_MAX_BANK_NUM 8 + +#define GPIO_BANK(gpio) ((gpio) >> 5) +#define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1)) + +#define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2)) +#define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2)) +#define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2)) +#define GPIO_OUT_CLEAR(bank) (0x00000060 + ((bank) << 2)) +#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 + +#define GPIO_GPCTR0_DBR_SHIFT 5 +#define GPIO_GPCTR0_DBR_MASK 0x000001e0 + +#define GPIO_GPCTR0_ITR_SHIFT 3 +#define GPIO_GPCTR0_ITR_MASK 0x00000018 +#define GPIO_GPCTR0_ITR_CMD_RISING_EDGE 0x00000001 +#define GPIO_GPCTR0_ITR_CMD_FALLING_EDGE 0x00000002 +#define GPIO_GPCTR0_ITR_CMD_BOTH_EDGE 0x00000003 + +#define GPIO_GPCTR0_IOTR_MASK 0x00000001 +#define GPIO_GPCTR0_IOTR_CMD_0UTPUT 0x00000000 +#define GPIO_GPCTR0_IOTR_CMD_INPUT 0x00000001 + +#define GPIO_GPCTR0_DB_ENABLE_MASK 0x00000100 + +#define LOCK_CODE 0xffffffff +#define UNLOCK_CODE 0x00000000 + +struct bcm_kona_gpio { + void __iomem *reg_base; + int num_bank; + spinlock_t lock; + struct gpio_chip gpio_chip; + struct irq_domain *irq_domain; + struct bcm_kona_gpio_bank *banks; + struct platform_device *pdev; +}; + +struct bcm_kona_gpio_bank { + int id; + int irq; + /* Used in the interrupt handler */ + struct bcm_kona_gpio *kona_gpio; +}; + +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) +{ + 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) +{ + bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, LOCK_CODE); +} + +static inline void bcm_kona_gpio_unlock_bank(void __iomem *reg_base, + int bank_id) +{ + bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, UNLOCK_CODE); +} + +static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val, reg_offset; + unsigned long flags; + + 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)); + val &= GPIO_GPCTR0_IOTR_MASK; + + /* this function only applies to output pin */ + if (GPIO_GPCTR0_IOTR_CMD_INPUT == val) + goto out; + + reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); + + val = readl(reg_base + reg_offset); + val |= BIT(bit); + writel(val, reg_base + reg_offset); + +out: + bcm_kona_gpio_lock_bank(reg_base, bank_id); + spin_unlock_irqrestore(&kona_gpio->lock, flags); +} + +static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val, reg_offset; + unsigned long flags; + + 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)); + val &= GPIO_GPCTR0_IOTR_MASK; + + /* read the GPIO bank status */ + reg_offset = (GPIO_GPCTR0_IOTR_CMD_INPUT == val) ? + 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); +} + +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; +} + +static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, + unsigned gpio, int value) +{ + struct bcm_kona_gpio *kona_gpio; + void __iomem *reg_base; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val, reg_offset; + unsigned long flags; + + 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_0UTPUT; + writel(val, reg_base + GPIO_CONTROL(gpio)); + reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id); + + val = readl(reg_base + reg_offset); + 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; +} + +static int bcm_kona_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio; + + kona_gpio = to_kona_gpio(chip); + if (gpio >= kona_gpio->gpio_chip.ngpio) + return -ENXIO; + return irq_create_mapping(kona_gpio->irq_domain, gpio); +} + +static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, + unsigned debounce) +{ + struct bcm_kona_gpio *kona_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; + /* debounce must be 1-128ms (or 0) */ + if ((debounce > 0 && debounce < 1000) || debounce > 128000) { + dev_err(chip->dev, "Debounce value %u not in range\n", + debounce); + return -EINVAL; + } + + /* calculate debounce bit value */ + if (debounce != 0) { + /* Convert to ms */ + debounce /= 1000; + /* find the MSB */ + res = fls(debounce) - 1; + /* Check if MSB-1 is set (round up or down) */ + if (res > 0 && (debounce & BIT(res - 1))) + res++; + } + + /* 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; + + if (debounce == 0) { + /* disable debounce */ + val &= ~GPIO_GPCTR0_DB_ENABLE_MASK; + } else { + val |= GPIO_GPCTR0_DB_ENABLE_MASK | + (res << GPIO_GPCTR0_DBR_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; +} + +static struct gpio_chip template_chip = { + .label = "bcm-kona-gpio", + .direction_input = bcm_kona_gpio_direction_input, + .get = bcm_kona_gpio_get, + .direction_output = bcm_kona_gpio_direction_output, + .set = bcm_kona_gpio_set, + .set_debounce = bcm_kona_gpio_set_debounce, + .to_irq = bcm_kona_gpio_to_irq, + .base = 0, +}; + +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; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val; + unsigned long flags; + + 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); +} + +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; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val; + unsigned long flags; + + 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); +} + +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; + int bank_id = GPIO_BANK(gpio); + int bit = GPIO_BIT(gpio); + u32 val; + unsigned long flags; + + 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); +} + +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; + 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; + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + lvl_type = GPIO_GPCTR0_ITR_CMD_RISING_EDGE; + break; + + case IRQ_TYPE_EDGE_FALLING: + lvl_type = GPIO_GPCTR0_ITR_CMD_FALLING_EDGE; + break; + + case IRQ_TYPE_EDGE_BOTH: + lvl_type = GPIO_GPCTR0_ITR_CMD_BOTH_EDGE; + break; + + case IRQ_TYPE_LEVEL_HIGH: + case IRQ_TYPE_LEVEL_LOW: + /* BCM GPIO doesn't support level triggering */ + default: + dev_err(kona_gpio->gpio_chip.dev, + "Invalid BCM GPIO irq type 0x%x\n", type); + return -EINVAL; + } + + 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; +} + +static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + void __iomem *reg_base; + int bit, bank_id; + unsigned long sta; + struct bcm_kona_gpio_bank *bank = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + + /* + * For bank interrupts, we can't use chip_data to store the kona_gpio + * pointer, since GIC needs it for its own purposes. Therefore, we get + * our pointer from the bank structure. + */ + 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)))))) { + for_each_set_bit(bit, &sta, 32) { + int hwirq = GPIO_PER_BANK * bank_id + bit; + int child_irq = + irq_find_mapping(bank->kona_gpio->irq_domain, + hwirq); + /* + * Clear interrupt before handler is called so we don't + * miss any interrupt occurred during executing them. + */ + writel(readl(reg_base + GPIO_INT_STATUS(bank_id)) | + BIT(bit), reg_base + GPIO_INT_STATUS(bank_id)); + /* Invoke interrupt handler */ + generic_handle_irq(child_irq); + } + } + + bcm_kona_gpio_lock_bank(reg_base, bank_id); + + chained_irq_exit(chip, desc); +} + +static struct irq_chip bcm_gpio_irq_chip = { + .name = "bcm-kona-gpio", + .irq_ack = bcm_kona_gpio_irq_ack, + .irq_mask = bcm_kona_gpio_irq_mask, + .irq_unmask = bcm_kona_gpio_irq_unmask, + .irq_set_type = bcm_kona_gpio_irq_set_type, +}; + +static struct __initconst of_device_id bcm_kona_gpio_of_match[] = { + { .compatible = "brcm,kona-gpio" }, + {} +}; + +MODULE_DEVICE_TABLE(of, bcm_kona_gpio_of_match); + +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + +static int bcm_kona_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + int ret; + + ret = irq_set_chip_data(irq, d->host_data); + if (ret < 0) + return ret; + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, handle_simple_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + + return 0; +} + +static void bcm_kona_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static struct irq_domain_ops bcm_kona_irq_ops = { + .map = bcm_kona_gpio_irq_map, + .unmap = bcm_kona_gpio_irq_unmap, + .xlate = irq_domain_xlate_twocell, +}; + +static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio) +{ + void __iomem *reg_base; + int i; + + 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); + writel(0xffffffff, reg_base + GPIO_INT_MASK(i)); + writel(0xffffffff, reg_base + GPIO_INT_STATUS(i)); + bcm_kona_gpio_lock_bank(reg_base, i); + } +} + +static int bcm_kona_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *match; + struct resource *res; + struct bcm_kona_gpio_bank *bank; + struct bcm_kona_gpio *kona_gpio; + struct gpio_chip *chip; + int ret; + int i; + + match = of_match_device(bcm_kona_gpio_of_match, dev); + if (!match) { + dev_err(dev, "Failed to find gpio controller\n"); + return -ENODEV; + } + + kona_gpio = devm_kzalloc(dev, sizeof(*kona_gpio), GFP_KERNEL); + if (!kona_gpio) + return -ENOMEM; + + kona_gpio->gpio_chip = template_chip; + chip = &kona_gpio->gpio_chip; + kona_gpio->num_bank = of_irq_count(dev->of_node); + if (kona_gpio->num_bank == 0) { + dev_err(dev, "Couldn't determine # GPIO banks\n"); + return -ENOENT; + } + if (kona_gpio->num_bank > GPIO_MAX_BANK_NUM) { + dev_err(dev, "Too many GPIO banks configured (max=%d)\n", + GPIO_MAX_BANK_NUM); + return -ENXIO; + } + kona_gpio->banks = devm_kzalloc(dev, + kona_gpio->num_bank * + sizeof(*kona_gpio->banks), GFP_KERNEL); + if (!kona_gpio->banks) + return -ENOMEM; + + kona_gpio->pdev = pdev; + platform_set_drvdata(pdev, kona_gpio); + chip->of_node = dev->of_node; + chip->ngpio = kona_gpio->num_bank * GPIO_PER_BANK; + + kona_gpio->irq_domain = irq_domain_add_linear(dev->of_node, + chip->ngpio, + &bcm_kona_irq_ops, + kona_gpio); + if (!kona_gpio->irq_domain) { + dev_err(dev, "Couldn't allocate IRQ domain\n"); + return -ENXIO; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + kona_gpio->reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(kona_gpio->reg_base)) { + ret = -ENXIO; + goto err_irq_domain; + } + + for (i = 0; i < kona_gpio->num_bank; i++) { + bank = &kona_gpio->banks[i]; + bank->id = i; + bank->irq = platform_get_irq(pdev, i); + bank->kona_gpio = kona_gpio; + if (bank->irq < 0) { + dev_err(dev, "Couldn't get IRQ for bank %d", i); + ret = -ENOENT; + goto err_irq_domain; + } + } + + dev_info(&pdev->dev, "Setting up Kona GPIO\n"); + + bcm_kona_gpio_reset(kona_gpio); + + ret = gpiochip_add(chip); + if (ret < 0) { + dev_err(dev, "Couldn't add GPIO chip -- %d\n", ret); + goto err_irq_domain; + } + for (i = 0; i < chip->ngpio; i++) { + int irq = bcm_kona_gpio_to_irq(chip, i); + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, + handle_simple_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + } + for (i = 0; i < kona_gpio->num_bank; i++) { + bank = &kona_gpio->banks[i]; + irq_set_chained_handler(bank->irq, bcm_kona_gpio_irq_handler); + irq_set_handler_data(bank->irq, bank); + } + + spin_lock_init(&kona_gpio->lock); + + return 0; + +err_irq_domain: + irq_domain_remove(kona_gpio->irq_domain); + + return ret; +} + +static struct platform_driver bcm_kona_gpio_driver = { + .driver = { + .name = "bcm-kona-gpio", + .owner = THIS_MODULE, + .of_match_table = bcm_kona_gpio_of_match, + }, + .probe = bcm_kona_gpio_probe, +}; + +module_platform_driver(bcm_kona_gpio_driver); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("Broadcom Kona GPIO Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index 8369e71ebe4f..9dfe36fd8baf 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -228,7 +228,6 @@ static int bt8xxgpio_probe(struct pci_dev *dev, err_release_mem: release_mem_region(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); - pci_set_drvdata(dev, NULL); err_disable: pci_disable_device(dev); err_freebg: @@ -252,7 +251,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev) pci_resource_len(pdev, 0)); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); kfree(bg); } diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index 0edaf2ce9266..0924f20fa47f 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -87,7 +87,7 @@ static struct platform_driver clps711x_gpio_driver = { .driver = { .name = "clps711x-gpio", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(clps711x_gpio_ids), + .of_match_table = clps711x_gpio_ids, }, .probe = clps711x_gpio_probe, .remove = clps711x_gpio_remove, diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index c6e1f086efe8..ec190361bf2e 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -232,16 +232,16 @@ static void em_gio_free(struct gpio_chip *chip, unsigned offset) em_gio_direction_input(chip, offset); } -static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) +static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) { struct em_gio_priv *p = h->host_data; - pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq); + pr_debug("gio: map hw irq = %d, irq = %d\n", (int)hwirq, irq); - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); /* kill me now */ + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); /* kill me now */ return 0; } @@ -319,6 +319,7 @@ static int em_gio_probe(struct platform_device *pdev) } gpio_chip = &p->gpio_chip; + gpio_chip->of_node = pdev->dev.of_node; gpio_chip->direction_input = em_gio_direction_input; gpio_chip->get = em_gio_get; gpio_chip->direction_output = em_gio_direction_output; diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 56b98eebe1fc..80829f3c6543 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -51,15 +51,15 @@ static void ep93xx_gpio_update_int_params(unsigned port) { BUG_ON(port > 2); - __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port])); + writeb_relaxed(0, EP93XX_GPIO_REG(int_en_register_offset[port])); - __raw_writeb(gpio_int_type2[port], + writeb_relaxed(gpio_int_type2[port], EP93XX_GPIO_REG(int_type2_register_offset[port])); - __raw_writeb(gpio_int_type1[port], + writeb_relaxed(gpio_int_type1[port], EP93XX_GPIO_REG(int_type1_register_offset[port])); - __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], + writeb(gpio_int_unmasked[port] & gpio_int_enabled[port], EP93XX_GPIO_REG(int_en_register_offset[port])); } @@ -74,7 +74,7 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable) else gpio_int_debounce[port] &= ~port_mask; - __raw_writeb(gpio_int_debounce[port], + writeb(gpio_int_debounce[port], EP93XX_GPIO_REG(int_debounce_register_offset[port])); } @@ -83,7 +83,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) unsigned char status; int i; - status = __raw_readb(EP93XX_GPIO_A_INT_STATUS); + status = readb(EP93XX_GPIO_A_INT_STATUS); for (i = 0; i < 8; i++) { if (status & (1 << i)) { int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i; @@ -91,7 +91,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) } } - status = __raw_readb(EP93XX_GPIO_B_INT_STATUS); + status = readb(EP93XX_GPIO_B_INT_STATUS); for (i = 0; i < 8; i++) { if (status & (1 << i)) { int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i; @@ -124,7 +124,7 @@ static void ep93xx_gpio_irq_ack(struct irq_data *d) ep93xx_gpio_update_int_params(port); } - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); } static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) @@ -139,7 +139,7 @@ static void ep93xx_gpio_irq_mask_ack(struct irq_data *d) gpio_int_unmasked[port] &= ~port_mask; ep93xx_gpio_update_int_params(port); - __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); + writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port])); } static void ep93xx_gpio_irq_mask(struct irq_data *d) diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c new file mode 100644 index 000000000000..be803af658ac --- /dev/null +++ b/drivers/gpio/gpio-intel-mid.c @@ -0,0 +1,471 @@ +/* + * Moorestown platform Langwell chip GPIO driver + * + * Copyright (c) 2008, 2009, 2013, 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 + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * 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: + * Moorestown platform Langwell chip. + * Medfield platform Penwell chip. + * Clovertrail platform Cloverview chip. + * Merrifield platform Tangier chip. + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/stddef.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/irqdomain.h> + +#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0) +#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1) + +/* + * Langwell chip has 64 pins and thus there are 2 32bit registers to control + * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit + * registers to control them, so we only define the order here instead of a + * structure, to get a bit offset for a pin (use GPDR as an example): + * + * nreg = ngpio / 32; + * reg = offset / 32; + * bit = offset % 32; + * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; + * + * so the bit of reg_addr is to control pin offset's GPDR feature +*/ + +enum GPIO_REG { + GPLR = 0, /* pin level read-only */ + GPDR, /* pin direction */ + GPSR, /* pin set */ + GPCR, /* pin clear */ + GRER, /* rising edge detect */ + GFER, /* falling edge detect */ + GEDR, /* edge detect result */ + GAFR, /* alt function */ +}; + +/* intel_mid gpio driver data */ +struct intel_mid_gpio_ddata { + u16 ngpio; /* number of gpio pins */ + u32 gplr_offset; /* offset of first GPLR register from base */ + u32 flis_base; /* base address of FLIS registers */ + u32 flis_len; /* length of FLIS registers */ + u32 (*get_flis_offset)(int gpio); + u32 chip_irq_type; /* chip interrupt type */ +}; + +struct intel_mid_gpio { + struct gpio_chip chip; + void __iomem *reg_base; + spinlock_t lock; + struct pci_dev *pdev; + struct irq_domain *domain; +}; + +#define to_intel_gpio_priv(chip) container_of(chip, struct intel_mid_gpio, chip) + +static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, + enum GPIO_REG reg_type) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + unsigned nreg = chip->ngpio / 32; + u8 reg = offset / 32; + + return priv->reg_base + reg_type * nreg * 4 + reg * 4; +} + +static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, + enum GPIO_REG reg_type) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + unsigned nreg = chip->ngpio / 32; + u8 reg = offset / 16; + + return priv->reg_base + reg_type * nreg * 4 + reg * 4; +} + +static int intel_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); + u32 value = readl(gafr); + int shift = (offset % 16) << 1, af = (value >> shift) & 3; + + if (af) { + value &= ~(3 << shift); + writel(value, gafr); + } + return 0; +} + +static int intel_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *gplr = gpio_reg(chip, offset, GPLR); + + return readl(gplr) & BIT(offset % 32); +} + +static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + void __iomem *gpsr, *gpcr; + + if (value) { + gpsr = gpio_reg(chip, offset, GPSR); + writel(BIT(offset % 32), gpsr); + } else { + gpcr = gpio_reg(chip, offset, GPCR); + writel(BIT(offset % 32), gpcr); + } +} + +static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + void __iomem *gpdr = gpio_reg(chip, offset, GPDR); + u32 value; + unsigned long flags; + + if (priv->pdev) + pm_runtime_get(&priv->pdev->dev); + + spin_lock_irqsave(&priv->lock, flags); + value = readl(gpdr); + value &= ~BIT(offset % 32); + writel(value, gpdr); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->pdev) + pm_runtime_put(&priv->pdev->dev); + + return 0; +} + +static int intel_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + void __iomem *gpdr = gpio_reg(chip, offset, GPDR); + unsigned long flags; + + intel_gpio_set(chip, offset, value); + + if (priv->pdev) + pm_runtime_get(&priv->pdev->dev); + + spin_lock_irqsave(&priv->lock, flags); + value = readl(gpdr); + value |= BIT(offset % 32); + writel(value, gpdr); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->pdev) + pm_runtime_put(&priv->pdev->dev); + + return 0; +} + +static int intel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct intel_mid_gpio *priv = to_intel_gpio_priv(chip); + return irq_create_mapping(priv->domain, offset); +} + +static int intel_mid_irq_type(struct irq_data *d, unsigned type) +{ + struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); + u32 gpio = irqd_to_hwirq(d); + unsigned long flags; + u32 value; + void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); + void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); + + if (gpio >= priv->chip.ngpio) + return -EINVAL; + + if (priv->pdev) + pm_runtime_get(&priv->pdev->dev); + + spin_lock_irqsave(&priv->lock, flags); + if (type & IRQ_TYPE_EDGE_RISING) + value = readl(grer) | BIT(gpio % 32); + else + value = readl(grer) & (~BIT(gpio % 32)); + writel(value, grer); + + if (type & IRQ_TYPE_EDGE_FALLING) + value = readl(gfer) | BIT(gpio % 32); + else + value = readl(gfer) & (~BIT(gpio % 32)); + writel(value, gfer); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->pdev) + pm_runtime_put(&priv->pdev->dev); + + return 0; +} + +static void intel_mid_irq_unmask(struct irq_data *d) +{ +} + +static void intel_mid_irq_mask(struct irq_data *d) +{ +} + +static struct irq_chip intel_mid_irqchip = { + .name = "INTEL_MID-GPIO", + .irq_mask = intel_mid_irq_mask, + .irq_unmask = intel_mid_irq_unmask, + .irq_set_type = intel_mid_irq_type, +}; + +static const struct intel_mid_gpio_ddata gpio_lincroft = { + .ngpio = 64, +}; + +static const struct intel_mid_gpio_ddata gpio_penwell_aon = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static const struct intel_mid_gpio_ddata gpio_penwell_core = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static const struct intel_mid_gpio_ddata gpio_cloverview_aon = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE | INTEL_MID_IRQ_TYPE_LEVEL, +}; + +static const struct intel_mid_gpio_ddata gpio_cloverview_core = { + .ngpio = 96, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static const struct intel_mid_gpio_ddata gpio_tangier = { + .ngpio = 192, + .gplr_offset = 4, + .flis_base = 0xff0c0000, + .flis_len = 0x8000, + .get_flis_offset = NULL, + .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, +}; + +static DEFINE_PCI_DEVICE_TABLE(intel_gpio_ids) = { + { + /* Lincroft */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), + .driver_data = (kernel_ulong_t)&gpio_lincroft, + }, + { + /* Penwell AON */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), + .driver_data = (kernel_ulong_t)&gpio_penwell_aon, + }, + { + /* Penwell Core */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), + .driver_data = (kernel_ulong_t)&gpio_penwell_core, + }, + { + /* Cloverview Aon */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), + .driver_data = (kernel_ulong_t)&gpio_cloverview_aon, + }, + { + /* Cloverview Core */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), + .driver_data = (kernel_ulong_t)&gpio_cloverview_core, + }, + { + /* Tangier */ + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199), + .driver_data = (kernel_ulong_t)&gpio_tangier, + }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, intel_gpio_ids); + +static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct intel_mid_gpio *priv = irq_data_get_irq_handler_data(data); + struct irq_chip *chip = irq_data_get_irq_chip(data); + u32 base, gpio, mask; + unsigned long pending; + void __iomem *gedr; + + /* check GPIO controller to check which pin triggered the interrupt */ + for (base = 0; base < priv->chip.ngpio; base += 32) { + gedr = gpio_reg(&priv->chip, base, GEDR); + while ((pending = readl(gedr))) { + gpio = __ffs(pending); + mask = BIT(gpio); + /* Clear before handling so we can't lose an edge */ + writel(mask, gedr); + generic_handle_irq(irq_find_mapping(priv->domain, + base + gpio)); + } + } + + chip->irq_eoi(data); +} + +static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv) +{ + void __iomem *reg; + unsigned base; + + for (base = 0; base < priv->chip.ngpio; base += 32) { + /* Clear the rising-edge detect register */ + reg = gpio_reg(&priv->chip, base, GRER); + writel(0, reg); + /* Clear the falling-edge detect register */ + reg = gpio_reg(&priv->chip, base, GFER); + writel(0, reg); + /* Clear the edge detect status register */ + reg = gpio_reg(&priv->chip, base, GEDR); + writel(~0, reg); + } +} + +static int intel_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct intel_mid_gpio *priv = d->host_data; + + irq_set_chip_and_handler_name(irq, &intel_mid_irqchip, + handle_simple_irq, "demux"); + irq_set_chip_data(irq, priv); + irq_set_irq_type(irq, IRQ_TYPE_NONE); + + return 0; +} + +static const struct irq_domain_ops intel_gpio_irq_ops = { + .map = intel_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int intel_gpio_runtime_idle(struct device *dev) +{ + pm_schedule_suspend(dev, 500); + return -EBUSY; +} + +static const struct dev_pm_ops intel_gpio_pm_ops = { + SET_RUNTIME_PM_OPS(NULL, NULL, intel_gpio_runtime_idle) +}; + +static int intel_gpio_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *base; + struct intel_mid_gpio *priv; + u32 gpio_base; + u32 irq_base; + int retval; + struct intel_mid_gpio_ddata *ddata = + (struct intel_mid_gpio_ddata *)id->driver_data; + + retval = pcim_enable_device(pdev); + if (retval) + return retval; + + retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev)); + if (retval) { + dev_err(&pdev->dev, "I/O memory mapping error\n"); + return retval; + } + + base = pcim_iomap_table(pdev)[1]; + + irq_base = readl(base); + gpio_base = readl(sizeof(u32) + base); + + /* release the IO mapping, since we already get the info from bar1 */ + pcim_iounmap_regions(pdev, 1 << 1); + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "can't allocate chip data\n"); + return -ENOMEM; + } + + priv->reg_base = pcim_iomap_table(pdev)[0]; + priv->chip.label = dev_name(&pdev->dev); + priv->chip.request = intel_gpio_request; + priv->chip.direction_input = intel_gpio_direction_input; + priv->chip.direction_output = intel_gpio_direction_output; + priv->chip.get = intel_gpio_get; + priv->chip.set = intel_gpio_set; + priv->chip.to_irq = intel_gpio_to_irq; + priv->chip.base = gpio_base; + priv->chip.ngpio = ddata->ngpio; + priv->chip.can_sleep = 0; + priv->pdev = pdev; + + spin_lock_init(&priv->lock); + + priv->domain = irq_domain_add_simple(pdev->dev.of_node, ddata->ngpio, + irq_base, &intel_gpio_irq_ops, priv); + if (!priv->domain) + return -ENOMEM; + + pci_set_drvdata(pdev, priv); + retval = gpiochip_add(&priv->chip); + if (retval) { + dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); + return retval; + } + + intel_mid_irq_init_hw(priv); + + irq_set_handler_data(pdev->irq, priv); + irq_set_chained_handler(pdev->irq, intel_mid_irq_handler); + + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_allow(&pdev->dev); + + return 0; +} + +static struct pci_driver intel_gpio_driver = { + .name = "intel_mid_gpio", + .id_table = intel_gpio_ids, + .probe = intel_gpio_probe, + .driver = { + .pm = &intel_gpio_pm_ops, + }, +}; + +static int __init intel_gpio_init(void) +{ + return pci_register_driver(&intel_gpio_driver); +} + +device_initcall(intel_gpio_init); diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c new file mode 100644 index 000000000000..c22a61be3a9c --- /dev/null +++ b/drivers/gpio/gpio-iop.c @@ -0,0 +1,130 @@ +/* + * arch/arm/plat-iop/gpio.c + * GPIO handling for Intel IOP3xx processors. + * + * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> + * + * 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 <linux/device.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/export.h> +#include <linux/platform_device.h> +#include <linux/bitops.h> +#include <linux/io.h> + +#define IOP3XX_N_GPIOS 8 + +#define GPIO_IN 0 +#define GPIO_OUT 1 +#define GPIO_LOW 0 +#define GPIO_HIGH 1 + +/* Memory base offset */ +static void __iomem *base; + +#define IOP3XX_GPIO_REG(reg) (base + (reg)) +#define IOP3XX_GPOE IOP3XX_GPIO_REG(0x0000) +#define IOP3XX_GPID IOP3XX_GPIO_REG(0x0004) +#define IOP3XX_GPOD IOP3XX_GPIO_REG(0x0008) + +static void gpio_line_config(int line, int direction) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = readl(IOP3XX_GPOE); + if (direction == GPIO_IN) { + val |= BIT(line); + } else if (direction == GPIO_OUT) { + val &= ~BIT(line); + } + writel(val, IOP3XX_GPOE); + local_irq_restore(flags); +} + +static int gpio_line_get(int line) +{ + return !!(readl(IOP3XX_GPID) & BIT(line)); +} + +static void gpio_line_set(int line, int value) +{ + unsigned long flags; + u32 val; + + local_irq_save(flags); + val = readl(IOP3XX_GPOD); + if (value == GPIO_LOW) { + val &= ~BIT(line); + } else if (value == GPIO_HIGH) { + val |= BIT(line); + } + writel(val, IOP3XX_GPOD); + local_irq_restore(flags); +} + +static int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + gpio_line_config(gpio, GPIO_IN); + return 0; +} + +static int iop3xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level) +{ + gpio_line_set(gpio, level); + gpio_line_config(gpio, GPIO_OUT); + return 0; +} + +static int iop3xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + return gpio_line_get(gpio); +} + +static void iop3xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) +{ + gpio_line_set(gpio, value); +} + +static struct gpio_chip iop3xx_chip = { + .label = "iop3xx", + .direction_input = iop3xx_gpio_direction_input, + .get = iop3xx_gpio_get_value, + .direction_output = iop3xx_gpio_direction_output, + .set = iop3xx_gpio_set_value, + .base = 0, + .ngpio = IOP3XX_N_GPIOS, +}; + +static int iop3xx_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + + return gpiochip_add(&iop3xx_chip); +} + +static struct platform_driver iop3xx_gpio_driver = { + .driver = { + .name = "gpio-iop", + .owner = THIS_MODULE, + }, + .probe = iop3xx_gpio_probe, +}; + +static int __init iop3xx_gpio_init(void) +{ + return platform_driver_register(&iop3xx_gpio_driver); +} +arch_initcall(iop3xx_gpio_init); diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c deleted file mode 100644 index bfa1af1b519f..000000000000 --- a/drivers/gpio/gpio-langwell.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Moorestown platform Langwell chip GPIO driver - * - * Copyright (c) 2008, 2009, 2013, 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 - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * 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: - * Moorestown platform Langwell chip. - * Medfield platform Penwell chip. - */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/platform_device.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/stddef.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/gpio.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> -#include <linux/irqdomain.h> - -/* - * Langwell chip has 64 pins and thus there are 2 32bit registers to control - * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit - * registers to control them, so we only define the order here instead of a - * structure, to get a bit offset for a pin (use GPDR as an example): - * - * nreg = ngpio / 32; - * reg = offset / 32; - * bit = offset % 32; - * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; - * - * so the bit of reg_addr is to control pin offset's GPDR feature -*/ - -enum GPIO_REG { - GPLR = 0, /* pin level read-only */ - GPDR, /* pin direction */ - GPSR, /* pin set */ - GPCR, /* pin clear */ - GRER, /* rising edge detect */ - GFER, /* falling edge detect */ - GEDR, /* edge detect result */ - GAFR, /* alt function */ -}; - -struct lnw_gpio { - struct gpio_chip chip; - void __iomem *reg_base; - spinlock_t lock; - struct pci_dev *pdev; - struct irq_domain *domain; -}; - -#define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip) - -static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 32; - - return lnw->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 16; - - return lnw->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); - u32 value = readl(gafr); - int shift = (offset % 16) << 1, af = (value >> shift) & 3; - - if (af) { - value &= ~(3 << shift); - writel(value, gafr); - } - return 0; -} - -static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gplr = gpio_reg(chip, offset, GPLR); - - return readl(gplr) & BIT(offset % 32); -} - -static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - void __iomem *gpsr, *gpcr; - - if (value) { - gpsr = gpio_reg(chip, offset, GPSR); - writel(BIT(offset % 32), gpsr); - } else { - gpcr = gpio_reg(chip, offset, GPCR); - writel(BIT(offset % 32), gpcr); - } -} - -static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - u32 value; - unsigned long flags; - - if (lnw->pdev) - pm_runtime_get(&lnw->pdev->dev); - - spin_lock_irqsave(&lnw->lock, flags); - value = readl(gpdr); - value &= ~BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&lnw->lock, flags); - - if (lnw->pdev) - pm_runtime_put(&lnw->pdev->dev); - - return 0; -} - -static int lnw_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - unsigned long flags; - - lnw_gpio_set(chip, offset, value); - - if (lnw->pdev) - pm_runtime_get(&lnw->pdev->dev); - - spin_lock_irqsave(&lnw->lock, flags); - value = readl(gpdr); - value |= BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&lnw->lock, flags); - - if (lnw->pdev) - pm_runtime_put(&lnw->pdev->dev); - - return 0; -} - -static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct lnw_gpio *lnw = to_lnw_priv(chip); - return irq_create_mapping(lnw->domain, offset); -} - -static int lnw_irq_type(struct irq_data *d, unsigned type) -{ - struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d); - u32 gpio = irqd_to_hwirq(d); - unsigned long flags; - u32 value; - void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); - void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER); - - if (gpio >= lnw->chip.ngpio) - return -EINVAL; - - if (lnw->pdev) - pm_runtime_get(&lnw->pdev->dev); - - spin_lock_irqsave(&lnw->lock, flags); - if (type & IRQ_TYPE_EDGE_RISING) - value = readl(grer) | BIT(gpio % 32); - else - value = readl(grer) & (~BIT(gpio % 32)); - writel(value, grer); - - if (type & IRQ_TYPE_EDGE_FALLING) - value = readl(gfer) | BIT(gpio % 32); - else - value = readl(gfer) & (~BIT(gpio % 32)); - writel(value, gfer); - spin_unlock_irqrestore(&lnw->lock, flags); - - if (lnw->pdev) - pm_runtime_put(&lnw->pdev->dev); - - return 0; -} - -static void lnw_irq_unmask(struct irq_data *d) -{ -} - -static void lnw_irq_mask(struct irq_data *d) -{ -} - -static struct irq_chip lnw_irqchip = { - .name = "LNW-GPIO", - .irq_mask = lnw_irq_mask, - .irq_unmask = lnw_irq_unmask, - .irq_set_type = lnw_irq_type, -}; - -static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), .driver_data = 96 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), .driver_data = 96 }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); - -static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data); - struct irq_chip *chip = irq_data_get_irq_chip(data); - u32 base, gpio, mask; - unsigned long pending; - void __iomem *gedr; - - /* check GPIO controller to check which pin triggered the interrupt */ - for (base = 0; base < lnw->chip.ngpio; base += 32) { - gedr = gpio_reg(&lnw->chip, base, GEDR); - while ((pending = readl(gedr))) { - gpio = __ffs(pending); - mask = BIT(gpio); - /* Clear before handling so we can't lose an edge */ - writel(mask, gedr); - generic_handle_irq(irq_find_mapping(lnw->domain, - base + gpio)); - } - } - - chip->irq_eoi(data); -} - -static void lnw_irq_init_hw(struct lnw_gpio *lnw) -{ - void __iomem *reg; - unsigned base; - - for (base = 0; base < lnw->chip.ngpio; base += 32) { - /* Clear the rising-edge detect register */ - reg = gpio_reg(&lnw->chip, base, GRER); - writel(0, reg); - /* Clear the falling-edge detect register */ - reg = gpio_reg(&lnw->chip, base, GFER); - writel(0, reg); - /* Clear the edge detect status register */ - reg = gpio_reg(&lnw->chip, base, GEDR); - writel(~0, reg); - } -} - -static int lnw_gpio_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) -{ - struct lnw_gpio *lnw = d->host_data; - - irq_set_chip_and_handler_name(virq, &lnw_irqchip, handle_simple_irq, - "demux"); - irq_set_chip_data(virq, lnw); - irq_set_irq_type(virq, IRQ_TYPE_NONE); - - return 0; -} - -static const struct irq_domain_ops lnw_gpio_irq_ops = { - .map = lnw_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static int lnw_gpio_runtime_idle(struct device *dev) -{ - pm_schedule_suspend(dev, 500); - return -EBUSY; -} - -static const struct dev_pm_ops lnw_gpio_pm_ops = { - SET_RUNTIME_PM_OPS(NULL, NULL, lnw_gpio_runtime_idle) -}; - -static int lnw_gpio_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - void __iomem *base; - struct lnw_gpio *lnw; - u32 gpio_base; - u32 irq_base; - int retval; - int ngpio = id->driver_data; - - retval = pcim_enable_device(pdev); - if (retval) - return retval; - - retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev)); - if (retval) { - dev_err(&pdev->dev, "I/O memory mapping error\n"); - return retval; - } - - base = pcim_iomap_table(pdev)[1]; - - irq_base = readl(base); - gpio_base = readl(sizeof(u32) + base); - - /* release the IO mapping, since we already get the info from bar1 */ - pcim_iounmap_regions(pdev, 1 << 1); - - lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL); - if (!lnw) { - dev_err(&pdev->dev, "can't allocate chip data\n"); - return -ENOMEM; - } - - lnw->reg_base = pcim_iomap_table(pdev)[0]; - lnw->chip.label = dev_name(&pdev->dev); - lnw->chip.request = lnw_gpio_request; - lnw->chip.direction_input = lnw_gpio_direction_input; - lnw->chip.direction_output = lnw_gpio_direction_output; - lnw->chip.get = lnw_gpio_get; - lnw->chip.set = lnw_gpio_set; - lnw->chip.to_irq = lnw_gpio_to_irq; - lnw->chip.base = gpio_base; - lnw->chip.ngpio = ngpio; - lnw->chip.can_sleep = 0; - lnw->pdev = pdev; - - spin_lock_init(&lnw->lock); - - lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base, - &lnw_gpio_irq_ops, lnw); - if (!lnw->domain) - return -ENOMEM; - - pci_set_drvdata(pdev, lnw); - retval = gpiochip_add(&lnw->chip); - if (retval) { - dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); - return retval; - } - - lnw_irq_init_hw(lnw); - - irq_set_handler_data(pdev->irq, lnw); - irq_set_chained_handler(pdev->irq, lnw_irq_handler); - - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_allow(&pdev->dev); - - return 0; -} - -static struct pci_driver lnw_gpio_driver = { - .name = "langwell_gpio", - .id_table = lnw_gpio_ids, - .probe = lnw_gpio_probe, - .driver = { - .pm = &lnw_gpio_pm_ops, - }, -}; - -static int __init lnw_gpio_init(void) -{ - return pci_register_driver(&lnw_gpio_driver); -} - -device_initcall(lnw_gpio_init); diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 90a80eb688a9..2d5555decf0c 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -21,6 +21,7 @@ #include <linux/io.h> #include <linux/errno.h> #include <linux/gpio.h> +#include <linux/of.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/module.h> diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 41b5913ddabe..a0804740a0b7 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -242,14 +242,13 @@ static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(lg->domain, offset); } -static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc) { struct irq_data *data = irq_desc_get_irq_data(desc); struct lp_gpio *lg = irq_data_get_irq_handler_data(data); struct irq_chip *chip = irq_data_get_irq_chip(data); u32 base, pin, mask; unsigned long reg, ena, pending; - unsigned virq; /* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < lg->chip.ngpio; base += 32) { @@ -257,12 +256,14 @@ static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc) ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE); while ((pending = (inl(reg) & inl(ena)))) { + unsigned irq; + pin = __ffs(pending); mask = BIT(pin); /* Clear before handling so we don't lose an edge */ outl(mask, reg); - virq = irq_find_mapping(lg->domain, base + pin); - generic_handle_irq(virq); + irq = irq_find_mapping(lg->domain, base + pin); + generic_handle_irq(irq); } } chip->irq_eoi(data); @@ -325,15 +326,15 @@ static void lp_gpio_irq_init_hw(struct lp_gpio *lg) } } -static int lp_gpio_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) +static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct lp_gpio *lg = d->host_data; - irq_set_chip_and_handler_name(virq, &lp_irqchip, handle_simple_irq, + irq_set_chip_and_handler_name(irq, &lp_irqchip, handle_simple_irq, "demux"); - irq_set_chip_data(virq, lg); - irq_set_irq_type(virq, IRQ_TYPE_NONE); + irq_set_chip_data(irq, lg); + irq_set_irq_type(irq, IRQ_TYPE_NONE); return 0; } diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 3fd2caa4a2e0..c0b7835f5136 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -142,7 +142,6 @@ static int mc33880_probe(struct spi_device *spi) return ret; exit_destroy: - spi_set_drvdata(spi, NULL); mutex_destroy(&mc->lock); return ret; } @@ -156,8 +155,6 @@ static int mc33880_remove(struct spi_device *spi) if (mc == NULL) return -ENODEV; - spi_set_drvdata(spi, NULL); - ret = gpiochip_remove(&mc->chip); if (!ret) mutex_destroy(&mc->lock); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index a0b33a216d4a..b350649b9764 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -282,16 +282,16 @@ static struct irq_chip mpc8xxx_irq_chip = { .irq_set_type = mpc8xxx_irq_set_type, }; -static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) +static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) { struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; if (mpc8xxx_gc->of_dev_id_data) mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data; - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq); + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq); return 0; } diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 89675f862308..f319c9ffd4a8 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -514,6 +514,14 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) return -EINVAL; } + retval = gpio_lock_as_irq(&bank->chip, offset); + if (retval) { + dev_err(bank->dev, "unable to lock offset %d for IRQ\n", + offset); + spin_unlock_irqrestore(&bank->lock, flags); + return retval; + } + bank->irq_usage |= 1 << GPIO_INDEX(bank, gpio); spin_unlock_irqrestore(&bank->lock, flags); @@ -797,6 +805,7 @@ static void gpio_irq_shutdown(struct irq_data *d) unsigned offset = GPIO_INDEX(bank, gpio); spin_lock_irqsave(&bank->lock, flags); + gpio_unlock_as_irq(&bank->chip, offset); bank->irq_usage &= ~(1 << offset); _disable_gpio_module(bank, offset); _reset_gpio(bank, gpio); @@ -957,22 +966,13 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value) { struct gpio_bank *bank; unsigned long flags; - int retval = 0; bank = container_of(chip, struct gpio_bank, chip); spin_lock_irqsave(&bank->lock, flags); - - if (LINE_USED(bank->irq_usage, offset)) { - retval = -EINVAL; - goto exit; - } - bank->set_dataout(bank, offset, value); _set_gpio_direction(bank, offset, 0); - -exit: spin_unlock_irqrestore(&bank->lock, flags); - return retval; + return 0; } static int gpio_debounce(struct gpio_chip *chip, unsigned offset, diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 8588af0f7661..11801e986dd9 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -31,6 +31,10 @@ struct palmas_gpio { struct palmas *palmas; }; +struct palmas_device_data { + int ngpio; +}; + static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip) { return container_of(chip, struct palmas_gpio, gpio_chip); @@ -42,23 +46,26 @@ static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset) struct palmas *palmas = pg->palmas; unsigned int val; int ret; + unsigned int reg; + int gpio16 = (offset/8); + + offset %= 8; + reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; - ret = palmas_read(palmas, PALMAS_GPIO_BASE, PALMAS_GPIO_DATA_DIR, &val); + ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val); if (ret < 0) { - dev_err(gc->dev, "GPIO_DATA_DIR read failed, err = %d\n", ret); + dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret); return ret; } - if (val & (1 << offset)) { - ret = palmas_read(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_OUT, &val); - } else { - ret = palmas_read(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_IN, &val); - } + if (val & BIT(offset)) + reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT; + else + reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN; + + ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val); if (ret < 0) { - dev_err(gc->dev, "GPIO_DATA_IN/OUT read failed, err = %d\n", - ret); + dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret); return ret; } return !!(val & BIT(offset)); @@ -70,17 +77,20 @@ static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset, struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas *palmas = pg->palmas; int ret; + unsigned int reg; + int gpio16 = (offset/8); - if (value) - ret = palmas_write(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_SET_DATA_OUT, BIT(offset)); + offset %= 8; + if (gpio16) + reg = (value) ? + PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2; else - ret = palmas_write(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_CLEAR_DATA_OUT, BIT(offset)); + reg = (value) ? + PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT; + + ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset)); if (ret < 0) - dev_err(gc->dev, "%s write failed, err = %d\n", - (value) ? "GPIO_SET_DATA_OUT" : "GPIO_CLEAR_DATA_OUT", - ret); + dev_err(gc->dev, "Reg 0x%02x write failed, %d\n", reg, ret); } static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, @@ -89,14 +99,19 @@ static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset, struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas *palmas = pg->palmas; int ret; + unsigned int reg; + int gpio16 = (offset/8); + + offset %= 8; + reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; /* Set the initial value */ palmas_gpio_set(gc, offset, value); - ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_DIR, BIT(offset), BIT(offset)); + ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, + BIT(offset), BIT(offset)); if (ret < 0) - dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); + dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret); return ret; } @@ -105,11 +120,15 @@ static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset) struct palmas_gpio *pg = to_palmas_gpio(gc); struct palmas *palmas = pg->palmas; int ret; + unsigned int reg; + int gpio16 = (offset/8); + + offset %= 8; + reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR; - ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, - PALMAS_GPIO_DATA_DIR, BIT(offset), 0); + ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0); if (ret < 0) - dev_err(gc->dev, "GPIO_DATA_DIR write failed, err = %d\n", ret); + dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret); return ret; } @@ -121,12 +140,36 @@ static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset); } +static const struct palmas_device_data palmas_dev_data = { + .ngpio = 8, +}; + +static const struct palmas_device_data tps80036_dev_data = { + .ngpio = 16, +}; + +static struct of_device_id of_palmas_gpio_match[] = { + { .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,}, + { .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,}, + { .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,}, + { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,}, + { }, +}; +MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); + static int palmas_gpio_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_platform_data *palmas_pdata; struct palmas_gpio *palmas_gpio; int ret; + const struct of_device_id *match; + const struct palmas_device_data *dev_data; + + match = of_match_device(of_palmas_gpio_match, &pdev->dev); + dev_data = match->data; + if (!dev_data) + dev_data = &palmas_dev_data; palmas_gpio = devm_kzalloc(&pdev->dev, sizeof(*palmas_gpio), GFP_KERNEL); @@ -138,7 +181,7 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio->palmas = palmas; palmas_gpio->gpio_chip.owner = THIS_MODULE; palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); - palmas_gpio->gpio_chip.ngpio = 8; + palmas_gpio->gpio_chip.ngpio = dev_data->ngpio; palmas_gpio->gpio_chip.can_sleep = 1; palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; @@ -172,15 +215,6 @@ static int palmas_gpio_remove(struct platform_device *pdev) return gpiochip_remove(&palmas_gpio->gpio_chip); } -static struct of_device_id of_palmas_gpio_match[] = { - { .compatible = "ti,palmas-gpio"}, - { .compatible = "ti,tps65913-gpio"}, - { .compatible = "ti,tps65914-gpio"}, - { .compatible = "ti,tps80036-gpio"}, - { }, -}; -MODULE_DEVICE_TABLE(of, of_palmas_gpio_match); - static struct platform_driver palmas_gpio_driver = { .driver.name = "palmas-gpio", .driver.owner = THIS_MODULE, diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index cdd1aa12b895..6e48c07e3d8c 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -683,17 +683,6 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) int ret; u8 val[MAX_BANK]; - /* Let every port in proper state, that could save power */ - memset(val, 0, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_PUPD, val); - memset(val, 0xFF, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_CFG, val); - memset(val, 0, NBANK(chip)); - pca953x_write_regs(chip, PCA957X_OUT, val); - - ret = pca953x_read_regs(chip, PCA957X_IN, val); - if (ret) - goto out; ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output); if (ret) goto out; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 9e61bb0719d0..1535686e74ea 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -26,9 +26,10 @@ #include <linux/irqdomain.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <linux/spinlock.h> -#include <linux/workqueue.h> static const struct i2c_device_id pcf857x_id[] = { @@ -50,6 +51,27 @@ static const struct i2c_device_id pcf857x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pcf857x_id); +#ifdef CONFIG_OF +static const struct of_device_id pcf857x_of_table[] = { + { .compatible = "nxp,pcf8574" }, + { .compatible = "nxp,pcf8574a" }, + { .compatible = "nxp,pca8574" }, + { .compatible = "nxp,pca9670" }, + { .compatible = "nxp,pca9672" }, + { .compatible = "nxp,pca9674" }, + { .compatible = "nxp,pcf8575" }, + { .compatible = "nxp,pca8575" }, + { .compatible = "nxp,pca9671" }, + { .compatible = "nxp,pca9673" }, + { .compatible = "nxp,pca9675" }, + { .compatible = "maxim,max7328" }, + { .compatible = "maxim,max7329" }, + { .compatible = "ti,tca9554" }, + { } +}; +MODULE_DEVICE_TABLE(of, pcf857x_of_table); +#endif + /* * The pcf857x, pca857x, and pca967x chips only expose one read and one * write register. Writing a "one" bit (to match the reset state) lets @@ -66,12 +88,11 @@ struct pcf857x { struct gpio_chip chip; struct i2c_client *client; struct mutex lock; /* protect 'out' */ - struct work_struct work; /* irq demux work */ struct irq_domain *irq_domain; /* for irq demux */ spinlock_t slock; /* protect irq demux */ unsigned out; /* software latch */ unsigned status; /* current status */ - int irq; /* real irq number */ + unsigned irq_mapped; /* mapped gpio irqs */ int (*write)(struct i2c_client *client, unsigned data); int (*read)(struct i2c_client *client); @@ -164,48 +185,54 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset) { struct pcf857x *gpio = container_of(chip, struct pcf857x, chip); + int ret; - return irq_create_mapping(gpio->irq_domain, offset); + ret = irq_create_mapping(gpio->irq_domain, offset); + if (ret > 0) + gpio->irq_mapped |= (1 << offset); + + return ret; } -static void pcf857x_irq_demux_work(struct work_struct *work) +static irqreturn_t pcf857x_irq(int irq, void *data) { - struct pcf857x *gpio = container_of(work, - struct pcf857x, - work); + struct pcf857x *gpio = data; unsigned long change, i, status, flags; status = gpio->read(gpio->client); spin_lock_irqsave(&gpio->slock, flags); - change = gpio->status ^ status; + /* + * call the interrupt handler iff gpio is used as + * interrupt source, just to avoid bad irqs + */ + + change = ((gpio->status ^ status) & gpio->irq_mapped); for_each_set_bit(i, &change, gpio->chip.ngpio) generic_handle_irq(irq_find_mapping(gpio->irq_domain, i)); gpio->status = status; spin_unlock_irqrestore(&gpio->slock, flags); -} - -static irqreturn_t pcf857x_irq_demux(int irq, void *data) -{ - struct pcf857x *gpio = data; - - /* - * pcf857x can't read/write data here, - * since i2c data access might go to sleep. - */ - schedule_work(&gpio->work); return IRQ_HANDLED; } -static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int virq, +static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, + struct pcf857x *gpio = domain->host_data; + + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_level_irq); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + gpio->irq_mapped |= (1 << hw); + return 0; } @@ -218,8 +245,6 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) if (gpio->irq_domain) irq_domain_remove(gpio->irq_domain); - if (gpio->irq) - free_irq(gpio->irq, gpio); } static int pcf857x_irq_domain_init(struct pcf857x *gpio, @@ -230,20 +255,21 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio, gpio->irq_domain = irq_domain_add_linear(client->dev.of_node, gpio->chip.ngpio, &pcf857x_irq_domain_ops, - NULL); + gpio); if (!gpio->irq_domain) goto fail; /* enable real irq */ - status = request_irq(client->irq, pcf857x_irq_demux, 0, - dev_name(&client->dev), gpio); + status = devm_request_threaded_irq(&client->dev, client->irq, + NULL, pcf857x_irq, IRQF_ONESHOT | + IRQF_TRIGGER_FALLING, + dev_name(&client->dev), gpio); + if (status) goto fail; /* enable gpio_to_irq() */ - INIT_WORK(&gpio->work, pcf857x_irq_demux_work); gpio->chip.to_irq = pcf857x_to_irq; - gpio->irq = client->irq; return 0; @@ -257,14 +283,18 @@ fail: static int pcf857x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct pcf857x_platform_data *pdata; + struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); + struct device_node *np = client->dev.of_node; struct pcf857x *gpio; + unsigned int n_latch = 0; int status; - pdata = dev_get_platdata(&client->dev); - if (!pdata) { + if (IS_ENABLED(CONFIG_OF) && np) + of_property_read_u32(np, "lines-initial-states", &n_latch); + else if (pdata) + n_latch = pdata->n_latch; + else dev_dbg(&client->dev, "no platform data\n"); - } /* Allocate, initialize, and register this gpio_chip. */ gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); @@ -357,11 +387,11 @@ static int pcf857x_probe(struct i2c_client *client, * may cause transient glitching since it can't know the last value * written (some pins may need to be driven low). * - * Using pdata->n_latch avoids that trouble. When left initialized - * to zero, our software copy of the "latch" then matches the chip's - * all-ones reset state. Otherwise it flags pins to be driven low. + * Using n_latch avoids that trouble. When left initialized to zero, + * our software copy of the "latch" then matches the chip's all-ones + * reset state. Otherwise it flags pins to be driven low. */ - gpio->out = pdata ? ~pdata->n_latch : ~0; + gpio->out = ~n_latch; gpio->status = gpio->out; status = gpiochip_add(&gpio->chip); @@ -423,6 +453,7 @@ static struct i2c_driver pcf857x_driver = { .driver = { .name = "pcf857x", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(pcf857x_of_table), }, .probe = pcf857x_probe, .remove = pcf857x_remove, diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 4274e2e70ef8..f22f7f3e2e53 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -238,15 +238,15 @@ static struct irq_chip pl061_irqchip = { .irq_set_type = pl061_irq_type, }; -static int pl061_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) +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_name(virq, &pl061_irqchip, handle_simple_irq, + irq_set_chip_and_handler_name(irq, &pl061_irqchip, handle_simple_irq, "pl061"); - irq_set_chip_data(virq, chip); - irq_set_irq_type(virq, IRQ_TYPE_NONE); + irq_set_chip_data(irq, chip); + irq_set_irq_type(irq, IRQ_TYPE_NONE); return 0; } diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 6038966ab045..d3f15ae93bd3 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -22,6 +22,7 @@ #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_data/gpio-rcar.h> #include <linux/platform_device.h> @@ -266,16 +267,16 @@ static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); } -static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) +static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq, + irq_hw_number_t hwirq) { struct gpio_rcar_priv *p = h->host_data; - dev_dbg(&p->pdev->dev, "map hw irq = %d, virq = %d\n", (int)hw, virq); + dev_dbg(&p->pdev->dev, "map hw irq = %d, irq = %d\n", (int)hwirq, irq); - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); /* kill me now */ + irq_set_chip_data(irq, h->host_data); + irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); /* kill me now */ return 0; } diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index b33bad1bb4df..2647e243d471 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -254,9 +254,10 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = bank * 8 + bit; - int virq = irq_find_mapping(stmpe_gpio->domain, line); + int child_irq = irq_find_mapping(stmpe_gpio->domain, + line); - handle_nested_irq(virq); + handle_nested_irq(child_irq); stat &= ~(1 << bit); } @@ -271,7 +272,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, +static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct stmpe_gpio *stmpe_gpio = d->host_data; @@ -279,26 +280,26 @@ static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, if (!stmpe_gpio) return -EINVAL; - irq_set_chip_data(hwirq, stmpe_gpio); - irq_set_chip_and_handler(hwirq, &stmpe_gpio_irq_chip, + irq_set_chip_data(irq, stmpe_gpio); + irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip, handle_simple_irq); - irq_set_nested_thread(hwirq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM - set_irq_flags(hwirq, IRQF_VALID); + set_irq_flags(irq, IRQF_VALID); #else - irq_set_noprobe(hwirq); + irq_set_noprobe(irq); #endif return 0; } -static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) +static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) { #ifdef CONFIG_ARM - set_irq_flags(virq, 0); + set_irq_flags(irq, 0); #endif - irq_set_chip_and_handler(virq, NULL, NULL); - irq_set_chip_data(virq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 4a5de273c230..ddb5fefaa715 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -96,27 +96,27 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, } /** - * tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * tc3589x_gpio_irq_get_irq(): Map a hardware IRQ on a chip to a Linux IRQ * * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on. - * @irq: index of the interrupt requested in the chip IRQs + * @irq: index of the hardware interrupt requested in the chip IRQs * * Useful for drivers to request their own IRQs. */ -static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio, - int irq) +static int tc3589x_gpio_irq_get_irq(struct tc3589x_gpio *tc3589x_gpio, + int hwirq) { if (!tc3589x_gpio) return -EINVAL; - return irq_create_mapping(tc3589x_gpio->domain, irq); + return irq_create_mapping(tc3589x_gpio->domain, hwirq); } static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); - return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset); + return tc3589x_gpio_irq_get_irq(tc3589x_gpio, offset); } static struct gpio_chip template_chip = { @@ -242,9 +242,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = i * 8 + bit; - int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line); + int irq = tc3589x_gpio_irq_get_irq(tc3589x_gpio, line); - handle_nested_irq(virq); + handle_nested_irq(irq); stat &= ~(1 << bit); } @@ -254,31 +254,31 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq, +static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { struct tc3589x *tc3589x_gpio = d->host_data; - irq_set_chip_data(virq, tc3589x_gpio); - irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip, + irq_set_chip_data(irq, tc3589x_gpio); + irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, handle_simple_irq); - irq_set_nested_thread(virq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM - set_irq_flags(virq, IRQF_VALID); + set_irq_flags(irq, IRQF_VALID); #else - irq_set_noprobe(virq); + irq_set_noprobe(irq); #endif return 0; } -static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) +static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) { #ifdef CONFIG_ARM - set_irq_flags(virq, 0); + set_irq_flags(irq, 0); #endif - irq_set_chip_and_handler(virq, NULL, NULL); - irq_set_chip_data(virq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } static struct irq_domain_ops tc3589x_irq_ops = { diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 9a62672f1bed..cfd3b9037bc7 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -75,6 +75,7 @@ struct tegra_gpio_bank { #endif }; +static struct device *dev; static struct irq_domain *irq_domain; static void __iomem *regs; static u32 tegra_gpio_bank_count; @@ -205,6 +206,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) int lvl_type; int val; unsigned long flags; + int ret; switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_RISING: @@ -231,6 +233,12 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } + ret = gpio_lock_as_irq(&tegra_gpio_chip, gpio); + if (ret) { + dev_err(dev, "unable to lock Tegra GPIO %d as IRQ\n", gpio); + return ret; + } + spin_lock_irqsave(&bank->lvl_lock[port], flags); val = tegra_gpio_readl(GPIO_INT_LVL(gpio)); @@ -251,6 +259,13 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } +static void tegra_gpio_irq_shutdown(struct irq_data *d) +{ + int gpio = d->hwirq; + + gpio_unlock_as_irq(&tegra_gpio_chip, gpio); +} + static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { struct tegra_gpio_bank *bank; @@ -368,6 +383,7 @@ static struct irq_chip tegra_gpio_irq_chip = { .irq_mask = tegra_gpio_irq_mask, .irq_unmask = tegra_gpio_irq_unmask, .irq_set_type = tegra_gpio_irq_set_type, + .irq_shutdown = tegra_gpio_irq_shutdown, #ifdef CONFIG_PM_SLEEP .irq_set_wake = tegra_gpio_irq_set_wake, #endif @@ -413,6 +429,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) int i; int j; + dev = &pdev->dev; + match = of_match_device(tegra_gpio_of_match, &pdev->dev); if (!match) { dev_err(&pdev->dev, "Error: No device match found\n"); diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index d8e4f6efcb29..0c7e891c8651 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -594,7 +594,7 @@ static struct platform_driver gpio_twl4030_driver = { .driver = { .name = "twl4030_gpio", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(twl_gpio_match), + .of_match_table = twl_gpio_match, }, .probe = gpio_twl4030_probe, .remove = gpio_twl4030_remove, diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 5c1ef2b3ef18..1745ce5983d6 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -73,15 +73,8 @@ 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_object_list args; - union acpi_object arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = evt_pin->pin; - args.count = 1; - args.pointer = &arg; - - acpi_evaluate_object(evt_pin->evt_handle, NULL, &args, NULL); + acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin); return IRQ_HANDLED; } @@ -201,6 +194,44 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) } EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); +/** + * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. + * @chip: 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. + */ +void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) +{ + acpi_handle handle; + acpi_status status; + struct list_head *evt_pins; + struct acpi_gpio_evt_pin *evt_pin, *ep; + + 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) { + 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); +} +EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); + struct acpi_gpio_lookup { struct acpi_gpio_info info; int index; @@ -278,41 +309,3 @@ int acpi_get_gpio_by_index(struct device *dev, int index, return lookup.gpio; } EXPORT_SYMBOL_GPL(acpi_get_gpio_by_index); - -/** - * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. - * @chip: 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. - */ -void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) -{ - acpi_handle handle; - acpi_status status; - struct list_head *evt_pins; - struct acpi_gpio_evt_pin *evt_pin, *ep; - - 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) { - 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); -} -EXPORT_SYMBOL(acpi_gpiochip_free_interrupts); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 0dee0e0c247a..d66139dc410d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -60,6 +60,7 @@ struct gpio_desc { #define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */ #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ +#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ #define ID_SHIFT 16 /* add new flags before this one */ @@ -96,12 +97,47 @@ static int gpiod_get_value(const struct gpio_desc *desc); static void gpiod_set_value(struct gpio_desc *desc, int value); static int gpiod_cansleep(const struct gpio_desc *desc); static int gpiod_to_irq(const struct gpio_desc *desc); +static int gpiod_lock_as_irq(struct gpio_desc *desc); +static void gpiod_unlock_as_irq(struct gpio_desc *desc); static int gpiod_export(struct gpio_desc *desc, bool direction_may_change); static int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc); static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value); static void gpiod_unexport(struct gpio_desc *desc); +#ifdef CONFIG_DEBUG_FS +#define gpiod_emerg(desc, fmt, ...) \ + pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_crit(desc, fmt, ...) \ + pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_err(desc, fmt, ...) \ + pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_warn(desc, fmt, ...) \ + pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_info(desc, fmt, ...) \ + pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#define gpiod_dbg(desc, fmt, ...) \ + pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ + ##__VA_ARGS__) +#else +#define gpiod_emerg(desc, fmt, ...) \ + pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_crit(desc, fmt, ...) \ + pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_err(desc, fmt, ...) \ + pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_warn(desc, fmt, ...) \ + pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_info(desc, fmt, ...) \ + pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#define gpiod_dbg(desc, fmt, ...) \ + pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) +#endif static inline void desc_set_label(struct gpio_desc *d, const char *label) { @@ -130,6 +166,17 @@ static struct gpio_desc *gpio_to_desc(unsigned gpio) } /** + * Convert an offset on a certain chip to a corresponding descriptor + */ +static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip, + unsigned int offset) +{ + unsigned int gpio = chip->base + offset; + + return gpio_to_desc(gpio); +} + +/** * Convert a GPIO descriptor to the integer namespace. * This should disappear in the future but is needed since we still * use GPIO numbers for error messages and sysfs nodes @@ -395,6 +442,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, desc->flags &= ~GPIO_TRIGGER_MASK; if (!gpio_flags) { + gpiod_unlock_as_irq(desc); ret = 0; goto free_id; } @@ -433,6 +481,12 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, if (ret < 0) goto free_id; + ret = gpiod_lock_as_irq(desc); + if (ret < 0) { + gpiod_warn(desc, "failed to flag the GPIO for IRQ\n"); + goto free_id; + } + desc->flags |= gpio_flags; return 0; @@ -1637,8 +1691,9 @@ static int gpiod_direction_input(struct gpio_desc *desc) chip = desc->chip; if (!chip->get || !chip->direction_input) { - pr_warn("%s: missing get() or direction_input() operations\n", - __func__); + gpiod_warn(desc, + "%s: missing get() or direction_input() operations\n", + __func__); return -EIO; } @@ -1658,8 +1713,7 @@ static int gpiod_direction_input(struct gpio_desc *desc) if (status) { status = chip->request(chip, offset); if (status < 0) { - pr_debug("GPIO-%d: chip request fail, %d\n", - desc_to_gpio(desc), status); + gpiod_dbg(desc, "chip request fail, %d\n", status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1677,8 +1731,7 @@ lose: fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - pr_debug("%s: gpio-%d status %d\n", __func__, - desc_to_gpio(desc), status); + gpiod_dbg(desc, "%s status %d\n", __func__, status); return status; } @@ -1700,6 +1753,14 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) return -EINVAL; } + /* GPIOs used for IRQs shall not be set as output */ + if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { + gpiod_err(desc, + "%s: tried to set a GPIO tied to an IRQ as output\n", + __func__); + return -EIO; + } + /* Open drain pin should not be driven to 1 */ if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) return gpiod_direction_input(desc); @@ -1710,8 +1771,9 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) chip = desc->chip; if (!chip->set || !chip->direction_output) { - pr_warn("%s: missing set() or direction_output() operations\n", - __func__); + gpiod_warn(desc, + "%s: missing set() or direction_output() operations\n", + __func__); return -EIO; } @@ -1731,8 +1793,7 @@ static int gpiod_direction_output(struct gpio_desc *desc, int value) if (status) { status = chip->request(chip, offset); if (status < 0) { - pr_debug("GPIO-%d: chip request fail, %d\n", - desc_to_gpio(desc), status); + gpiod_dbg(desc, "chip request fail, %d\n", status); /* and it's not available to anyone else ... * gpio_request() is the fully clean solution. */ @@ -1750,8 +1811,7 @@ lose: fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - pr_debug("%s: gpio-%d status %d\n", __func__, - desc_to_gpio(desc), status); + gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } @@ -1783,8 +1843,9 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) chip = desc->chip; if (!chip->set || !chip->set_debounce) { - pr_debug("%s: missing set() or set_debounce() operations\n", - __func__); + gpiod_dbg(desc, + "%s: missing set() or set_debounce() operations\n", + __func__); return -ENOTSUPP; } @@ -1806,8 +1867,7 @@ static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) - pr_debug("%s: gpio-%d status %d\n", __func__, - desc_to_gpio(desc), status); + gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } @@ -1840,6 +1900,19 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce); * that the GPIO was actually requested. */ +static int _gpiod_get_value(const struct gpio_desc *desc) +{ + struct gpio_chip *chip; + int value; + int offset; + + chip = desc->chip; + offset = gpio_chip_hwgpio(desc); + value = chip->get ? chip->get(chip, offset) : 0; + trace_gpio_value(desc_to_gpio(desc), 1, value); + return value; +} + /** * __gpio_get_value() - return a gpio's value * @gpio: gpio whose value will be returned @@ -1851,19 +1924,11 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce); */ static int gpiod_get_value(const struct gpio_desc *desc) { - struct gpio_chip *chip; - int value; - int offset; - if (!desc) return 0; - chip = desc->chip; - offset = gpio_chip_hwgpio(desc); /* Should be using gpio_get_value_cansleep() */ - WARN_ON(chip->can_sleep); - value = chip->get ? chip->get(chip, offset) : 0; - trace_gpio_value(desc_to_gpio(desc), 1, value); - return value; + WARN_ON(desc->chip->can_sleep); + return _gpiod_get_value(desc); } int __gpio_get_value(unsigned gpio) @@ -1895,8 +1960,9 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) } trace_gpio_direction(desc_to_gpio(desc), value, err); if (err < 0) - pr_err("%s: Error in set_value for open drain gpio%d err %d\n", - __func__, desc_to_gpio(desc), err); + gpiod_err(desc, + "%s: Error in set_value for open drain err %d\n", + __func__, err); } /* @@ -1922,8 +1988,23 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) } trace_gpio_direction(desc_to_gpio(desc), !value, err); if (err < 0) - pr_err("%s: Error in set_value for open source gpio%d err %d\n", - __func__, desc_to_gpio(desc), err); + gpiod_err(desc, + "%s: Error in set_value for open source err %d\n", + __func__, err); +} + +static void _gpiod_set_value(struct gpio_desc *desc, int value) +{ + struct gpio_chip *chip; + + chip = desc->chip; + trace_gpio_value(desc_to_gpio(desc), 0, value); + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + _gpio_set_open_drain_value(desc, value); + else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + _gpio_set_open_source_value(desc, value); + else + chip->set(chip, gpio_chip_hwgpio(desc), value); } /** @@ -1937,20 +2018,12 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) */ static void gpiod_set_value(struct gpio_desc *desc, int value) { - struct gpio_chip *chip; if (!desc) return; - chip = desc->chip; /* Should be using gpio_set_value_cansleep() */ - WARN_ON(chip->can_sleep); - trace_gpio_value(desc_to_gpio(desc), 0, value); - if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - _gpio_set_open_drain_value(desc, value); - else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - _gpio_set_open_source_value(desc, value); - else - chip->set(chip, gpio_chip_hwgpio(desc), value); + WARN_ON(desc->chip->can_sleep); + _gpiod_set_value(desc, value); } void __gpio_set_value(unsigned gpio, int value) @@ -2008,6 +2081,58 @@ int __gpio_to_irq(unsigned gpio) } EXPORT_SYMBOL_GPL(__gpio_to_irq); +/** + * gpiod_lock_as_irq() - lock a GPIO to be used as 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. + */ +static int gpiod_lock_as_irq(struct gpio_desc *desc) +{ + if (!desc) + return -EINVAL; + + if (test_bit(FLAG_IS_OUT, &desc->flags)) { + gpiod_err(desc, + "%s: tried to flag a GPIO set as output for IRQ\n", + __func__); + return -EIO; + } + + set_bit(FLAG_USED_AS_IRQ, &desc->flags); + return 0; +} + +int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset)); +} +EXPORT_SYMBOL_GPL(gpio_lock_as_irq); + +/** + * gpiod_unlock_as_irq() - unlock a GPIO used as IRQ + * @gpio: the GPIO line to unlock from IRQ usage + * + * This is used directly by GPIO drivers that want to indicate + * that a certain GPIO is no longer used exclusively for IRQ. + */ +static void gpiod_unlock_as_irq(struct gpio_desc *desc) +{ + if (!desc) + return; + + clear_bit(FLAG_USED_AS_IRQ, &desc->flags); +} + +void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) +{ + return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset)); +} +EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); /* There's no value in making it easy to inline GPIO calls that may sleep. * Common examples include ones connected to I2C or SPI chips. @@ -2015,18 +2140,10 @@ EXPORT_SYMBOL_GPL(__gpio_to_irq); static int gpiod_get_value_cansleep(const struct gpio_desc *desc) { - struct gpio_chip *chip; - int value; - int offset; - might_sleep_if(extra_checks); if (!desc) return 0; - chip = desc->chip; - offset = gpio_chip_hwgpio(desc); - value = chip->get ? chip->get(chip, offset) : 0; - trace_gpio_value(desc_to_gpio(desc), 1, value); - return value; + return _gpiod_get_value(desc); } int gpio_get_value_cansleep(unsigned gpio) @@ -2037,19 +2154,10 @@ EXPORT_SYMBOL_GPL(gpio_get_value_cansleep); static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) { - struct gpio_chip *chip; - might_sleep_if(extra_checks); if (!desc) return; - chip = desc->chip; - trace_gpio_value(desc_to_gpio(desc), 0, value); - if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) - _gpio_set_open_drain_value(desc, value); - else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) - _gpio_set_open_source_value(desc, value); - else - chip->set(chip, gpio_chip_hwgpio(desc), value); + _gpiod_set_value(desc, value); } void gpio_set_value_cansleep(unsigned gpio, int value) @@ -2066,6 +2174,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; struct gpio_desc *gdesc = &chip->desc[0]; int is_out; + int is_irq; for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) @@ -2073,12 +2182,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) gpiod_get_direction(gdesc); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); - seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", + is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags); + seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s", gpio, gdesc->label, is_out ? "out" : "in ", chip->get ? (chip->get(chip, i) ? "hi" : "lo") - : "? "); + : "? ", + is_irq ? "IRQ" : " "); seq_printf(s, "\n"); } } |