diff options
Diffstat (limited to 'drivers/gpio')
60 files changed, 2633 insertions, 1318 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 697338772b6..4a1b5113e52 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -55,6 +55,10 @@ config GPIO_ACPI def_bool y depends on ACPI +config GPIOLIB_IRQCHIP + select IRQ_DOMAIN + bool + config DEBUG_GPIO bool "Debug GPIO calls" depends on DEBUG_KERNEL @@ -128,6 +132,15 @@ config GPIO_GENERIC_PLATFORM help Say yes here to support basic platform_device memory-mapped GPIO controllers. +config GPIO_DWAPB + tristate "Synopsys DesignWare APB GPIO driver" + select GPIO_GENERIC + select GENERIC_IRQ_CHIP + depends on OF_GPIO + help + Say Y or M here to build support for the Synopsys DesignWare APB + GPIO block. + config GPIO_IT8761E tristate "IT8761E GPIO support" depends on X86 # unconditional access to IO space. @@ -145,6 +158,12 @@ config GPIO_EP93XX depends on ARCH_EP93XX select GPIO_GENERIC +config GPIO_ZEVIO + bool "LSI ZEVIO SoC memory mapped GPIOs" + depends on ARM && OF_GPIO + help + Say yes here to support the GPIO controller in LSI ZEVIO SoCs. + config GPIO_MM_LANTIQ bool "Lantiq Memory mapped GPIOs" depends on LANTIQ && SOC_XWAY @@ -192,7 +211,7 @@ config GPIO_MSM_V1 config GPIO_MSM_V2 tristate "Qualcomm MSM GPIO v2" - depends on GPIOLIB && OF && ARCH_MSM + depends on GPIOLIB && OF && ARCH_QCOM help Say yes here to support the GPIO interface on ARM v7 based Qualcomm MSM chips. Most of the pins on the MSM can be @@ -225,10 +244,20 @@ config GPIO_OCTEON Say yes here to support the on-chip GPIO lines on the OCTEON family of SOCs. +config GPIO_OMAP + bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS + default y if ARCH_OMAP + depends on ARM + select GENERIC_IRQ_CHIP + select GPIOLIB_IRQCHIP + help + Say yes here to enable GPIO support for TI OMAP SoCs. + config GPIO_PL061 bool "PrimeCell PL061 GPIO support" depends on ARM_AMBA - select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + select GPIOLIB_IRQCHIP help Say yes here to support the PrimeCell PL061 GPIO device @@ -240,7 +269,7 @@ config GPIO_PXA config GPIO_RCAR tristate "Renesas R-Car GPIO" - depends on ARM + depends on ARM && (ARCH_SHMOBILE || COMPILE_TEST) help Say yes here to support GPIO on Renesas R-Car SoCs. @@ -275,8 +304,15 @@ config GPIO_STA2X11 Say yes here to support the STA2x11/ConneXt GPIO device. The GPIO module has 128 GPIO pins with alternate functions. +config GPIO_SYSCON + tristate "GPIO based on SYSCON" + depends on MFD_SYSCON && OF + help + Say yes here to support GPIO functionality though SYSCON driver. + config GPIO_TS5500 tristate "TS-5500 DIO blocks and compatibles" + depends on TS5500 || COMPILE_TEST help This driver supports Digital I/O exposed by pin blocks found on some Technologic Systems platforms. It includes, but is not limited to, 3 @@ -403,6 +439,7 @@ config GPIO_GRGPIO config GPIO_TB10X bool + select GENERIC_IRQ_CHIP select OF_GPIO comment "I2C GPIO expanders:" @@ -461,7 +498,7 @@ config GPIO_MC9S08DZ60 Select this to enable the MC9S08DZ60 GPIO driver config GPIO_PCA953X - tristate "PCA953x, PCA955x, PCA957x, TCA64xx, and MAX7310 I/O ports" + tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports" depends on I2C help Say yes here to provide access to several register-oriented @@ -471,14 +508,19 @@ config GPIO_PCA953X 4 bits: pca9536, pca9537 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554, - pca9556, pca9557, pca9574, tca6408 + pca9556, pca9557, pca9574, tca6408, xra1202 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575, tca6416 + 24 bits: tca6424 + + 40 bits: pca9505, pca9698 + config GPIO_PCA953X_IRQ bool "Interrupt controller support for PCA953x" depends on GPIO_PCA953X=y + select GPIOLIB_IRQCHIP help Say yes here to enable the pca953x to be used as an interrupt controller. It requires the driver to be built in the kernel. @@ -548,6 +590,7 @@ config GPIO_STP_XWAY config GPIO_TC3589X bool "TC3589X GPIOs" depends on MFD_TC3589X + select GPIOLIB_IRQCHIP help This enables support for the GPIOs found on the TC3589X I/O Expander. @@ -629,7 +672,7 @@ comment "PCI GPIO expanders:" config GPIO_CS5535 tristate "AMD CS5535/CS5536 GPIO support" - depends on PCI && X86 && MFD_CS5535 + depends on MFD_CS5535 help The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that can be used for quite a number of things. The CS5535/6 is found on @@ -641,7 +684,7 @@ config GPIO_BT8XX tristate "BT8XX GPIO abuser" depends on PCI && VIDEO_BT848=n help - The BT8xx frame grabber chip has 24 GPIO pins than can be abused + The BT8xx frame grabber chip has 24 GPIO pins that can be abused as a cheap PCI GPIO card. This chip can be found on Miro, Hauppauge and STB TV-cards. @@ -668,13 +711,13 @@ config GPIO_AMD8111 config GPIO_INTEL_MID bool "Intel Mid GPIO support" depends on PCI && X86 - select IRQ_DOMAIN + select GPIOLIB_IRQCHIP help Say Y here to support Intel Mid GPIO. config GPIO_PCH tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO" - depends on PCI && X86 + depends on PCI && (X86_32 || COMPILE_TEST) select GENERIC_IRQ_CHIP help This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff @@ -708,7 +751,7 @@ config GPIO_SODAVILLE config GPIO_TIMBERDALE bool "Support for timberdale GPIO IP" - depends on MFD_TIMBERDALE && HAS_IOMEM + depends on MFD_TIMBERDALE ---help--- Add support for the GPIO IP in the timberdale FPGA. diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 5d50179ece1..d10f6a9d875 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o +obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o @@ -57,7 +58,7 @@ obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o -obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o +obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o @@ -76,11 +77,11 @@ obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o +obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o -obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o @@ -99,3 +100,4 @@ obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o +obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 307464fd015..65978cf85f7 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -52,6 +52,22 @@ struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, EXPORT_SYMBOL(devm_gpiod_get); /** + * devm_gpiod_get_optional - Resource-managed gpiod_get_optional() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * + * Managed gpiod_get_optional(). GPIO descriptors returned from this function + * are automatically disposed on driver detach. See gpiod_get_optional() for + * detailed information about behavior and return values. + */ +struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, + const char *con_id) +{ + return devm_gpiod_get_index_optional(dev, con_id, 0); +} +EXPORT_SYMBOL(devm_gpiod_get_optional); + +/** * devm_gpiod_get_index - Resource-managed gpiod_get_index() * @dev: GPIO consumer * @con_id: function within the GPIO consumer @@ -87,6 +103,33 @@ struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, EXPORT_SYMBOL(devm_gpiod_get_index); /** + * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional() + * @dev: GPIO consumer + * @con_id: function within the GPIO consumer + * @index: index of the GPIO to obtain in the consumer + * + * Managed gpiod_get_index_optional(). GPIO descriptors returned from this + * function are automatically disposed on driver detach. See + * gpiod_get_index_optional() for detailed information about behavior and + * return values. + */ +struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev, + const char *con_id, + unsigned int index) +{ + struct gpio_desc *desc; + + desc = devm_gpiod_get_index(dev, con_id, index); + if (IS_ERR(desc)) { + if (PTR_ERR(desc) == -ENOENT) + return NULL; + } + + return desc; +} +EXPORT_SYMBOL(devm_gpiod_get_index_optional); + +/** * devm_gpiod_put - Resource-managed gpiod_put() * @desc: GPIO descriptor to dispose of * diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 6fc6206b38b..b2239d678d0 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -408,24 +408,23 @@ static void adnp_irq_bus_unlock(struct irq_data *data) mutex_unlock(&adnp->irq_lock); } -static unsigned int adnp_irq_startup(struct irq_data *data) +static int adnp_irq_reqres(struct irq_data *data) { struct adnp *adnp = irq_data_get_irq_chip_data(data); - if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) + if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) { dev_err(adnp->gpio.dev, "unable to lock HW IRQ %lu for IRQ\n", data->hwirq); - /* Satisfy the .enable semantics by unmasking the line */ - adnp_irq_unmask(data); + return -EINVAL; + } return 0; } -static void adnp_irq_shutdown(struct irq_data *data) +static void adnp_irq_relres(struct irq_data *data) { struct adnp *adnp = irq_data_get_irq_chip_data(data); - adnp_irq_mask(data); gpio_unlock_as_irq(&adnp->gpio, data->hwirq); } @@ -436,8 +435,8 @@ static struct irq_chip adnp_irq_chip = { .irq_set_type = adnp_irq_set_type, .irq_bus_lock = adnp_irq_bus_lock, .irq_bus_sync_unlock = adnp_irq_bus_unlock, - .irq_startup = adnp_irq_startup, - .irq_shutdown = adnp_irq_shutdown, + .irq_request_resources = adnp_irq_reqres, + .irq_release_resources = adnp_irq_relres, }; static int adnp_irq_map(struct irq_domain *domain, unsigned int irq, diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index 613265944e2..f1ade8fa321 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -106,10 +106,8 @@ static int adp5520_gpio_probe(struct platform_device *pdev) } dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&pdev->dev, "failed to alloc memory\n"); + if (dev == NULL) return -ENOMEM; - } dev->master = pdev->dev.parent; diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 3f190e68f97..ef19bc33f2b 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -67,9 +67,20 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off) { struct adp5588_gpio *dev = container_of(chip, struct adp5588_gpio, gpio_chip); + unsigned bank = ADP5588_BANK(off); + unsigned bit = ADP5588_BIT(off); + int val; - return !!(adp5588_gpio_read(dev->client, - GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off)); + mutex_lock(&dev->lock); + + if (dev->dir[bank] & bit) + val = dev->dat_out[bank]; + else + val = adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + bank); + + mutex_unlock(&dev->lock); + + return !!(val & bit); } static void adp5588_gpio_set_value(struct gpio_chip *chip, @@ -368,10 +379,8 @@ static int adp5588_gpio_probe(struct i2c_client *client, } dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&client->dev, "failed to alloc memory\n"); + if (dev == NULL) return -ENOMEM; - } dev->client = client; @@ -386,6 +395,7 @@ static int adp5588_gpio_probe(struct i2c_client *client, gc->ngpio = ADP5588_MAXGPIO; gc->label = client->name; gc->owner = THIS_MODULE; + gc->names = pdata->names; mutex_init(&dev->lock); diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 233d088ac59..3f6b33ce9bd 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Broadcom Corporation + * Copyright (C) 2012-2014 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 @@ -28,6 +28,10 @@ #define GPIO_BANK(gpio) ((gpio) >> 5) #define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1)) +/* There is a GPIO control register for each GPIO */ +#define GPIO_CONTROL(gpio) (0x00000100 + ((gpio) << 2)) + +/* The remaining registers are per GPIO bank */ #define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2)) #define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2)) #define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2)) @@ -35,7 +39,6 @@ #define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2)) #define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2)) #define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2)) -#define GPIO_CONTROL(bank) (0x00000100 + ((bank) << 2)) #define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2)) #define GPIO_GPPWR_OFFSET 0x00000520 @@ -80,22 +83,43 @@ static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip) return container_of(chip, struct bcm_kona_gpio, gpio_chip); } -static void bcm_kona_gpio_set_lockcode_bank(void __iomem *reg_base, - int bank_id, int lockcode) +static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base, + int bank_id, u32 lockcode) { writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET); writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id)); } -static inline void bcm_kona_gpio_lock_bank(void __iomem *reg_base, int bank_id) +static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio, + unsigned gpio) { - bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, LOCK_CODE); + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + spin_lock_irqsave(&kona_gpio->lock, flags); + + val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id)); + val |= BIT(gpio); + bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val); + + spin_unlock_irqrestore(&kona_gpio->lock, flags); } -static inline void bcm_kona_gpio_unlock_bank(void __iomem *reg_base, - int bank_id) +static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio, + unsigned gpio) { - bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, UNLOCK_CODE); + u32 val; + unsigned long flags; + int bank_id = GPIO_BANK(gpio); + + spin_lock_irqsave(&kona_gpio->lock, flags); + + val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id)); + val &= ~BIT(gpio); + bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val); + + spin_unlock_irqrestore(&kona_gpio->lock, flags); } static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) @@ -110,7 +134,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); /* determine the GPIO pin direction */ val = readl(reg_base + GPIO_CONTROL(gpio)); @@ -127,7 +150,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) writel(val, reg_base + reg_offset); out: - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -143,7 +165,6 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); /* determine the GPIO pin direction */ val = readl(reg_base + GPIO_CONTROL(gpio)); @@ -154,32 +175,43 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id); val = readl(reg_base + reg_offset); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); /* return the specified bit status */ return !!(val & BIT(bit)); } +static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip); + + bcm_kona_gpio_unlock_gpio(kona_gpio, gpio); + return 0; +} + +static void bcm_kona_gpio_free(struct gpio_chip *chip, unsigned gpio) +{ + struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip); + + bcm_kona_gpio_lock_gpio(kona_gpio, gpio); +} + static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; u32 val; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_IOTR_MASK; val |= GPIO_GPCTR0_IOTR_CMD_INPUT; writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -198,7 +230,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_IOTR_MASK; @@ -210,7 +241,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, val |= BIT(bit); writel(val, reg_base + reg_offset); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -233,7 +263,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, void __iomem *reg_base; u32 val, res; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = to_kona_gpio(chip); reg_base = kona_gpio->reg_base; @@ -257,7 +286,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, /* spin lock for read-modify-write of the GPIO register */ spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_DBR_MASK; @@ -272,7 +300,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -281,6 +308,8 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, static struct gpio_chip template_chip = { .label = "bcm-kona-gpio", .owner = THIS_MODULE, + .request = bcm_kona_gpio_request, + .free = bcm_kona_gpio_free, .direction_input = bcm_kona_gpio_direction_input, .get = bcm_kona_gpio_get, .direction_output = bcm_kona_gpio_direction_output, @@ -294,7 +323,7 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -303,13 +332,11 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_STATUS(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_STATUS(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -317,7 +344,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -326,13 +353,11 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_MASK(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MASK(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -340,7 +365,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; int bank_id = GPIO_BANK(gpio); int bit = GPIO_BIT(gpio); u32 val; @@ -349,13 +374,11 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d) kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_INT_MSKCLR(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MSKCLR(bank_id)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); } @@ -363,11 +386,10 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct bcm_kona_gpio *kona_gpio; void __iomem *reg_base; - int gpio = d->hwirq; + unsigned gpio = d->hwirq; u32 lvl_type; u32 val; unsigned long flags; - int bank_id = GPIO_BANK(gpio); kona_gpio = irq_data_get_irq_chip_data(d); reg_base = kona_gpio->reg_base; @@ -394,14 +416,12 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) } spin_lock_irqsave(&kona_gpio->lock, flags); - bcm_kona_gpio_unlock_bank(reg_base, bank_id); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_ITR_MASK; val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT; writel(val, reg_base + GPIO_CONTROL(gpio)); - bcm_kona_gpio_lock_bank(reg_base, bank_id); spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; @@ -424,7 +444,6 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) */ reg_base = bank->kona_gpio->reg_base; bank_id = bank->id; - bcm_kona_gpio_unlock_bank(reg_base, bank_id); while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) & (~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) { @@ -444,28 +463,26 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } } - bcm_kona_gpio_lock_bank(reg_base, bank_id); - chained_irq_exit(chip, desc); } -static unsigned int bcm_kona_gpio_irq_startup(struct irq_data *d) +static int bcm_kona_gpio_irq_reqres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) + if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) { dev_err(kona_gpio->gpio_chip.dev, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); - bcm_kona_gpio_irq_unmask(d); + return -EINVAL; + } return 0; } -static void bcm_kona_gpio_irq_shutdown(struct irq_data *d) +static void bcm_kona_gpio_irq_relres(struct irq_data *d) { struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d); - bcm_kona_gpio_irq_mask(d); gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq); } @@ -475,8 +492,8 @@ static struct irq_chip bcm_gpio_irq_chip = { .irq_mask = bcm_kona_gpio_irq_mask, .irq_unmask = bcm_kona_gpio_irq_unmask, .irq_set_type = bcm_kona_gpio_irq_set_type, - .irq_startup = bcm_kona_gpio_irq_startup, - .irq_shutdown = bcm_kona_gpio_irq_shutdown, + .irq_request_resources = bcm_kona_gpio_irq_reqres, + .irq_release_resources = bcm_kona_gpio_irq_relres, }; static struct __initconst of_device_id bcm_kona_gpio_of_match[] = { @@ -531,10 +548,12 @@ static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio) reg_base = kona_gpio->reg_base; /* disable interrupts and clear status */ for (i = 0; i < kona_gpio->num_bank; i++) { - bcm_kona_gpio_unlock_bank(reg_base, i); + /* Unlock the entire bank first */ + bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE); writel(0xffffffff, reg_base + GPIO_INT_MASK(i)); writel(0xffffffff, reg_base + GPIO_INT_STATUS(i)); - bcm_kona_gpio_lock_bank(reg_base, i); + /* Now re-lock the bank */ + bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE); } } @@ -657,6 +676,6 @@ static struct platform_driver bcm_kona_gpio_driver = { module_platform_driver(bcm_kona_gpio_driver); -MODULE_AUTHOR("Broadcom"); +MODULE_AUTHOR("Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>"); 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 ecb3ca2d1d1..6557147d933 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -178,7 +178,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev, struct bt8xxgpio *bg; int err; - bg = kzalloc(sizeof(*bg), GFP_KERNEL); + bg = devm_kzalloc(&dev->dev, sizeof(struct bt8xxgpio), GFP_KERNEL); if (!bg) return -ENOMEM; @@ -188,9 +188,9 @@ static int bt8xxgpio_probe(struct pci_dev *dev, err = pci_enable_device(dev); if (err) { printk(KERN_ERR "bt8xxgpio: Can't enable device.\n"); - goto err_freebg; + return err; } - if (!request_mem_region(pci_resource_start(dev, 0), + if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0), pci_resource_len(dev, 0), "bt8xxgpio")) { printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n", @@ -201,11 +201,11 @@ static int bt8xxgpio_probe(struct pci_dev *dev, pci_set_master(dev); pci_set_drvdata(dev, bg); - bg->mmio = ioremap(pci_resource_start(dev, 0), 0x1000); + bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000); if (!bg->mmio) { printk(KERN_ERR "bt8xxgpio: ioremap() failed\n"); err = -EIO; - goto err_release_mem; + goto err_disable; } /* Disable interrupts */ @@ -220,18 +220,13 @@ static int bt8xxgpio_probe(struct pci_dev *dev, err = gpiochip_add(&bg->gpio); if (err) { printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n"); - goto err_release_mem; + goto err_disable; } return 0; -err_release_mem: - release_mem_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); err_disable: pci_disable_device(dev); -err_freebg: - kfree(bg); return err; } @@ -250,8 +245,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev) release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); pci_disable_device(pdev); - - kfree(bg); } #ifdef CONFIG_PM diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index d3550274b8f..e1e861239e9 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -65,6 +65,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev) } bgc->gc.base = id * 8; + bgc->gc.owner = THIS_MODULE; platform_set_drvdata(pdev, bgc); return gpiochip_add(&bgc->gc); @@ -97,3 +98,4 @@ module_platform_driver(clps711x_gpio_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); MODULE_DESCRIPTION("CLPS711X GPIO driver"); +MODULE_ALIAS("platform:clps711x-gpio"); diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 7629b4f12b7..9f0682534e2 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -37,6 +37,8 @@ struct davinci_gpio_regs { u32 intstat; }; +typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq); + #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */ #define chip2controller(chip) \ @@ -172,6 +174,27 @@ of_err: return NULL; } +#ifdef CONFIG_OF_GPIO +static int davinci_gpio_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, + u32 *flags) +{ + struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev); + struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev); + + if (gpiospec->args[0] > pdata->ngpio) + return -EINVAL; + + if (gc != &chips[gpiospec->args[0] / 32].chip) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[1]; + + return gpiospec->args[0] % 32; +} +#endif + static int davinci_gpio_probe(struct platform_device *pdev) { int i, base; @@ -207,10 +230,8 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips = devm_kzalloc(dev, ngpio * sizeof(struct davinci_gpio_controller), GFP_KERNEL); - if (!chips) { - dev_err(dev, "Memory allocation failed\n"); + if (!chips) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -236,6 +257,9 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips[i].chip.ngpio = 32; #ifdef CONFIG_OF_GPIO + chips[i].chip.of_gpio_n_cells = 2; + chips[i].chip.of_xlate = davinci_gpio_of_xlate; + chips[i].chip.dev = dev; chips[i].chip.of_node = dev->of_node; #endif spin_lock_init(&chips[i].lock); @@ -413,6 +437,26 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = { .xlate = irq_domain_xlate_onetwocell, }; +static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq) +{ + static struct irq_chip_type gpio_unbanked; + + gpio_unbanked = *container_of(irq_get_chip(irq), + struct irq_chip_type, chip); + + return &gpio_unbanked.chip; +}; + +static struct irq_chip *keystone_gpio_get_irq_chip(unsigned int irq) +{ + static struct irq_chip gpio_unbanked; + + gpio_unbanked = *irq_get_chip(irq); + return &gpio_unbanked; +}; + +static const struct of_device_id davinci_gpio_ids[]; + /* * NOTE: for suspend/resume, probably best to make a platform_device with * suspend_late/resume_resume calls hooking into results of the set_wake() @@ -423,7 +467,8 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = { static int davinci_gpio_irq_setup(struct platform_device *pdev) { - unsigned gpio, irq, bank; + unsigned gpio, bank; + int irq; struct clk *clk; u32 binten = 0; unsigned ngpio, bank_irq; @@ -433,6 +478,18 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) struct davinci_gpio_platform_data *pdata = dev->platform_data; struct davinci_gpio_regs __iomem *g; struct irq_domain *irq_domain = NULL; + const struct of_device_id *match; + struct irq_chip *irq_chip; + gpio_get_irq_chip_cb_t gpio_get_irq_chip; + + /* + * Use davinci_gpio_get_irq_chip by default to handle non DT cases + */ + gpio_get_irq_chip = davinci_gpio_get_irq_chip; + match = of_match_device(of_match_ptr(davinci_gpio_ids), + dev); + if (match) + gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data; ngpio = pdata->ngpio; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -489,8 +546,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. */ if (pdata->gpio_unbanked) { - static struct irq_chip_type gpio_unbanked; - /* pass "bank 0" GPIO IRQs to AINTC */ chips[0].chip.to_irq = gpio_to_irq_unbanked; chips[0].gpio_irq = bank_irq; @@ -499,10 +554,9 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; - gpio_unbanked = *container_of(irq_get_chip(irq), - struct irq_chip_type, chip); - gpio_unbanked.chip.name = "GPIO-AINTC"; - gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked; + irq_chip = gpio_get_irq_chip(irq); + irq_chip->name = "GPIO-AINTC"; + irq_chip->irq_set_type = gpio_irq_type_unbanked; /* default trigger: both edges */ g = gpio2regs(0); @@ -511,7 +565,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) { - irq_set_chip(irq, &gpio_unbanked.chip); + irq_set_chip(irq, irq_chip); irq_set_handler_data(irq, &chips[gpio / 32]); irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); } @@ -554,7 +608,8 @@ done: #if IS_ENABLED(CONFIG_OF) static const struct of_device_id davinci_gpio_ids[] = { - { .compatible = "ti,dm6441-gpio", }, + { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip}, + { .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip}, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, davinci_gpio_ids); diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c new file mode 100644 index 00000000000..cd3b8143527 --- /dev/null +++ b/drivers/gpio/gpio-dwapb.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2011 Jamie Iles + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * All enquiries to support@picochip.com + */ +#include <linux/basic_mmio_gpio.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> + +#define GPIO_SWPORTA_DR 0x00 +#define GPIO_SWPORTA_DDR 0x04 +#define GPIO_SWPORTB_DR 0x0c +#define GPIO_SWPORTB_DDR 0x10 +#define GPIO_SWPORTC_DR 0x18 +#define GPIO_SWPORTC_DDR 0x1c +#define GPIO_SWPORTD_DR 0x24 +#define GPIO_SWPORTD_DDR 0x28 +#define GPIO_INTEN 0x30 +#define GPIO_INTMASK 0x34 +#define GPIO_INTTYPE_LEVEL 0x38 +#define GPIO_INT_POLARITY 0x3c +#define GPIO_INTSTATUS 0x40 +#define GPIO_PORTA_EOI 0x4c +#define GPIO_EXT_PORTA 0x50 +#define GPIO_EXT_PORTB 0x54 +#define GPIO_EXT_PORTC 0x58 +#define GPIO_EXT_PORTD 0x5c + +#define DWAPB_MAX_PORTS 4 +#define GPIO_EXT_PORT_SIZE (GPIO_EXT_PORTB - GPIO_EXT_PORTA) +#define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR) +#define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR) + +struct dwapb_gpio; + +struct dwapb_gpio_port { + struct bgpio_chip bgc; + bool is_registered; + struct dwapb_gpio *gpio; +}; + +struct dwapb_gpio { + struct device *dev; + void __iomem *regs; + struct dwapb_gpio_port *ports; + unsigned int nr_ports; + struct irq_domain *domain; +}; + +static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + struct dwapb_gpio_port *port = container_of(bgc, struct + dwapb_gpio_port, bgc); + struct dwapb_gpio *gpio = port->gpio; + + return irq_find_mapping(gpio->domain, offset); +} + +static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs) +{ + u32 v = readl(gpio->regs + GPIO_INT_POLARITY); + + if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs)) + v &= ~BIT(offs); + else + v |= BIT(offs); + + writel(v, gpio->regs + GPIO_INT_POLARITY); +} + +static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) +{ + struct dwapb_gpio *gpio = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS); + + while (irq_status) { + int hwirq = fls(irq_status) - 1; + int gpio_irq = irq_find_mapping(gpio->domain, hwirq); + + generic_handle_irq(gpio_irq); + irq_status &= ~BIT(hwirq); + + if ((irq_get_trigger_type(gpio_irq) & IRQ_TYPE_SENSE_MASK) + == IRQ_TYPE_EDGE_BOTH) + dwapb_toggle_trigger(gpio, hwirq); + } + + if (chip->irq_eoi) + chip->irq_eoi(irq_desc_get_irq_data(desc)); +} + +static void dwapb_irq_enable(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&bgc->lock, flags); + val = readl(gpio->regs + GPIO_INTEN); + val |= BIT(d->hwirq); + writel(val, gpio->regs + GPIO_INTEN); + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static void dwapb_irq_disable(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&bgc->lock, flags); + val = readl(gpio->regs + GPIO_INTEN); + val &= ~BIT(d->hwirq); + writel(val, gpio->regs + GPIO_INTEN); + spin_unlock_irqrestore(&bgc->lock, flags); +} + +static int dwapb_irq_reqres(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + + if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) { + dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n", + irqd_to_hwirq(d)); + return -EINVAL; + } + return 0; +} + +static void dwapb_irq_relres(struct irq_data *d) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + + gpio_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d)); +} + +static int dwapb_irq_set_type(struct irq_data *d, u32 type) +{ + struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d); + struct dwapb_gpio *gpio = igc->private; + struct bgpio_chip *bgc = &gpio->ports[0].bgc; + int bit = d->hwirq; + unsigned long level, polarity, flags; + + if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | + IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) + return -EINVAL; + + spin_lock_irqsave(&bgc->lock, flags); + level = readl(gpio->regs + GPIO_INTTYPE_LEVEL); + polarity = readl(gpio->regs + GPIO_INT_POLARITY); + + switch (type) { + case IRQ_TYPE_EDGE_BOTH: + level |= BIT(bit); + dwapb_toggle_trigger(gpio, bit); + break; + case IRQ_TYPE_EDGE_RISING: + level |= BIT(bit); + polarity |= BIT(bit); + break; + case IRQ_TYPE_EDGE_FALLING: + level |= BIT(bit); + polarity &= ~BIT(bit); + break; + case IRQ_TYPE_LEVEL_HIGH: + level &= ~BIT(bit); + polarity |= BIT(bit); + break; + case IRQ_TYPE_LEVEL_LOW: + level &= ~BIT(bit); + polarity &= ~BIT(bit); + break; + } + + irq_setup_alt_chip(d, type); + + writel(level, gpio->regs + GPIO_INTTYPE_LEVEL); + writel(polarity, gpio->regs + GPIO_INT_POLARITY); + spin_unlock_irqrestore(&bgc->lock, flags); + + return 0; +} + +static void dwapb_configure_irqs(struct dwapb_gpio *gpio, + struct dwapb_gpio_port *port) +{ + struct gpio_chip *gc = &port->bgc.gc; + struct device_node *node = gc->of_node; + struct irq_chip_generic *irq_gc; + unsigned int hwirq, ngpio = gc->ngpio; + struct irq_chip_type *ct; + int err, irq, i; + + irq = irq_of_parse_and_map(node, 0); + if (!irq) { + dev_warn(gpio->dev, "no irq for bank %s\n", + port->bgc.gc.of_node->full_name); + return; + } + + gpio->domain = irq_domain_add_linear(node, ngpio, + &irq_generic_chip_ops, gpio); + if (!gpio->domain) + return; + + err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2, + "gpio-dwapb", handle_level_irq, + IRQ_NOREQUEST, 0, + IRQ_GC_INIT_NESTED_LOCK); + if (err) { + dev_info(gpio->dev, "irq_alloc_domain_generic_chips failed\n"); + irq_domain_remove(gpio->domain); + gpio->domain = NULL; + return; + } + + irq_gc = irq_get_domain_generic_chip(gpio->domain, 0); + if (!irq_gc) { + irq_domain_remove(gpio->domain); + gpio->domain = NULL; + return; + } + + irq_gc->reg_base = gpio->regs; + irq_gc->private = gpio; + + for (i = 0; i < 2; i++) { + ct = &irq_gc->chip_types[i]; + ct->chip.irq_ack = irq_gc_ack_set_bit; + ct->chip.irq_mask = irq_gc_mask_set_bit; + ct->chip.irq_unmask = irq_gc_mask_clr_bit; + ct->chip.irq_set_type = dwapb_irq_set_type; + ct->chip.irq_enable = dwapb_irq_enable; + ct->chip.irq_disable = dwapb_irq_disable; + ct->chip.irq_request_resources = dwapb_irq_reqres; + ct->chip.irq_release_resources = dwapb_irq_relres; + ct->regs.ack = GPIO_PORTA_EOI; + ct->regs.mask = GPIO_INTMASK; + ct->type = IRQ_TYPE_LEVEL_MASK; + } + + irq_gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK; + irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; + irq_gc->chip_types[1].handler = handle_edge_irq; + + irq_set_chained_handler(irq, dwapb_irq_handler); + irq_set_handler_data(irq, gpio); + + for (hwirq = 0 ; hwirq < ngpio ; hwirq++) + irq_create_mapping(gpio->domain, hwirq); + + port->bgc.gc.to_irq = dwapb_gpio_to_irq; +} + +static void dwapb_irq_teardown(struct dwapb_gpio *gpio) +{ + struct dwapb_gpio_port *port = &gpio->ports[0]; + struct gpio_chip *gc = &port->bgc.gc; + unsigned int ngpio = gc->ngpio; + irq_hw_number_t hwirq; + + if (!gpio->domain) + return; + + for (hwirq = 0 ; hwirq < ngpio ; hwirq++) + irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq)); + + irq_domain_remove(gpio->domain); + gpio->domain = NULL; +} + +static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, + struct device_node *port_np, + unsigned int offs) +{ + struct dwapb_gpio_port *port; + u32 port_idx, ngpio; + void __iomem *dat, *set, *dirout; + int err; + + if (of_property_read_u32(port_np, "reg", &port_idx) || + port_idx >= DWAPB_MAX_PORTS) { + dev_err(gpio->dev, "missing/invalid port index for %s\n", + port_np->full_name); + return -EINVAL; + } + + port = &gpio->ports[offs]; + port->gpio = gpio; + + if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) { + dev_info(gpio->dev, "failed to get number of gpios for %s\n", + port_np->full_name); + ngpio = 32; + } + + dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE); + set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE); + dirout = gpio->regs + GPIO_SWPORTA_DDR + + (port_idx * GPIO_SWPORT_DDR_SIZE); + + err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout, + NULL, false); + if (err) { + dev_err(gpio->dev, "failed to init gpio chip for %s\n", + port_np->full_name); + return err; + } + + port->bgc.gc.ngpio = ngpio; + port->bgc.gc.of_node = port_np; + + /* + * Only port A can provide interrupts in all configurations of the IP. + */ + if (port_idx == 0 && + of_property_read_bool(port_np, "interrupt-controller")) + dwapb_configure_irqs(gpio, port); + + err = gpiochip_add(&port->bgc.gc); + if (err) + dev_err(gpio->dev, "failed to register gpiochip for %s\n", + port_np->full_name); + else + port->is_registered = true; + + return err; +} + +static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) +{ + unsigned int m; + + for (m = 0; m < gpio->nr_ports; ++m) + if (gpio->ports[m].is_registered) + WARN_ON(gpiochip_remove(&gpio->ports[m].bgc.gc)); +} + +static int dwapb_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + struct dwapb_gpio *gpio; + struct device_node *np; + int err; + unsigned int offs = 0; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + gpio->dev = &pdev->dev; + + gpio->nr_ports = of_get_child_count(pdev->dev.of_node); + if (!gpio->nr_ports) { + err = -EINVAL; + goto out_err; + } + gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports * + sizeof(*gpio->ports), GFP_KERNEL); + if (!gpio->ports) { + err = -ENOMEM; + goto out_err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio->regs)) { + err = PTR_ERR(gpio->regs); + goto out_err; + } + + for_each_child_of_node(pdev->dev.of_node, np) { + err = dwapb_gpio_add_port(gpio, np, offs++); + if (err) + goto out_unregister; + } + platform_set_drvdata(pdev, gpio); + + return 0; + +out_unregister: + dwapb_gpio_unregister(gpio); + dwapb_irq_teardown(gpio); + +out_err: + return err; +} + +static int dwapb_gpio_remove(struct platform_device *pdev) +{ + struct dwapb_gpio *gpio = platform_get_drvdata(pdev); + + dwapb_gpio_unregister(gpio); + dwapb_irq_teardown(gpio); + + return 0; +} + +static const struct of_device_id dwapb_of_match[] = { + { .compatible = "snps,dw-apb-gpio" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dwapb_of_match); + +static struct platform_driver dwapb_gpio_driver = { + .driver = { + .name = "gpio-dwapb", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(dwapb_of_match), + }, + .probe = dwapb_gpio_probe, + .remove = dwapb_gpio_remove, +}; + +module_platform_driver(dwapb_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jamie Iles"); +MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver"); diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index 1e98a987396..cde36054c38 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -99,23 +99,23 @@ static void em_gio_irq_enable(struct irq_data *d) em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d))); } -static unsigned int em_gio_irq_startup(struct irq_data *d) +static int em_gio_irq_reqres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) { dev_err(p->gpio_chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - em_gio_irq_enable(d); + return -EINVAL; + } return 0; } -static void em_gio_irq_shutdown(struct irq_data *d) +static void em_gio_irq_relres(struct irq_data *d) { struct em_gio_priv *p = irq_data_get_irq_chip_data(d); - em_gio_irq_disable(d); gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)); } @@ -212,7 +212,7 @@ static void __em_gio_set(struct gpio_chip *chip, unsigned int reg, { /* upper 16 bits contains mask and lower 16 actual value */ em_gio_write(gpio_to_priv(chip), reg, - (1 << (shift + 16)) | (value << shift)); + (BIT(shift + 16)) | (value << shift)); } static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -284,7 +284,6 @@ static int em_gio_probe(struct platform_device *pdev) p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); if (!p) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); ret = -ENOMEM; goto err0; } @@ -359,8 +358,8 @@ static int em_gio_probe(struct platform_device *pdev) irq_chip->irq_mask = em_gio_irq_disable; irq_chip->irq_unmask = em_gio_irq_enable; irq_chip->irq_set_type = em_gio_irq_set_type; - irq_chip->irq_startup = em_gio_irq_startup; - irq_chip->irq_shutdown = em_gio_irq_shutdown; + irq_chip->irq_request_resources = em_gio_irq_reqres; + irq_chip->irq_release_resources = em_gio_irq_relres; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 80829f3c654..dcc2bb4074e 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -344,37 +344,24 @@ static int ep93xx_gpio_probe(struct platform_device *pdev) { struct ep93xx_gpio *ep93xx_gpio; struct resource *res; - void __iomem *mmio; int i; - int ret; + struct device *dev = &pdev->dev; - ep93xx_gpio = kzalloc(sizeof(*ep93xx_gpio), GFP_KERNEL); + ep93xx_gpio = devm_kzalloc(dev, sizeof(struct ep93xx_gpio), GFP_KERNEL); if (!ep93xx_gpio) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENXIO; - goto exit_free; - } - - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - ret = -EBUSY; - goto exit_free; - } - - mmio = ioremap(res->start, resource_size(res)); - if (!mmio) { - ret = -ENXIO; - goto exit_release; - } - ep93xx_gpio->mmio_base = mmio; + ep93xx_gpio->mmio_base = devm_ioremap_resource(dev, res); + if (IS_ERR(ep93xx_gpio->mmio_base)) + return PTR_ERR(ep93xx_gpio->mmio_base); for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i]; struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; - if (ep93xx_gpio_add_bank(bgc, &pdev->dev, mmio, bank)) + if (ep93xx_gpio_add_bank(bgc, &pdev->dev, + ep93xx_gpio->mmio_base, bank)) dev_warn(&pdev->dev, "Unable to add gpio bank %s\n", bank->label); } @@ -382,13 +369,6 @@ static int ep93xx_gpio_probe(struct platform_device *pdev) ep93xx_gpio_init_irq(); return 0; - -exit_release: - release_mem_region(res->start, resource_size(res)); -exit_free: - kfree(ep93xx_gpio); - dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, ret); - return ret; } static struct platform_driver ep93xx_gpio_driver = { diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index 7b95a4a8318..1237a73c3c9 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -18,15 +18,9 @@ */ #include <linux/kernel.h> -#include <linux/compiler.h> -#include <linux/init.h> #include <linux/io.h> -#include <linux/of.h> #include <linux/of_device.h> -#include <linux/of_platform.h> #include <linux/of_gpio.h> -#include <linux/gpio.h> -#include <linux/slab.h> #include <linux/module.h> #define GEF_GPIO_DIRECT 0x00 @@ -39,28 +33,26 @@ #define GEF_GPIO_OVERRUN 0x1C #define GEF_GPIO_MODE 0x20 -static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value) +static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); unsigned int data; - data = ioread32be(reg); - /* value: 0=low; 1=high */ - if (value & 0x1) - data = data | (0x1 << offset); + data = ioread32be(mmchip->regs + GEF_GPIO_OUT); + if (value) + data = data | BIT(offset); else - data = data & ~(0x1 << offset); - - iowrite32be(data, reg); + data = data & ~BIT(offset); + iowrite32be(data, mmchip->regs + GEF_GPIO_OUT); } - static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) { unsigned int data; struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data | (0x1 << offset); + data = data | BIT(offset); iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); return 0; @@ -71,11 +63,11 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) unsigned int data; struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - /* Set direction before switching to input */ - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); + /* Set value before switching to output */ + gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); - data = data & ~(0x1 << offset); + data = data & ~BIT(offset); iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); return 0; @@ -83,116 +75,56 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) { - unsigned int data; - int state = 0; struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - data = ioread32be(mmchip->regs + GEF_GPIO_IN); - state = (int)((data >> offset) & 0x1); - - return state; + return !!(ioread32be(mmchip->regs + GEF_GPIO_IN) & BIT(offset)); } -static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); - - _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); -} +static const struct of_device_id gef_gpio_ids[] = { + { + .compatible = "gef,sbc610-gpio", + .data = (void *)19, + }, { + .compatible = "gef,sbc310-gpio", + .data = (void *)6, + }, { + .compatible = "ge,imp3a-gpio", + .data = (void *)16, + }, + { } +}; +MODULE_DEVICE_TABLE(of, gef_gpio_ids); -static int __init gef_gpio_init(void) +static int __init gef_gpio_probe(struct platform_device *pdev) { - struct device_node *np; - int retval; - struct of_mm_gpio_chip *gef_gpio_chip; - - for_each_compatible_node(np, NULL, "gef,sbc610-gpio") { - - pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 19; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } - - for_each_compatible_node(np, NULL, "gef,sbc310-gpio") { - - pr_debug("%s: Initialising GEF GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 6; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } - - for_each_compatible_node(np, NULL, "ge,imp3a-gpio") { - - pr_debug("%s: Initialising GE GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 16; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } + const struct of_device_id *of_id = + of_match_device(gef_gpio_ids, &pdev->dev); + struct of_mm_gpio_chip *mmchip; + + mmchip = devm_kzalloc(&pdev->dev, sizeof(*mmchip), GFP_KERNEL); + if (!mmchip) + return -ENOMEM; + + /* Setup pointers to chip functions */ + mmchip->gc.ngpio = (u16)(uintptr_t)of_id->data; + mmchip->gc.of_gpio_n_cells = 2; + mmchip->gc.direction_input = gef_gpio_dir_in; + mmchip->gc.direction_output = gef_gpio_dir_out; + mmchip->gc.get = gef_gpio_get; + mmchip->gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + return of_mm_gpiochip_add(pdev->dev.of_node, mmchip); +}; - return 0; +static struct platform_driver gef_gpio_driver = { + .driver = { + .name = "gef-gpio", + .owner = THIS_MODULE, + .of_match_table = gef_gpio_ids, + }, }; -arch_initcall(gef_gpio_init); +module_platform_driver_probe(gef_gpio_driver, gef_gpio_probe); MODULE_DESCRIPTION("GE I/O FPGA GPIO driver"); MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com"); diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index d2196bf7384..fea8c82bb8f 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -139,7 +139,7 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) { struct bgpio_chip *bgc = to_bgpio_chip(gc); - return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio); + return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); } static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) @@ -388,6 +388,14 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, return 0; } +static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin) +{ + if (gpio_pin < chip->ngpio) + return 0; + + return -EINVAL; +} + int bgpio_remove(struct bgpio_chip *bgc) { return gpiochip_remove(&bgc->gc); @@ -413,6 +421,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, bgc->gc.label = dev_name(dev); bgc->gc.base = -1; bgc->gc.ngpio = bgc->bits; + bgc->gc.request = bgpio_request; ret = bgpio_setup_io(bgc, dat, set, clr); if (ret) @@ -488,7 +497,7 @@ static int bgpio_pdev_probe(struct platform_device *pdev) void __iomem *dirout; void __iomem *dirin; unsigned long sz; - unsigned long flags = 0; + unsigned long flags = pdev->id_entry->driver_data; int err; struct bgpio_chip *bgc; struct bgpio_pdata *pdata = dev_get_platdata(dev); @@ -519,9 +528,6 @@ static int bgpio_pdev_probe(struct platform_device *pdev) if (err) return err; - if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be")) - flags |= BGPIOF_BIG_ENDIAN; - bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); if (!bgc) return -ENOMEM; @@ -531,6 +537,8 @@ static int bgpio_pdev_probe(struct platform_device *pdev) return err; if (pdata) { + if (pdata->label) + bgc->gc.label = pdata->label; bgc->gc.base = pdata->base; if (pdata->ngpio > 0) bgc->gc.ngpio = pdata->ngpio; @@ -549,9 +557,14 @@ static int bgpio_pdev_remove(struct platform_device *pdev) } static const struct platform_device_id bgpio_id_table[] = { - { "basic-mmio-gpio", }, - { "basic-mmio-gpio-be", }, - {}, + { + .name = "basic-mmio-gpio", + .driver_data = 0, + }, { + .name = "basic-mmio-gpio-be", + .driver_data = BGPIOF_BIG_ENDIAN, + }, + { } }; MODULE_DEVICE_TABLE(platform, bgpio_id_table); diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 84d2478ec29..3c3f515b791 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -481,7 +481,7 @@ out: return ret; } -static struct of_device_id grgpio_match[] = { +static const struct of_device_id grgpio_match[] = { {.name = "GAISLER_GPIO"}, {.name = "01_01a"}, {}, diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index f5bf3c38bca..70304220a47 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -1,5 +1,5 @@ /* - * Intel ICH6-10, Series 5 and 6 GPIO driver + * Intel ICH6-10, Series 5 and 6, Atom C2000 (Avoton/Rangeley) GPIO driver * * Copyright (C) 2010 Extreme Engineering Solutions. * @@ -55,6 +55,16 @@ static const u8 ichx_reglen[3] = { 0x30, 0x10, 0x10, }; +static const u8 avoton_regs[4][3] = { + {0x00, 0x80, 0x00}, + {0x04, 0x84, 0x00}, + {0x08, 0x88, 0x00}, +}; + +static const u8 avoton_reglen[3] = { + 0x10, 0x10, 0x00, +}; + #define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) #define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start) @@ -62,6 +72,13 @@ struct ichx_desc { /* Max GPIO pins the chipset can have */ uint ngpio; + /* chipset registers */ + const u8 (*regs)[3]; + const u8 *reglen; + + /* GPO_BLINK is available on this chipset */ + bool have_blink; + /* Whether the chipset has GPIO in GPE0_STS in the PM IO region */ bool uses_gpe0; @@ -71,6 +88,12 @@ struct ichx_desc { /* Some chipsets have quirks, let these use their own request/get */ int (*request)(struct gpio_chip *chip, unsigned offset); int (*get)(struct gpio_chip *chip, unsigned offset); + + /* + * Some chipsets don't let reading output values on GPIO_LVL register + * this option allows driver caching written output values + */ + bool use_outlvl_cache; }; static struct { @@ -82,6 +105,7 @@ static struct { struct ichx_desc *desc; /* Pointer to chipset-specific description */ u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ u8 use_gpio; /* Which GPIO groups are usable */ + int outlvl_cache[3]; /* cached output values */ } ichx_priv; static int modparam_gpiobase = -1; /* dynamic */ @@ -99,13 +123,23 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify) spin_lock_irqsave(&ichx_priv.lock, flags); - data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base); + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + data = ichx_priv.outlvl_cache[reg_nr]; + else + data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + if (val) data |= 1 << bit; else data &= ~(1 << bit); - ICHX_WRITE(data, ichx_regs[reg][reg_nr], ichx_priv.gpio_base); - tmp = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base); + ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + ichx_priv.outlvl_cache[reg_nr] = data; + + tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); if (verify && data != tmp) ret = -EPERM; @@ -123,7 +157,11 @@ static int ichx_read_bit(int reg, unsigned nr) spin_lock_irqsave(&ichx_priv.lock, flags); - data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base); + data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], + ichx_priv.gpio_base); + + if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) + data = ichx_priv.outlvl_cache[reg_nr] | data; spin_unlock_irqrestore(&ichx_priv.lock, flags); @@ -151,7 +189,7 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, int val) { /* Disable blink hardware which is available for GPIOs from 0 to 31. */ - if (nr < 32) + if (nr < 32 && ichx_priv.desc->have_blink) ichx_write_bit(GPO_BLINK, nr, 0, 0); /* Set GPIO output value. */ @@ -266,6 +304,9 @@ static struct ichx_desc ich6_desc = { .uses_gpe0 = true, .ngpio = 50, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* Intel 3100 */ @@ -285,29 +326,56 @@ static struct ichx_desc i3100_desc = { .uses_gpe0 = true, .ngpio = 50, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* ICH7 and ICH8-based */ static struct ichx_desc ich7_desc = { .ngpio = 50, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* ICH9-based */ static struct ichx_desc ich9_desc = { .ngpio = 61, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* ICH10-based - Consumer/corporate versions have different amount of GPIO */ static struct ichx_desc ich10_cons_desc = { .ngpio = 61, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; static struct ichx_desc ich10_corp_desc = { .ngpio = 72, + .have_blink = true, + .regs = ichx_regs, + .reglen = ichx_reglen, }; /* Intel 5 series, 6 series, 3400 series, and C200 series */ static struct ichx_desc intel5_desc = { .ngpio = 76, + .regs = ichx_regs, + .reglen = ichx_reglen, +}; + +/* Avoton */ +static struct ichx_desc avoton_desc = { + /* Avoton has only 59 GPIOs, but we assume the first set of register + * (Core) has 32 instead of 31 to keep gpio-ich compliance + */ + .ngpio = 60, + .regs = avoton_regs, + .reglen = avoton_reglen, + .use_outlvl_cache = true, }; static int ichx_gpio_request_regions(struct resource *res_base, @@ -318,11 +386,12 @@ static int ichx_gpio_request_regions(struct resource *res_base, if (!res_base || !res_base->start || !res_base->end) return -ENODEV; - for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { if (!(use_gpio & (1 << i))) continue; - if (!request_region(res_base->start + ichx_regs[0][i], - ichx_reglen[i], name)) + if (!request_region( + res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i], name)) goto request_err; } return 0; @@ -332,8 +401,8 @@ request_err: for (i--; i >= 0; i--) { if (!(use_gpio & (1 << i))) continue; - release_region(res_base->start + ichx_regs[0][i], - ichx_reglen[i]); + release_region(res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i]); } return -EBUSY; } @@ -342,11 +411,11 @@ static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio) { int i; - for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { if (!(use_gpio & (1 << i))) continue; - release_region(res_base->start + ichx_regs[0][i], - ichx_reglen[i]); + release_region(res_base->start + ichx_priv.desc->regs[0][i], + ichx_priv.desc->reglen[i]); } } @@ -383,6 +452,9 @@ static int ichx_gpio_probe(struct platform_device *pdev) case ICH_V10CONS_GPIO: ichx_priv.desc = &ich10_cons_desc; break; + case AVOTON_GPIO: + ichx_priv.desc = &avoton_desc; + break; default: return -ENODEV; } diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index d1b50ef5fab..118a6bf455d 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -1,7 +1,7 @@ /* - * Moorestown platform Langwell chip GPIO driver + * Intel MID GPIO driver * - * Copyright (c) 2008, 2009, 2013, Intel Corporation. + * Copyright (c) 2008-2014 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Supports: @@ -235,23 +231,23 @@ static void intel_mid_irq_mask(struct irq_data *d) { } -static unsigned int intel_mid_irq_startup(struct irq_data *d) +static int intel_mid_irq_reqres(struct irq_data *d) { struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) { dev_err(priv->chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - intel_mid_irq_unmask(d); + return -EINVAL; + } return 0; } -static void intel_mid_irq_shutdown(struct irq_data *d) +static void intel_mid_irq_relres(struct irq_data *d) { struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d); - intel_mid_irq_mask(d); gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d)); } @@ -260,8 +256,8 @@ static struct irq_chip intel_mid_irqchip = { .irq_mask = intel_mid_irq_mask, .irq_unmask = intel_mid_irq_unmask, .irq_set_type = intel_mid_irq_type, - .irq_startup = intel_mid_irq_startup, - .irq_shutdown = intel_mid_irq_shutdown, + .irq_request_resources = intel_mid_irq_reqres, + .irq_release_resources = intel_mid_irq_relres, }; static const struct intel_mid_gpio_ddata gpio_lincroft = { @@ -394,8 +390,8 @@ static const struct irq_domain_ops intel_gpio_irq_ops = { static int intel_gpio_runtime_idle(struct device *dev) { - pm_schedule_suspend(dev, 500); - return -EBUSY; + int err = pm_schedule_suspend(dev, 500); + return err ?: -EBUSY; } static const struct dev_pm_ops intel_gpio_pm_ops = { diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c index c22a61be3a9..0a5e9d3f308 100644 --- a/drivers/gpio/gpio-iop.c +++ b/drivers/gpio/gpio-iop.c @@ -111,6 +111,8 @@ static int iop3xx_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); return gpiochip_add(&iop3xx_chip); } diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c index 2ecd3a09c74..42852eaaf02 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/gpio-janz-ttl.c @@ -152,34 +152,21 @@ static int ttl_probe(struct platform_device *pdev) pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_err(dev, "no platform data\n"); - ret = -ENXIO; - goto out_return; + return -ENXIO; } - mod = kzalloc(sizeof(*mod), GFP_KERNEL); - if (!mod) { - dev_err(dev, "unable to allocate private data\n"); - ret = -ENOMEM; - goto out_return; - } + mod = devm_kzalloc(dev, sizeof(*mod), GFP_KERNEL); + if (!mod) + return -ENOMEM; platform_set_drvdata(pdev, mod); spin_lock_init(&mod->lock); /* get access to the MODULbus registers for this module */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "MODULbus registers not found\n"); - ret = -ENODEV; - goto out_free_mod; - } - - mod->regs = ioremap(res->start, resource_size(res)); - if (!mod->regs) { - dev_err(dev, "MODULbus registers not ioremap\n"); - ret = -ENOMEM; - goto out_free_mod; - } + mod->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(mod->regs)) + return PTR_ERR(mod->regs); ttl_setup_device(mod); @@ -198,17 +185,10 @@ static int ttl_probe(struct platform_device *pdev) ret = gpiochip_add(gpio); if (ret) { dev_err(dev, "unable to add GPIO chip\n"); - goto out_iounmap_regs; + return ret; } return 0; - -out_iounmap_regs: - iounmap(mod->regs); -out_free_mod: - kfree(mod); -out_return: - return ret; } static int ttl_remove(struct platform_device *pdev) @@ -223,8 +203,6 @@ static int ttl_remove(struct platform_device *pdev) return ret; } - iounmap(mod->regs); - kfree(mod); return 0; } diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index c6d88173f5a..1e5e51987d3 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -24,7 +24,7 @@ #include <linux/mfd/kempld.h> #define KEMPLD_GPIO_MAX_NUM 16 -#define KEMPLD_GPIO_MASK(x) (1 << ((x) % 8)) +#define KEMPLD_GPIO_MASK(x) (BIT((x) % 8)) #define KEMPLD_GPIO_DIR_NUM(x) (0x40 + (x) / 8) #define KEMPLD_GPIO_LVL_NUM(x) (0x42 + (x) / 8) #define KEMPLD_GPIO_EVT_LVL_EDGE 0x46 @@ -216,4 +216,4 @@ module_platform_driver(kempld_gpio_driver); MODULE_DESCRIPTION("KEM PLD GPIO Driver"); MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:gpio-kempld"); +MODULE_ALIAS("platform:kempld-gpio"); diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 66b18535b5a..2bea89b7250 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -188,7 +188,7 @@ static int lp_irq_type(struct irq_data *d, unsigned type) static int lp_gpio_get(struct gpio_chip *chip, unsigned offset) { unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1); - return inl(reg) & IN_LVL_BIT; + return !!(inl(reg) & IN_LVL_BIT); } static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -301,23 +301,23 @@ static void lp_irq_disable(struct irq_data *d) spin_unlock_irqrestore(&lg->lock, flags); } -static unsigned int lp_irq_startup(struct irq_data *d) +static int lp_irq_reqres(struct irq_data *d) { struct lp_gpio *lg = irq_data_get_irq_chip_data(d); - if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) + if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) { dev_err(lg->chip.dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); - lp_irq_enable(d); + return -EINVAL; + } return 0; } -static void lp_irq_shutdown(struct irq_data *d) +static void lp_irq_relres(struct irq_data *d) { struct lp_gpio *lg = irq_data_get_irq_chip_data(d); - lp_irq_disable(d); gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d)); } @@ -328,8 +328,8 @@ static struct irq_chip lp_irqchip = { .irq_enable = lp_irq_enable, .irq_disable = lp_irq_disable, .irq_set_type = lp_irq_type, - .irq_startup = lp_irq_startup, - .irq_shutdown = lp_irq_shutdown, + .irq_request_resources = lp_irq_reqres, + .irq_release_resources = lp_irq_relres, .flags = IRQCHIP_SKIP_SET_WAKE, }; @@ -375,10 +375,8 @@ static int lp_gpio_probe(struct platform_device *pdev) int ret = -ENODEV; lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL); - if (!lg) { - dev_err(dev, "can't allocate lp_gpio chip data\n"); + if (!lg) return -ENOMEM; - } lg->pdev = pdev; platform_set_drvdata(pdev, lg); diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 8672755f95c..0814584fcdc 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -237,10 +237,9 @@ int __max730x_remove(struct device *dev) ts->write(dev, 0x04, 0x00); ret = gpiochip_remove(&ts->chip); - if (!ret) { + if (!ret) mutex_destroy(&ts->lock); - kfree(ts); - } else + else dev_err(dev, "Failed to remove GPIO controller: %d\n", ret); return ret; diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 36cb290764b..7c36f2b0983 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -622,6 +622,13 @@ static int max732x_probe(struct i2c_client *client, goto out_failed; } + if (nr_port > 8 && !chip->client_dummy) { + dev_err(&client->dev, + "Failed to allocate second group I2C device\n"); + ret = -ENODEV; + goto out_failed; + } + mutex_init(&chip->lock); max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); @@ -647,6 +654,8 @@ static int max732x_probe(struct i2c_client *client, return 0; out_failed: + if (chip->client_dummy) + i2c_unregister_device(chip->client_dummy); max732x_irq_teardown(chip); return ret; } diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 1ac288ea810..57adbc90fda 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -173,7 +173,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); return (status < 0) ? status : rx[0]; } @@ -184,7 +184,7 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[0] = mcp->addr; tx[1] = reg; tx[2] = val; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); } static int @@ -193,13 +193,13 @@ mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) u8 tx[2], *tmp; int status; - if ((n + reg) > sizeof mcp->cache) + if ((n + reg) > sizeof(mcp->cache)) return -EINVAL; tx[0] = mcp->addr | 0x01; tx[1] = reg; tmp = (u8 *)vals; - status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), tmp, n); if (status >= 0) { while (n--) vals[n] = tmp[n]; /* expand to 16bit */ @@ -214,7 +214,7 @@ static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg) tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); + status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx)); return (status < 0) ? status : (rx[0] | (rx[1] << 8)); } @@ -226,7 +226,7 @@ static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) tx[1] = reg << 1; tx[2] = val; tx[3] = val >> 8; - return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); + return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0); } static int @@ -235,12 +235,12 @@ mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) u8 tx[2]; int status; - if ((n + reg) > sizeof mcp->cache) + if ((n + reg) > sizeof(mcp->cache)) return -EINVAL; tx[0] = mcp->addr | 0x01; tx[1] = reg << 1; - status = spi_write_then_read(mcp->data, tx, sizeof tx, + status = spi_write_then_read(mcp->data, tx, sizeof(tx), (u8 *)vals, n * 2); if (status >= 0) { while (n--) @@ -440,24 +440,24 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data) mutex_unlock(&mcp->irq_lock); } -static unsigned int mcp23s08_irq_startup(struct irq_data *data) +static int mcp23s08_irq_reqres(struct irq_data *data) { struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) + if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) { dev_err(mcp->chip.dev, "unable to lock HW IRQ %lu for IRQ usage\n", data->hwirq); + return -EINVAL; + } - mcp23s08_irq_unmask(data); return 0; } -static void mcp23s08_irq_shutdown(struct irq_data *data) +static void mcp23s08_irq_relres(struct irq_data *data) { struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data); - mcp23s08_irq_mask(data); gpio_unlock_as_irq(&mcp->chip, data->hwirq); } @@ -468,8 +468,8 @@ static struct irq_chip mcp23s08_irq_chip = { .irq_set_type = mcp23s08_irq_set_type, .irq_bus_lock = mcp23s08_irq_bus_lock, .irq_bus_sync_unlock = mcp23s08_irq_bus_unlock, - .irq_startup = mcp23s08_irq_startup, - .irq_shutdown = mcp23s08_irq_shutdown, + .irq_request_resources = mcp23s08_irq_reqres, + .irq_release_resources = mcp23s08_irq_relres, }; static int mcp23s08_irq_setup(struct mcp23s08 *mcp) @@ -567,7 +567,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo", (mcp->cache[MCP_GPPU] & mask) ? "up" : " "); /* NOTE: ignoring the irq-related registers */ - seq_printf(s, "\n"); + seq_puts(s, "\n"); } done: mutex_unlock(&mcp->lock); @@ -714,7 +714,7 @@ fail: #ifdef CONFIG_OF #ifdef CONFIG_SPI_MASTER -static struct of_device_id mcp23s08_spi_of_match[] = { +static const struct of_device_id mcp23s08_spi_of_match[] = { { .compatible = "microchip,mcp23s08", .data = (void *) MCP_TYPE_S08, @@ -738,7 +738,7 @@ MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match); #endif #if IS_ENABLED(CONFIG_I2C) -static struct of_device_id mcp23s08_i2c_of_match[] = { +static const struct of_device_id mcp23s08_i2c_of_match[] = { { .compatible = "microchip,mcp23008", .data = (void *) MCP_TYPE_008, @@ -789,7 +789,7 @@ static int mcp230xx_probe(struct i2c_client *client, pullups = pdata->chip[0].pullups; } - mcp = kzalloc(sizeof *mcp, GFP_KERNEL); + mcp = kzalloc(sizeof(*mcp), GFP_KERNEL); if (!mcp) return -ENOMEM; @@ -867,7 +867,7 @@ static int mcp23s08_probe(struct spi_device *spi) { struct mcp23s08_platform_data *pdata; unsigned addr; - unsigned chips = 0; + int chips = 0; struct mcp23s08_driver_data *data; int status, type; unsigned base = -1, @@ -895,8 +895,11 @@ static int mcp23s08_probe(struct spi_device *spi) return -ENODEV; } - for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) + for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { pullups[addr] = 0; + if (spi_present_mask & (1 << addr)) + chips++; + } } else { type = spi_get_device_id(spi)->driver_data; pdata = dev_get_platdata(&spi->dev); @@ -919,13 +922,13 @@ static int mcp23s08_probe(struct spi_device *spi) pullups[addr] = pdata->chip[addr].pullups; } - if (!chips) - return -ENODEV; - base = pdata->base; } - data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08), + if (!chips) + return -ENODEV; + + data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08), GFP_KERNEL); if (!data) return -ENOMEM; diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c index 2af990022cc..4661e181be0 100644 --- a/drivers/gpio/gpio-moxart.c +++ b/drivers/gpio/gpio-moxart.c @@ -48,25 +48,6 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset) pinctrl_free_gpio(offset); } -static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - writel(readl(ioaddr) & ~BIT(offset), ioaddr); - return 0; -} - -static int moxart_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct moxart_gpio_chip *gc = to_moxart_gpio(chip); - void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; - - writel(readl(ioaddr) | BIT(offset), ioaddr); - return 0; -} - static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { struct moxart_gpio_chip *gc = to_moxart_gpio(chip); @@ -78,7 +59,6 @@ static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value) else reg = reg & ~BIT(offset); - writel(reg, ioaddr); } @@ -93,6 +73,26 @@ static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset)); } +static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; + + writel(readl(ioaddr) & ~BIT(offset), ioaddr); + return 0; +} + +static int moxart_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct moxart_gpio_chip *gc = to_moxart_gpio(chip); + void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION; + + moxart_gpio_set(chip, offset, value); + writel(readl(ioaddr) | BIT(offset), ioaddr); + return 0; +} + static struct gpio_chip moxart_template_chip = { .label = "moxart-gpio", .request = moxart_gpio_request, @@ -113,10 +113,8 @@ static int moxart_gpio_probe(struct platform_device *pdev) int ret; mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL); - if (!mgc) { - dev_err(dev, "can't allocate GPIO chip container\n"); + if (!mgc) return -ENOMEM; - } mgc->gpio = moxart_template_chip; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 3b1fd1ce460..418e3865036 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -44,6 +44,7 @@ #include <linux/of_device.h> #include <linux/clk.h> #include <linux/pinctrl/consumer.h> +#include <linux/irqchip/chained_irq.h> /* * GPIO unit register offsets. @@ -438,12 +439,15 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); u32 cause, type; int i; if (mvchip == NULL) return; + chained_irq_enter(chip, desc); + cause = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) & readl_relaxed(mvebu_gpioreg_level_mask(mvchip)); cause |= readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)) & @@ -466,8 +470,11 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) polarity ^= 1 << i; writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip)); } + generic_handle_irq(irq); } + + chained_irq_exit(chip, desc); } #ifdef CONFIG_DEBUG_FS @@ -528,7 +535,7 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) #define mvebu_gpio_dbg_show NULL #endif -static struct of_device_id mvebu_gpio_of_match[] = { +static const struct of_device_id mvebu_gpio_of_match[] = { { .compatible = "marvell,orion-gpio", .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, @@ -567,10 +574,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL); - if (!mvchip) { - dev_err(&pdev->dev, "Cannot allocate memory\n"); + if (!mvchip) return -ENOMEM; - } if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { dev_err(&pdev->dev, "Missing ngpios OF property\n"); @@ -731,9 +736,4 @@ static struct platform_driver mvebu_gpio_driver = { }, .probe = mvebu_gpio_probe, }; - -static int __init mvebu_gpio_init(void) -{ - return platform_driver_register(&mvebu_gpio_driver); -} -postcore_initcall(mvebu_gpio_init); +module_platform_driver(mvebu_gpio_driver); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 532bcb336ef..8ffdd7d2bad 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -214,7 +214,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR; ct->regs.mask = PINCTRL_IRQEN(port); - irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0); + irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK, + IRQ_NOREQUEST, 0); } static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 424319061e0..00f29aa1fb9 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -24,9 +24,9 @@ #include <linux/pm.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/irqdomain.h> #include <linux/irqchip/chained_irq.h> #include <linux/gpio.h> +#include <linux/bitops.h> #include <linux/platform_data/gpio-omap.h> #define OFF_MODE 1 @@ -52,7 +52,6 @@ struct gpio_bank { struct list_head node; void __iomem *base; u16 irq; - struct irq_domain *domain; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; @@ -84,22 +83,21 @@ struct gpio_bank { }; #define GPIO_INDEX(bank, gpio) (gpio % bank->width) -#define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio)) +#define GPIO_BIT(bank, gpio) (BIT(GPIO_INDEX(bank, gpio))) #define GPIO_MOD_CTRL_BIT BIT(0) #define BANK_USED(bank) (bank->mod_usage || bank->irq_usage) -#define LINE_USED(line, offset) (line & (1 << offset)) +#define LINE_USED(line, offset) (line & (BIT(offset))) static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq) { return bank->chip.base + gpio_irq; } -static int omap_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +static inline struct gpio_bank *_irq_data_get_bank(struct irq_data *d) { - struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); - - return irq_find_mapping(bank->domain, offset); + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + return container_of(chip, struct gpio_bank, chip); } static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) @@ -110,9 +108,9 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input) reg += bank->regs->direction; l = readl_relaxed(reg); if (is_input) - l |= 1 << gpio; + l |= BIT(gpio); else - l &= ~(1 << gpio); + l &= ~(BIT(gpio)); writel_relaxed(l, reg); bank->context.oe = l; } @@ -155,14 +153,14 @@ static int _get_gpio_datain(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->datain; - return (readl_relaxed(reg) & (1 << offset)) != 0; + return (readl_relaxed(reg) & (BIT(offset))) != 0; } static int _get_gpio_dataout(struct gpio_bank *bank, int offset) { void __iomem *reg = bank->base + bank->regs->dataout; - return (readl_relaxed(reg) & (1 << offset)) != 0; + return (readl_relaxed(reg) & (BIT(offset))) != 0; } static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) @@ -180,7 +178,7 @@ static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) static inline void _gpio_dbck_enable(struct gpio_bank *bank) { if (bank->dbck_enable_mask && !bank->dbck_enabled) { - clk_enable(bank->dbck); + clk_prepare_enable(bank->dbck); bank->dbck_enabled = true; writel_relaxed(bank->dbck_enable_mask, @@ -198,7 +196,7 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank) */ writel_relaxed(0, bank->base + bank->regs->debounce_en); - clk_disable(bank->dbck); + clk_disable_unprepare(bank->dbck); bank->dbck_enabled = false; } } @@ -231,7 +229,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, l = GPIO_BIT(bank, gpio); - clk_enable(bank->dbck); + clk_prepare_enable(bank->dbck); reg = bank->base + bank->regs->debounce; writel_relaxed(debounce, reg); @@ -245,7 +243,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio, bank->dbck_enable_mask = val; writel_relaxed(val, reg); - clk_disable(bank->dbck); + clk_disable_unprepare(bank->dbck); /* * Enable debounce clock per module. * This call is mandatory because in omap_gpio_request() when @@ -290,7 +288,7 @@ static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio) bank->context.debounce = 0; writel_relaxed(bank->context.debounce, bank->base + bank->regs->debounce); - clk_disable(bank->dbck); + clk_disable_unprepare(bank->dbck); bank->dbck_enabled = false; } } @@ -299,7 +297,7 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio, unsigned trigger) { void __iomem *base = bank->base; - u32 gpio_bit = 1 << gpio; + u32 gpio_bit = BIT(gpio); _gpio_rmw(base, bank->regs->leveldetect0, gpio_bit, trigger & IRQ_TYPE_LEVEL_LOW); @@ -368,9 +366,9 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) l = readl_relaxed(reg); if ((l >> gpio) & 1) - l &= ~(1 << gpio); + l &= ~(BIT(gpio)); else - l |= 1 << gpio; + l |= BIT(gpio); writel_relaxed(l, reg); } @@ -392,11 +390,11 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, l = readl_relaxed(reg); if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) - bank->toggle_mask |= 1 << gpio; + bank->toggle_mask |= BIT(gpio); if (trigger & IRQ_TYPE_EDGE_RISING) - l |= 1 << gpio; + l |= BIT(gpio); else if (trigger & IRQ_TYPE_EDGE_FALLING) - l &= ~(1 << gpio); + l &= ~(BIT(gpio)); else return -EINVAL; @@ -413,10 +411,10 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, if (trigger & IRQ_TYPE_EDGE_RISING) l |= 2 << (gpio << 1); if (trigger & IRQ_TYPE_EDGE_FALLING) - l |= 1 << (gpio << 1); + l |= BIT(gpio << 1); /* Enable wake-up during idle for dynamic tick */ - _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger); + _gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger); bank->context.wake_en = readl_relaxed(bank->base + bank->regs->wkup_en); writel_relaxed(l, reg); @@ -430,7 +428,7 @@ static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset) void __iomem *reg = bank->base + bank->regs->pinctrl; /* Claim the pin for MPU */ - writel_relaxed(readl_relaxed(reg) | (1 << offset), reg); + writel_relaxed(readl_relaxed(reg) | (BIT(offset)), reg); } if (bank->regs->ctrl && !BANK_USED(bank)) { @@ -453,7 +451,7 @@ static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset) !LINE_USED(bank->mod_usage, offset) && !LINE_USED(bank->irq_usage, offset)) { /* Disable wake-up during idle for dynamic tick */ - _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0); + _gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0); bank->context.wake_en = readl_relaxed(bank->base + bank->regs->wkup_en); } @@ -479,7 +477,7 @@ static int gpio_is_input(struct gpio_bank *bank, int mask) static int gpio_irq_type(struct irq_data *d, unsigned type) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned gpio = 0; int retval; unsigned long flags; @@ -509,20 +507,12 @@ static int gpio_irq_type(struct irq_data *d, unsigned type) if (!LINE_USED(bank->mod_usage, offset)) { _enable_gpio_module(bank, offset); _set_gpio_direction(bank, offset, 1); - } else if (!gpio_is_input(bank, 1 << offset)) { + } else if (!gpio_is_input(bank, BIT(offset))) { spin_unlock_irqrestore(&bank->lock, flags); 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); + bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio)); spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) @@ -559,7 +549,7 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank) { void __iomem *reg = bank->base; u32 l; - u32 mask = (1 << bank->width) - 1; + u32 mask = (BIT(bank->width)) - 1; reg += bank->regs->irqenable; l = readl_relaxed(reg); @@ -664,7 +654,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio) /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */ static int gpio_wake_enable(struct irq_data *d, unsigned int enable) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); return _set_gpio_wakeup(bank, gpio, enable); @@ -691,7 +681,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); _enable_gpio_module(bank, offset); } - bank->mod_usage |= 1 << offset; + bank->mod_usage |= BIT(offset); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -703,7 +693,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - bank->mod_usage &= ~(1 << offset); + bank->mod_usage &= ~(BIT(offset)); _disable_gpio_module(bank, offset); _reset_gpio(bank, bank->chip.base + offset); spin_unlock_irqrestore(&bank->lock, flags); @@ -732,11 +722,12 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) unsigned int bit; struct gpio_bank *bank; int unmasked = 0; - struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + struct gpio_chip *chip = irq_get_handler_data(irq); - chained_irq_enter(chip, desc); + chained_irq_enter(irqchip, desc); - bank = irq_get_handler_data(irq); + bank = container_of(chip, struct gpio_bank, chip); isr_reg = bank->base + bank->regs->irqstatus; pm_runtime_get_sync(bank->dev); @@ -764,7 +755,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) configured, we could unmask GPIO bank interrupt immediately */ if (!level_mask && !unmasked) { unmasked = 1; - chained_irq_exit(chip, desc); + chained_irq_exit(irqchip, desc); } if (!isr) @@ -772,7 +763,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) while (isr) { bit = __ffs(isr); - isr &= ~(1 << bit); + isr &= ~(BIT(bit)); /* * Some chips can't respond to both rising and falling @@ -781,10 +772,11 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) * to respond to the IRQ for the opposite direction. * This will be indicated in the bank toggle_mask. */ - if (bank->toggle_mask & (1 << bit)) + if (bank->toggle_mask & (BIT(bit))) _toggle_gpio_edge_triggering(bank, bit); - generic_handle_irq(irq_find_mapping(bank->domain, bit)); + generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, + bit)); } } /* if bank has any level sensitive GPIO pin interrupt @@ -793,20 +785,20 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) interrupt */ exit: if (!unmasked) - chained_irq_exit(chip, desc); + chained_irq_exit(irqchip, desc); pm_runtime_put(bank->dev); } static void gpio_irq_shutdown(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; unsigned offset = GPIO_INDEX(bank, gpio); spin_lock_irqsave(&bank->lock, flags); gpio_unlock_as_irq(&bank->chip, offset); - bank->irq_usage &= ~(1 << offset); + bank->irq_usage &= ~(BIT(offset)); _disable_gpio_module(bank, offset); _reset_gpio(bank, gpio); spin_unlock_irqrestore(&bank->lock, flags); @@ -821,7 +813,7 @@ static void gpio_irq_shutdown(struct irq_data *d) static void gpio_ack_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); _clear_gpio_irqstatus(bank, gpio); @@ -829,7 +821,7 @@ static void gpio_ack_irq(struct irq_data *d) static void gpio_mask_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned long flags; @@ -841,7 +833,7 @@ static void gpio_mask_irq(struct irq_data *d) static void gpio_unmask_irq(struct irq_data *d) { - struct gpio_bank *bank = irq_data_get_irq_chip_data(d); + struct gpio_bank *bank = _irq_data_get_bank(d); unsigned int gpio = irq_to_gpio(bank, d->hwirq); unsigned int irq_mask = GPIO_BIT(bank, gpio); u32 trigger = irqd_get_trigger_type(d); @@ -936,6 +928,21 @@ static inline void mpuio_init(struct gpio_bank *bank) /*---------------------------------------------------------------------*/ +static int gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct gpio_bank *bank; + unsigned long flags; + void __iomem *reg; + int dir; + + bank = container_of(chip, struct gpio_bank, chip); + reg = bank->base + bank->regs->direction; + spin_lock_irqsave(&bank->lock, flags); + dir = !!(readl_relaxed(reg) & BIT(offset)); + spin_unlock_irqrestore(&bank->lock, flags); + return dir; +} + static int gpio_input(struct gpio_chip *chip, unsigned offset) { struct gpio_bank *bank; @@ -954,7 +961,7 @@ static int gpio_get(struct gpio_chip *chip, unsigned offset) u32 mask; bank = container_of(chip, struct gpio_bank, chip); - mask = (1 << offset); + mask = (BIT(offset)); if (gpio_is_input(bank, mask)) return _get_gpio_datain(bank, offset); @@ -1081,10 +1088,12 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -static void omap_gpio_chip_init(struct gpio_bank *bank) +static int omap_gpio_chip_init(struct gpio_bank *bank) { int j; static int gpio; + int irq_base = 0; + int ret; /* * REVISIT eventually switch from OMAP-specific gpio structs @@ -1092,12 +1101,12 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) */ bank->chip.request = omap_gpio_request; bank->chip.free = omap_gpio_free; + bank->chip.get_direction = gpio_get_direction; bank->chip.direction_input = gpio_input; bank->chip.get = gpio_get; bank->chip.direction_output = gpio_output; bank->chip.set_debounce = gpio_debounce; bank->chip.set = gpio_set; - bank->chip.to_irq = omap_gpio_to_irq; if (bank->is_mpuio) { bank->chip.label = "mpuio"; if (bank->regs->wkup_en) @@ -1110,22 +1119,48 @@ static void omap_gpio_chip_init(struct gpio_bank *bank) } bank->chip.ngpio = bank->width; - gpiochip_add(&bank->chip); + ret = gpiochip_add(&bank->chip); + if (ret) { + dev_err(bank->dev, "Could not register gpio chip %d\n", ret); + return ret; + } + +#ifdef CONFIG_ARCH_OMAP1 + /* + * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop + * irq_alloc_descs() since a base IRQ offset will no longer be needed. + */ + irq_base = irq_alloc_descs(-1, 0, bank->width, 0); + if (irq_base < 0) { + dev_err(bank->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } +#endif + + ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip, + irq_base, gpio_irq_handler, + IRQ_TYPE_NONE); + + if (ret) { + dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret); + ret = gpiochip_remove(&bank->chip); + return -ENODEV; + } + + gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip, + bank->irq, gpio_irq_handler); for (j = 0; j < bank->width; j++) { - int irq = irq_create_mapping(bank->domain, j); + int irq = irq_find_mapping(bank->chip.irqdomain, j); irq_set_lockdep_class(irq, &gpio_lock_class); - irq_set_chip_data(irq, bank); if (bank->is_mpuio) { omap_mpuio_alloc_gc(bank, irq, bank->width); - } else { - irq_set_chip_and_handler(irq, &gpio_irq_chip, - handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); + irq_set_chip_and_handler(irq, NULL, NULL); + set_irq_flags(irq, 0); } } - irq_set_chained_handler(bank->irq, gpio_irq_handler); - irq_set_handler_data(bank->irq, bank); + + return 0; } static const struct of_device_id omap_gpio_match[]; @@ -1138,9 +1173,7 @@ static int omap_gpio_probe(struct platform_device *pdev) const struct omap_gpio_platform_data *pdata; struct resource *res; struct gpio_bank *bank; -#ifdef CONFIG_ARCH_OMAP1 - int irq_base; -#endif + int ret; match = of_match_device(of_match_ptr(omap_gpio_match), dev); @@ -1162,6 +1195,7 @@ static int omap_gpio_probe(struct platform_device *pdev) bank->irq = res->start; bank->dev = dev; + bank->chip.dev = dev; bank->dbck_flag = pdata->dbck_flag; bank->stride = pdata->bank_stride; bank->width = pdata->bank_width; @@ -1182,29 +1216,6 @@ static int omap_gpio_probe(struct platform_device *pdev) pdata->get_context_loss_count; } -#ifdef CONFIG_ARCH_OMAP1 - /* - * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop - * irq_alloc_descs() and irq_domain_add_legacy() and just use a - * linear IRQ domain mapping for all OMAP platforms. - */ - irq_base = irq_alloc_descs(-1, 0, bank->width, 0); - if (irq_base < 0) { - dev_err(dev, "Couldn't allocate IRQ numbers\n"); - return -ENODEV; - } - - bank->domain = irq_domain_add_legacy(node, bank->width, irq_base, - 0, &irq_domain_simple_ops, NULL); -#else - bank->domain = irq_domain_add_linear(node, bank->width, - &irq_domain_simple_ops, NULL); -#endif - if (!bank->domain) { - dev_err(dev, "Couldn't register an IRQ domain\n"); - return -ENODEV; - } - if (bank->regs->set_dataout && bank->regs->clr_dataout) bank->set_dataout = _set_gpio_dataout_reg; else @@ -1214,24 +1225,10 @@ static int omap_gpio_probe(struct platform_device *pdev) /* Static mapping, never released */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!res)) { - dev_err(dev, "Invalid mem resource\n"); - irq_domain_remove(bank->domain); - return -ENODEV; - } - - if (!devm_request_mem_region(dev, res->start, resource_size(res), - pdev->name)) { - dev_err(dev, "Region already claimed\n"); - irq_domain_remove(bank->domain); - return -EBUSY; - } - - bank->base = devm_ioremap(dev, res->start, resource_size(res)); - if (!bank->base) { - dev_err(dev, "Could not ioremap\n"); - irq_domain_remove(bank->domain); - return -ENOMEM; + bank->base = devm_ioremap_resource(dev, res); + if (IS_ERR(bank->base)) { + irq_domain_remove(bank->chip.irqdomain); + return PTR_ERR(bank->base); } platform_set_drvdata(pdev, bank); @@ -1244,7 +1241,11 @@ static int omap_gpio_probe(struct platform_device *pdev) mpuio_init(bank); omap_gpio_mod_init(bank); - omap_gpio_chip_init(bank); + + ret = omap_gpio_chip_init(bank); + if (ret) + return ret; + omap_gpio_show_rev(bank); pm_runtime_put(bank->dev); diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index da9d33252e5..86bdbe36206 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -148,7 +148,7 @@ static const struct palmas_device_data tps80036_dev_data = { .ngpio = 16, }; -static struct of_device_id of_palmas_gpio_match[] = { +static const 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,}, @@ -173,10 +173,8 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio = devm_kzalloc(&pdev->dev, sizeof(*palmas_gpio), GFP_KERNEL); - if (!palmas_gpio) { - dev_err(&pdev->dev, "Could not allocate palmas_gpio\n"); + if (!palmas_gpio) return -ENOMEM; - } palmas_gpio->palmas = palmas; palmas_gpio->gpio_chip.owner = THIS_MODULE; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 019b23b955a..e721a37c347 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -1,5 +1,5 @@ /* - * PCA953x 4/8/16 bit I/O ports + * PCA953x 4/8/16/24/40 bit I/O ports * * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> * Copyright (C) 2007 Marvell International Ltd. @@ -15,8 +15,6 @@ #include <linux/init.h> #include <linux/gpio.h> #include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/i2c.h> #include <linux/platform_data/pca953x.h> #include <linux/slab.h> @@ -59,6 +57,7 @@ static const struct i2c_device_id pca953x_id[] = { { "pca9557", 8 | PCA953X_TYPE, }, { "pca9574", 8 | PCA957X_TYPE | PCA_INT, }, { "pca9575", 16 | PCA957X_TYPE | PCA_INT, }, + { "pca9698", 40 | PCA953X_TYPE, }, { "max7310", 8 | PCA953X_TYPE, }, { "max7312", 16 | PCA953X_TYPE | PCA_INT, }, @@ -68,6 +67,7 @@ static const struct i2c_device_id pca953x_id[] = { { "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, { "tca6424", 24 | PCA953X_TYPE | PCA_INT, }, + { "xra1202", 8 | PCA953X_TYPE }, { } }; MODULE_DEVICE_TABLE(i2c, pca953x_id); @@ -89,7 +89,6 @@ struct pca953x_chip { u8 irq_stat[MAX_BANK]; u8 irq_trig_raise[MAX_BANK]; u8 irq_trig_fall[MAX_BANK]; - struct irq_domain *domain; #endif struct i2c_client *client; @@ -98,6 +97,11 @@ struct pca953x_chip { int chip_type; }; +static inline struct pca953x_chip *to_pca(struct gpio_chip *gc) +{ + return container_of(gc, struct pca953x_chip, gpio_chip); +} + static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val, int off) { @@ -200,12 +204,10 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val) static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { - struct pca953x_chip *chip; + struct pca953x_chip *chip = to_pca(gc); u8 reg_val; int ret, offset = 0; - chip = container_of(gc, struct pca953x_chip, gpio_chip); - mutex_lock(&chip->i2c_lock); reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ)); @@ -231,12 +233,10 @@ exit: static int pca953x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { - struct pca953x_chip *chip; + struct pca953x_chip *chip = to_pca(gc); u8 reg_val; int ret, offset = 0; - chip = container_of(gc, struct pca953x_chip, gpio_chip); - mutex_lock(&chip->i2c_lock); /* set output level */ if (val) @@ -283,12 +283,10 @@ exit: static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) { - struct pca953x_chip *chip; + struct pca953x_chip *chip = to_pca(gc); u32 reg_val; int ret, offset = 0; - chip = container_of(gc, struct pca953x_chip, gpio_chip); - mutex_lock(&chip->i2c_lock); switch (chip->chip_type) { case PCA953X_TYPE: @@ -313,12 +311,10 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) { - struct pca953x_chip *chip; + struct pca953x_chip *chip = to_pca(gc); u8 reg_val; int ret, offset = 0; - chip = container_of(gc, struct pca953x_chip, gpio_chip); - mutex_lock(&chip->i2c_lock); if (val) reg_val = chip->reg_output[off / BANK_SZ] @@ -365,38 +361,34 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) } #ifdef CONFIG_GPIO_PCA953X_IRQ -static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off) -{ - struct pca953x_chip *chip; - - chip = container_of(gc, struct pca953x_chip, gpio_chip); - return irq_create_mapping(chip->domain, off); -} - static void pca953x_irq_mask(struct irq_data *d) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ)); } static void pca953x_irq_unmask(struct irq_data *d) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ); } static void pca953x_irq_bus_lock(struct irq_data *d) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); mutex_lock(&chip->irq_lock); } static void pca953x_irq_bus_sync_unlock(struct irq_data *d) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); u8 new_irqs; int level, i; @@ -418,7 +410,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { - struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pca953x_chip *chip = to_pca(gc); int bank_nb = d->hwirq / BANK_SZ; u8 mask = 1 << (d->hwirq % BANK_SZ); @@ -501,44 +494,25 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) struct pca953x_chip *chip = devid; u8 pending[MAX_BANK]; u8 level; + unsigned nhandled = 0; int i; if (!pca953x_irq_pending(chip, pending)) - return IRQ_HANDLED; + return IRQ_NONE; for (i = 0; i < NBANK(chip); i++) { while (pending[i]) { level = __ffs(pending[i]); - handle_nested_irq(irq_find_mapping(chip->domain, + handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain, level + (BANK_SZ * i))); pending[i] &= ~(1 << level); + nhandled++; } } - return IRQ_HANDLED; + return (nhandled > 0) ? IRQ_HANDLED : IRQ_NONE; } -static int pca953x_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - irq_clear_status_flags(irq, IRQ_NOREQUEST); - irq_set_chip_data(irq, d->host_data); - irq_set_chip(irq, &pca953x_irq_chip); - irq_set_nested_thread(irq, true); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - - return 0; -} - -static const struct irq_domain_ops pca953x_irq_simple_ops = { - .map = pca953x_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - static int pca953x_irq_setup(struct pca953x_chip *chip, const struct i2c_device_id *id, int irq_base) @@ -570,19 +544,12 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, chip->irq_stat[i] &= chip->reg_direction[i]; mutex_init(&chip->irq_lock); - chip->domain = irq_domain_add_simple(client->dev.of_node, - chip->gpio_chip.ngpio, - irq_base, - &pca953x_irq_simple_ops, - chip); - if (!chip->domain) - return -ENODEV; - ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, pca953x_irq_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + IRQF_TRIGGER_LOW | IRQF_ONESHOT | + IRQF_SHARED, dev_name(&client->dev), chip); if (ret) { dev_err(&client->dev, "failed to request irq %d\n", @@ -590,7 +557,16 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return ret; } - chip->gpio_chip.to_irq = pca953x_gpio_to_irq; + ret = gpiochip_irqchip_add(&chip->gpio_chip, + &pca953x_irq_chip, + irq_base, + handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(&client->dev, + "could not connect irqchip to gpiochip\n"); + return ret; + } } return 0; @@ -625,11 +601,12 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) const __be32 *val; int size; + *gpio_base = -1; + node = client->dev.of_node; if (node == NULL) return; - *gpio_base = -1; val = of_get_property(node, "linux,gpio-base", &size); WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__); if (val) { @@ -753,11 +730,11 @@ static int pca953x_probe(struct i2c_client *client, if (ret) return ret; - ret = pca953x_irq_setup(chip, id, irq_base); + ret = gpiochip_add(&chip->gpio_chip); if (ret) return ret; - ret = gpiochip_add(&chip->gpio_chip); + ret = pca953x_irq_setup(chip, id, irq_base); if (ret) return ret; @@ -812,6 +789,7 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "nxp,pca9557", }, { .compatible = "nxp,pca9574", }, { .compatible = "nxp,pca9575", }, + { .compatible = "nxp,pca9698", }, { .compatible = "maxim,max7310", }, { .compatible = "maxim,max7312", }, @@ -822,6 +800,8 @@ static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "ti,tca6408", }, { .compatible = "ti,tca6416", }, { .compatible = "ti,tca6424", }, + + { .compatible = "exar,xra1202", }, { } }; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 82735822bc9..27b46751ea7 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -262,7 +262,7 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio, /* enable real irq */ status = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf857x_irq, IRQF_ONESHOT | - IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_FALLING | IRQF_SHARED, dev_name(&client->dev), gpio); if (status) @@ -319,7 +319,7 @@ static int pcf857x_probe(struct i2c_client *client, status = pcf857x_irq_domain_init(gpio, client); if (status < 0) { dev_err(&client->dev, "irq_domain init failed\n"); - goto fail; + goto fail_irq_domain; } } @@ -414,12 +414,13 @@ static int pcf857x_probe(struct i2c_client *client, return 0; fail: - dev_dbg(&client->dev, "probe error %d for '%s'\n", - status, client->name); - if (client->irq) pcf857x_irq_domain_cleanup(gpio); +fail_irq_domain: + dev_dbg(&client->dev, "probe error %d for '%s'\n", + status, client->name); + return status; } diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 9656c196772..d6eac9b17db 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -20,6 +20,7 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/slab.h> #define PCH_EDGE_FALLING 0 #define PCH_EDGE_RISING BIT(0) @@ -138,9 +139,6 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, unsigned long flags; spin_lock_irqsave(&chip->spinlock, flags); - pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); - pm |= (1 << nr); - iowrite32(pm, &chip->reg->pm); reg_val = ioread32(&chip->reg->po); if (val) @@ -148,6 +146,11 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, else reg_val &= ~(1 << nr); iowrite32(reg_val, &chip->reg->po); + + pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); + pm |= (1 << nr); + iowrite32(pm, &chip->reg->pm); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b4d42112d02..84b49cfb81a 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -15,10 +15,8 @@ #include <linux/io.h> #include <linux/ioport.h> #include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/irqchip/chained_irq.h> #include <linux/bitops.h> -#include <linux/workqueue.h> #include <linux/gpio.h> #include <linux/device.h> #include <linux/amba/bus.h> @@ -53,7 +51,6 @@ struct pl061_gpio { spinlock_t lock; void __iomem *base; - struct irq_domain *domain; struct gpio_chip gc; #ifdef CONFIG_PM @@ -90,7 +87,7 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) spin_lock_irqsave(&chip->lock, flags); gpiodir = readb(chip->base + GPIODIR); - gpiodir &= ~(1 << offset); + gpiodir &= ~(BIT(offset)); writeb(gpiodir, chip->base + GPIODIR); spin_unlock_irqrestore(&chip->lock, flags); @@ -108,16 +105,16 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, return -EINVAL; spin_lock_irqsave(&chip->lock, flags); - writeb(!!value << offset, chip->base + (1 << (offset + 2))); + writeb(!!value << offset, chip->base + (BIT(offset + 2))); gpiodir = readb(chip->base + GPIODIR); - gpiodir |= 1 << offset; + gpiodir |= BIT(offset); writeb(gpiodir, chip->base + GPIODIR); /* * gpio value is set again, because pl061 doesn't allow to set value of * a gpio pin before configuring it in OUT mode. */ - writeb(!!value << offset, chip->base + (1 << (offset + 2))); + writeb(!!value << offset, chip->base + (BIT(offset + 2))); spin_unlock_irqrestore(&chip->lock, flags); return 0; @@ -127,29 +124,24 @@ static int pl061_get_value(struct gpio_chip *gc, unsigned offset) { struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - return !!readb(chip->base + (1 << (offset + 2))); + return !!readb(chip->base + (BIT(offset + 2))); } static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) { struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - writeb(!!value << offset, chip->base + (1 << (offset + 2))); -} - -static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - - return irq_create_mapping(chip->domain, offset); + writeb(!!value << offset, chip->base + (BIT(offset + 2))); } static int pl061_irq_type(struct irq_data *d, unsigned trigger) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); int offset = irqd_to_hwirq(d); unsigned long flags; u8 gpiois, gpioibe, gpioiev; + u8 bit = BIT(offset); if (offset < 0 || offset >= PL061_GPIO_NR) return -EINVAL; @@ -157,30 +149,31 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) spin_lock_irqsave(&chip->lock, flags); gpioiev = readb(chip->base + GPIOIEV); - gpiois = readb(chip->base + GPIOIS); + gpioibe = readb(chip->base + GPIOIBE); + if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { - gpiois |= 1 << offset; + gpiois |= bit; if (trigger & IRQ_TYPE_LEVEL_HIGH) - gpioiev |= 1 << offset; + gpioiev |= bit; else - gpioiev &= ~(1 << offset); + gpioiev &= ~bit; } else - gpiois &= ~(1 << offset); - writeb(gpiois, chip->base + GPIOIS); + gpiois &= ~bit; - gpioibe = readb(chip->base + GPIOIBE); if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) - gpioibe |= 1 << offset; + /* Setting this makes GPIOEV be ignored */ + gpioibe |= bit; else { - gpioibe &= ~(1 << offset); + gpioibe &= ~bit; if (trigger & IRQ_TYPE_EDGE_RISING) - gpioiev |= 1 << offset; + gpioiev |= bit; else if (trigger & IRQ_TYPE_EDGE_FALLING) - gpioiev &= ~(1 << offset); + gpioiev &= ~bit; } - writeb(gpioibe, chip->base + GPIOIBE); + writeb(gpiois, chip->base + GPIOIS); + writeb(gpioibe, chip->base + GPIOIBE); writeb(gpioiev, chip->base + GPIOIEV); spin_unlock_irqrestore(&chip->lock, flags); @@ -192,7 +185,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) { unsigned long pending; int offset; - struct pl061_gpio *chip = irq_desc_get_handler_data(desc); + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); struct irq_chip *irqchip = irq_desc_get_chip(desc); chained_irq_enter(irqchip, desc); @@ -201,7 +195,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) writeb(pending, chip->base + GPIOIC); if (pending) { for_each_set_bit(offset, &pending, PL061_GPIO_NR) - generic_handle_irq(pl061_to_irq(&chip->gc, offset)); + generic_handle_irq(irq_find_mapping(gc->irqdomain, + offset)); } chained_irq_exit(irqchip, desc); @@ -209,8 +204,9 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) static void pl061_irq_mask(struct irq_data *d) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; spin_lock(&chip->lock); @@ -221,8 +217,9 @@ static void pl061_irq_mask(struct irq_data *d) static void pl061_irq_unmask(struct irq_data *d) { - struct pl061_gpio *chip = irq_data_get_irq_chip_data(d); - u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); + u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; spin_lock(&chip->lock); @@ -232,30 +229,12 @@ static void pl061_irq_unmask(struct irq_data *d) } static struct irq_chip pl061_irqchip = { - .name = "pl061 gpio", + .name = "pl061", .irq_mask = pl061_irq_mask, .irq_unmask = pl061_irq_unmask, .irq_set_type = pl061_irq_type, }; -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(irq, &pl061_irqchip, handle_simple_irq, - "pl061"); - irq_set_chip_data(irq, chip); - irq_set_irq_type(irq, IRQ_TYPE_NONE); - - return 0; -} - -static const struct irq_domain_ops pl061_domain_ops = { - .map = pl061_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; @@ -270,21 +249,18 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) if (pdata) { chip->gc.base = pdata->gpio_base; irq_base = pdata->irq_base; - if (irq_base <= 0) + if (irq_base <= 0) { + dev_err(&adev->dev, "invalid IRQ base in pdata\n"); return -ENODEV; + } } else { chip->gc.base = -1; irq_base = 0; } - if (!devm_request_mem_region(dev, adev->res.start, - resource_size(&adev->res), "pl061")) - return -EBUSY; - - chip->base = devm_ioremap(dev, adev->res.start, - resource_size(&adev->res)); - if (!chip->base) - return -ENOMEM; + chip->base = devm_ioremap_resource(dev, &adev->res); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); spin_lock_init(&chip->lock); @@ -294,7 +270,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) chip->gc.direction_output = pl061_direction_output; chip->gc.get = pl061_get_value; chip->gc.set = pl061_set_value; - chip->gc.to_irq = pl061_to_irq; chip->gc.ngpio = PL061_GPIO_NR; chip->gc.label = dev_name(dev); chip->gc.dev = dev; @@ -309,28 +284,34 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) */ writeb(0, chip->base + GPIOIE); /* disable irqs */ irq = adev->irq[0]; - if (irq < 0) + if (irq < 0) { + dev_err(&adev->dev, "invalid IRQ\n"); return -ENODEV; + } - irq_set_chained_handler(irq, pl061_irq_handler); - irq_set_handler_data(irq, chip); - - chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR, - irq_base, &pl061_domain_ops, chip); - if (!chip->domain) - return -ENODEV; + ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip, + irq_base, handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_info(&adev->dev, "could not add irqchip\n"); + return ret; + } + gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip, + irq, pl061_irq_handler); for (i = 0; i < PL061_GPIO_NR; i++) { if (pdata) { - if (pdata->directions & (1 << i)) + if (pdata->directions & (BIT(i))) pl061_direction_output(&chip->gc, i, - pdata->values & (1 << i)); + pdata->values & (BIT(i))); else pl061_direction_input(&chip->gc, i); } } amba_set_drvdata(adev, chip); + dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n", + &adev->res.start); return 0; } @@ -349,7 +330,7 @@ static int pl061_suspend(struct device *dev) chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE); for (offset = 0; offset < PL061_GPIO_NR; offset++) { - if (chip->csave_regs.gpio_dir & (1 << offset)) + if (chip->csave_regs.gpio_dir & (BIT(offset))) chip->csave_regs.gpio_data |= pl061_get_value(&chip->gc, offset) << offset; } @@ -363,10 +344,10 @@ static int pl061_resume(struct device *dev) int offset; for (offset = 0; offset < PL061_GPIO_NR; offset++) { - if (chip->csave_regs.gpio_dir & (1 << offset)) + if (chip->csave_regs.gpio_dir & (BIT(offset))) pl061_direction_output(&chip->gc, offset, chip->csave_regs.gpio_data & - (1 << offset)); + (BIT(offset))); else pl061_direction_input(&chip->gc, offset); } diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index 122b776fdc0..562b0c4d9cc 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -97,7 +97,7 @@ static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); - if ((offset >= 0) && (offset < 8)) + if (offset < RC5T583_MAX_GPIO) return rc5t583_gpio->rc5t583->irq_base + RC5T583_IRQ_GPIO0 + offset; return -EINVAL; @@ -119,10 +119,8 @@ static int rc5t583_gpio_probe(struct platform_device *pdev) rc5t583_gpio = devm_kzalloc(&pdev->dev, sizeof(*rc5t583_gpio), GFP_KERNEL); - if (!rc5t583_gpio) { - dev_warn(&pdev->dev, "Mem allocation for rc5t583_gpio failed"); + if (!rc5t583_gpio) return -ENOMEM; - } rc5t583_gpio->gpio_chip.label = "gpio-rc5t583", rc5t583_gpio->gpio_chip.owner = THIS_MODULE, diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index ca76ce75154..b6ae89ea881 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -26,6 +26,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/platform_data/gpio-rcar.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/spinlock.h> #include <linux/slab.h> @@ -283,6 +284,7 @@ static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq, static struct irq_domain_ops gpio_rcar_irq_domain_ops = { .map = gpio_rcar_irq_domain_map, + .xlate = irq_domain_xlate_twocell, }; struct gpio_rcar_info { @@ -356,12 +358,12 @@ static int gpio_rcar_probe(struct platform_device *pdev) struct resource *io, *irq; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; - const char *name = dev_name(&pdev->dev); + struct device *dev = &pdev->dev; + const char *name = dev_name(dev); int ret; - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); if (!p) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); ret = -ENOMEM; goto err0; } @@ -376,19 +378,21 @@ static int gpio_rcar_probe(struct platform_device *pdev) platform_set_drvdata(pdev, p); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!io || !irq) { - dev_err(&pdev->dev, "missing IRQ or IOMEM\n"); + dev_err(dev, "missing IRQ or IOMEM\n"); ret = -EINVAL; goto err0; } - p->base = devm_ioremap_nocache(&pdev->dev, io->start, - resource_size(io)); + p->base = devm_ioremap_nocache(dev, io->start, resource_size(io)); if (!p->base) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); + dev_err(dev, "failed to remap I/O memory\n"); ret = -ENXIO; goto err0; } @@ -402,7 +406,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) gpio_chip->set = gpio_rcar_set; gpio_chip->to_irq = gpio_rcar_to_irq; gpio_chip->label = name; - gpio_chip->dev = &pdev->dev; + gpio_chip->dev = dev; gpio_chip->owner = THIS_MODULE; gpio_chip->base = p->config.gpio_base; gpio_chip->ngpio = p->config.number_of_pins; @@ -421,30 +425,30 @@ static int gpio_rcar_probe(struct platform_device *pdev) &gpio_rcar_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; - dev_err(&pdev->dev, "cannot initialize irq domain\n"); + dev_err(dev, "cannot initialize irq domain\n"); goto err0; } - if (devm_request_irq(&pdev->dev, irq->start, - gpio_rcar_irq_handler, IRQF_SHARED, name, p)) { - dev_err(&pdev->dev, "failed to request IRQ\n"); + if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler, + IRQF_SHARED, name, p)) { + dev_err(dev, "failed to request IRQ\n"); ret = -ENOENT; goto err1; } ret = gpiochip_add(gpio_chip); if (ret) { - dev_err(&pdev->dev, "failed to add GPIO controller\n"); + dev_err(dev, "failed to add GPIO controller\n"); goto err1; } - dev_info(&pdev->dev, "driving %d GPIOs\n", p->config.number_of_pins); + dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins); /* warn in case of mismatch if irq base is specified */ if (p->config.irq_base) { ret = irq_find_mapping(p->irq_domain, 0); if (p->config.irq_base != ret) - dev_warn(&pdev->dev, "irq base mismatch (%u/%u)\n", + dev_warn(dev, "irq base mismatch (%u/%u)\n", p->config.irq_base, ret); } @@ -452,7 +456,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0, gpio_chip->base, gpio_chip->ngpio); if (ret < 0) - dev_warn(&pdev->dev, "failed to add pin range\n"); + dev_warn(dev, "failed to add pin range\n"); } return 0; @@ -460,6 +464,8 @@ static int gpio_rcar_probe(struct platform_device *pdev) err1: irq_domain_remove(p->irq_domain); err0: + pm_runtime_put(dev); + pm_runtime_disable(dev); return ret; } @@ -473,6 +479,8 @@ static int gpio_rcar_remove(struct platform_device *pdev) return ret; irq_domain_remove(p->irq_domain); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index 88577c3272a..9fa7e53331c 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -141,17 +141,15 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) return -ENODEV; } - rdc321x_gpio_dev = kzalloc(sizeof(struct rdc321x_gpio), GFP_KERNEL); - if (!rdc321x_gpio_dev) { - dev_err(&pdev->dev, "failed to allocate private data\n"); + rdc321x_gpio_dev = devm_kzalloc(&pdev->dev, sizeof(struct rdc321x_gpio), + GFP_KERNEL); + if (!rdc321x_gpio_dev) return -ENOMEM; - } r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1"); if (!r) { dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n"); - err = -ENODEV; - goto out_free; + return -ENODEV; } spin_lock_init(&rdc321x_gpio_dev->lock); @@ -162,8 +160,7 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2"); if (!r) { dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n"); - err = -ENODEV; - goto out_free; + return -ENODEV; } rdc321x_gpio_dev->reg2_ctrl_base = r->start; @@ -187,21 +184,17 @@ static int rdc321x_gpio_probe(struct platform_device *pdev) rdc321x_gpio_dev->reg1_data_base, &rdc321x_gpio_dev->data_reg[0]); if (err) - goto out_free; + return err; err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev, rdc321x_gpio_dev->reg2_data_base, &rdc321x_gpio_dev->data_reg[1]); if (err) - goto out_free; + return err; dev_info(&pdev->dev, "registering %d GPIOs\n", rdc321x_gpio_dev->chip.ngpio); return gpiochip_add(&rdc321x_gpio_dev->chip); - -out_free: - kfree(rdc321x_gpio_dev); - return err; } static int rdc321x_gpio_remove(struct platform_device *pdev) @@ -213,8 +206,6 @@ static int rdc321x_gpio_remove(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "failed to unregister chip\n"); - kfree(rdc321x_gpio_dev); - return ret; } diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index a85e00bf983..07105ee5c9a 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -379,6 +379,7 @@ static int s5p64x0_gpio_setcfg_rbank(struct samsung_gpio_chip *chip, case 6: shift = ((off + 1) & 7) * 4; reg -= 4; + break; default: shift = ((off + 1) & 7) * 4; break; diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 5af65719b95..a9b1cd16c84 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -97,8 +97,6 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc, u8 curr_dirs; unsigned short offset, bit; - sch_gpio_core_set(gc, gpio_num, val); - spin_lock(&gpio_lock); offset = CGIO + gpio_num / 8; @@ -109,6 +107,17 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc, outb(curr_dirs & ~(1 << bit), gpio_ba + offset); spin_unlock(&gpio_lock); + + /* + * according to the datasheet, writing to the level register has no + * effect when GPIO is programmed as input. + * Actually the the level register is read-only when configured as input. + * Thus presetting the output level before switching to output is _NOT_ possible. + * Hence we set the level after configuring the GPIO as output. + * But we cannot prevent a short low pulse if direction is set to high + * and an external pull-up is connected. + */ + sch_gpio_core_set(gc, gpio_num, val); return 0; } @@ -178,8 +187,6 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc, u8 curr_dirs; unsigned short offset, bit; - sch_gpio_resume_set(gc, gpio_num, val); - offset = RGIO + gpio_num / 8; bit = gpio_num % 8; @@ -190,6 +197,17 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc, outb(curr_dirs & ~(1 << bit), gpio_ba + offset); spin_unlock(&gpio_lock); + + /* + * according to the datasheet, writing to the level register has no + * effect when GPIO is programmed as input. + * Actually the the level register is read-only when configured as input. + * Thus presetting the output level before switching to output is _NOT_ possible. + * Hence we set the level after configuring the GPIO as output. + * But we cannot prevent a short low pulse if direction is set to high + * and an external pull-up is connected. + */ + sch_gpio_resume_set(gc, gpio_num, val); return 0; } diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c index 0357387b364..f942b80ee40 100644 --- a/drivers/gpio/gpio-sch311x.c +++ b/drivers/gpio/gpio-sch311x.c @@ -327,14 +327,22 @@ static int __init sch311x_detect(int sio_config_port, unsigned short *addr) if (err) return err; - /* Check device ID. We currently know about: - * SCH3112 (0x7c), SCH3114 (0x7d), and SCH3116 (0x7f). */ + /* Check device ID. */ reg = sch311x_sio_inb(sio_config_port, 0x20); - if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) { + switch (reg) { + case 0x7c: /* SCH3112 */ + dev_id = 2; + break; + case 0x7d: /* SCH3114 */ + dev_id = 4; + break; + case 0x7f: /* SCH3116 */ + dev_id = 6; + break; + default: err = -ENODEV; goto exit; } - dev_id = reg == 0x7c ? 2 : reg == 0x7d ? 4 : 6; /* Select logical device A (runtime registers) */ sch311x_sio_outb(sio_config_port, 0x07, 0x0a); diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c index e9a0415834e..353263c85d2 100644 --- a/drivers/gpio/gpio-spear-spics.c +++ b/drivers/gpio/gpio-spear-spics.c @@ -2,7 +2,7 @@ * SPEAr platform SPI chipselect abstraction over gpiolib * * Copyright (C) 2012 ST Microelectronics - * Shiraz Hashim <shiraz.hashim@st.com> + * Shiraz Hashim <shiraz.linux.kernel@gmail.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -129,10 +129,8 @@ static int spics_gpio_probe(struct platform_device *pdev) int ret; spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL); - if (!spics) { - dev_err(&pdev->dev, "memory allocation fail\n"); + if (!spics) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); spics->base = devm_ioremap_resource(&pdev->dev, res); @@ -205,6 +203,6 @@ static int __init spics_gpio_init(void) } subsys_initcall(spics_gpio_init); -MODULE_AUTHOR("Shiraz Hashim <shiraz.hashim@st.com>"); +MODULE_AUTHOR("Shiraz Hashim <shiraz.linux.kernel@gmail.com>"); MODULE_DESCRIPTION("ST Microlectronics SPEAr SPI Chip Select Abstraction"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 2776a09bee5..628b5849429 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -23,7 +23,8 @@ enum { REG_RE, REG_FE, REG_IE }; #define CACHE_NR_REGS 3 -#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8) +/* No variant has more than 24 GPIOs */ +#define CACHE_NR_BANKS (24 / 8) struct stmpe_gpio { struct gpio_chip chip; @@ -31,8 +32,6 @@ struct stmpe_gpio { struct device *dev; struct mutex irq_lock; struct irq_domain *domain; - - int irq_base; unsigned norequest_mask; /* Caches of interrupt control registers for bus_lock */ @@ -311,13 +310,8 @@ static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio, struct device_node *np) { - int base = 0; - - if (!np) - base = stmpe_gpio->irq_base; - stmpe_gpio->domain = irq_domain_add_simple(np, - stmpe_gpio->chip.ngpio, base, + stmpe_gpio->chip.ngpio, 0, &stmpe_gpio_irq_simple_ops, stmpe_gpio); if (!stmpe_gpio->domain) { dev_err(stmpe_gpio->dev, "failed to create irqdomain\n"); @@ -354,7 +348,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_OF stmpe_gpio->chip.of_node = np; #endif - stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1; + stmpe_gpio->chip.base = -1; if (pdata) stmpe_gpio->norequest_mask = pdata->norequest_mask; @@ -362,9 +356,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) of_property_read_u32(np, "st,norequest-mask", &stmpe_gpio->norequest_mask); - if (irq >= 0) - stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0); - else + if (irq < 0) dev_info(&pdev->dev, "device configured in no-irq mode; " "irqs are not available\n"); diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index 13d73fb2b5e..b51ca9f5c14 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -22,7 +22,6 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/slab.h> -#include <linux/workqueue.h> #include <linux/i2c/sx150x.h> #define NO_UPDATE_PENDING -1 diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c new file mode 100644 index 00000000000..b50fe129774 --- /dev/null +++ b/drivers/gpio/gpio-syscon.c @@ -0,0 +1,191 @@ +/* + * SYSCON GPIO driver + * + * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> + * + * 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/err.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> + +#define GPIO_SYSCON_FEAT_IN BIT(0) +#define GPIO_SYSCON_FEAT_OUT BIT(1) +#define GPIO_SYSCON_FEAT_DIR BIT(2) + +/* SYSCON driver is designed to use 32-bit wide registers */ +#define SYSCON_REG_SIZE (4) +#define SYSCON_REG_BITS (SYSCON_REG_SIZE * 8) + +/** + * struct syscon_gpio_data - Configuration for the device. + * compatible: SYSCON driver compatible string. + * flags: Set of GPIO_SYSCON_FEAT_ flags: + * GPIO_SYSCON_FEAT_IN: GPIOs supports input, + * GPIO_SYSCON_FEAT_OUT: GPIOs supports output, + * GPIO_SYSCON_FEAT_DIR: GPIOs supports switch direction. + * bit_count: Number of bits used as GPIOs. + * dat_bit_offset: Offset (in bits) to the first GPIO bit. + * dir_bit_offset: Optional offset (in bits) to the first bit to switch + * GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag). + */ + +struct syscon_gpio_data { + const char *compatible; + unsigned int flags; + unsigned int bit_count; + unsigned int dat_bit_offset; + unsigned int dir_bit_offset; +}; + +struct syscon_gpio_priv { + struct gpio_chip chip; + struct regmap *syscon; + const struct syscon_gpio_data *data; +}; + +static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct syscon_gpio_priv, chip); +} + +static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + unsigned int val, offs = priv->data->dat_bit_offset + offset; + int ret; + + ret = regmap_read(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val); + if (ret) + return ret; + + return !!(val & BIT(offs % SYSCON_REG_BITS)); +} + +static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + unsigned int offs = priv->data->dat_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), + val ? BIT(offs % SYSCON_REG_BITS) : 0); +} + +static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + + if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { + unsigned int offs = priv->data->dir_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), 0); + } + + return 0; +} + +static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val) +{ + struct syscon_gpio_priv *priv = to_syscon_gpio(chip); + + if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) { + unsigned int offs = priv->data->dir_bit_offset + offset; + + regmap_update_bits(priv->syscon, + (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, + BIT(offs % SYSCON_REG_BITS), + BIT(offs % SYSCON_REG_BITS)); + } + + syscon_gpio_set(chip, offset, val); + + return 0; +} + +static const struct syscon_gpio_data clps711x_mctrl_gpio = { + /* ARM CLPS711X SYSFLG1 Bits 8-10 */ + .compatible = "cirrus,clps711x-syscon1", + .flags = GPIO_SYSCON_FEAT_IN, + .bit_count = 3, + .dat_bit_offset = 0x40 * 8 + 8, +}; + +static const struct of_device_id syscon_gpio_ids[] = { + { + .compatible = "cirrus,clps711x-mctrl-gpio", + .data = &clps711x_mctrl_gpio, + }, + { } +}; +MODULE_DEVICE_TABLE(of, syscon_gpio_ids); + +static int syscon_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev); + struct syscon_gpio_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_id->data; + + priv->syscon = + syscon_regmap_lookup_by_compatible(priv->data->compatible); + if (IS_ERR(priv->syscon)) + return PTR_ERR(priv->syscon); + + priv->chip.dev = dev; + priv->chip.owner = THIS_MODULE; + priv->chip.label = dev_name(dev); + priv->chip.base = -1; + priv->chip.ngpio = priv->data->bit_count; + priv->chip.get = syscon_gpio_get; + if (priv->data->flags & GPIO_SYSCON_FEAT_IN) + priv->chip.direction_input = syscon_gpio_dir_in; + if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) { + priv->chip.set = syscon_gpio_set; + priv->chip.direction_output = syscon_gpio_dir_out; + } + + platform_set_drvdata(pdev, priv); + + return gpiochip_add(&priv->chip); +} + +static int syscon_gpio_remove(struct platform_device *pdev) +{ + struct syscon_gpio_priv *priv = platform_get_drvdata(pdev); + + return gpiochip_remove(&priv->chip); +} + +static struct platform_driver syscon_gpio_driver = { + .driver = { + .name = "gpio-syscon", + .owner = THIS_MODULE, + .of_match_table = syscon_gpio_ids, + }, + .probe = syscon_gpio_probe, + .remove = syscon_gpio_remove, +}; +module_platform_driver(syscon_gpio_driver); + +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("SYSCON GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 1019320984d..51f7cbd9ff7 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -12,8 +12,6 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/of.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> #include <linux/interrupt.h> #include <linux/mfd/tc3589x.h> @@ -31,10 +29,6 @@ struct tc3589x_gpio { struct tc3589x *tc3589x; struct device *dev; struct mutex irq_lock; - struct irq_domain *domain; - - int irq_base; - /* Caches of interrupt control registers for bus_lock */ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; @@ -95,30 +89,6 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip, return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); } -/** - * 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 hardware interrupt requested in the chip IRQs - * - * Useful for drivers to request their own IRQs. - */ -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, 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_irq(tc3589x_gpio, offset); -} - static struct gpio_chip template_chip = { .label = "tc3589x", .owner = THIS_MODULE, @@ -126,13 +96,13 @@ static struct gpio_chip template_chip = { .get = tc3589x_gpio_get, .direction_output = tc3589x_gpio_direction_output, .set = tc3589x_gpio_set, - .to_irq = tc3589x_gpio_to_irq, .can_sleep = true, }; static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -159,14 +129,16 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void tc3589x_gpio_irq_lock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); mutex_lock(&tc3589x_gpio->irq_lock); } static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; static const u8 regmap[] = { [REG_IBE] = TC3589x_GPIOIBE0, @@ -194,7 +166,8 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) static void tc3589x_gpio_irq_mask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -204,7 +177,8 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d) static void tc3589x_gpio_irq_unmask(struct irq_data *d) { - struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -242,7 +216,8 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = i * 8 + bit; - int irq = tc3589x_gpio_irq_get_irq(tc3589x_gpio, line); + int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain, + line); handle_nested_irq(irq); stat &= ~(1 << bit); @@ -254,61 +229,6 @@ 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 irq, - irq_hw_number_t hwirq) -{ - struct tc3589x *tc3589x_gpio = d->host_data; - - irq_set_chip_data(irq, tc3589x_gpio); - irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, - handle_simple_irq); - irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - - return 0; -} - -static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) -{ -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); -} - -static struct irq_domain_ops tc3589x_irq_ops = { - .map = tc3589x_gpio_irq_map, - .unmap = tc3589x_gpio_irq_unmap, - .xlate = irq_domain_xlate_twocell, -}; - -static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, - struct device_node *np) -{ - int base = tc3589x_gpio->irq_base; - - /* - * If this results in a linear domain, irq_create_mapping() will - * take care of allocating IRQ descriptors at runtime. When a base - * is provided, the IRQ descriptors will be allocated when the - * domain is instantiated. - */ - tc3589x_gpio->domain = irq_domain_add_simple(np, - tc3589x_gpio->chip.ngpio, base, &tc3589x_irq_ops, - tc3589x_gpio); - if (!tc3589x_gpio->domain) { - dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n"); - return -ENOSYS; - } - - return 0; -} - static int tc3589x_gpio_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); @@ -329,7 +249,8 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) if (irq < 0) return irq; - tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL); + tc3589x_gpio = devm_kzalloc(&pdev->dev, sizeof(struct tc3589x_gpio), + GFP_KERNEL); if (!tc3589x_gpio) return -ENOMEM; @@ -347,30 +268,36 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) tc3589x_gpio->chip.of_node = np; #endif - tc3589x_gpio->irq_base = tc3589x->irq_base ? - tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0; - /* Bring the GPIO module out of reset */ ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_RSTCTRL_GPIRST, 0); if (ret < 0) - goto out_free; - - ret = tc3589x_gpio_irq_init(tc3589x_gpio, np); - if (ret) - goto out_free; + return ret; - ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT, - "tc3589x-gpio", tc3589x_gpio); + ret = devm_request_threaded_irq(&pdev->dev, + irq, NULL, tc3589x_gpio_irq, + IRQF_ONESHOT, "tc3589x-gpio", + tc3589x_gpio); if (ret) { dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_free; + return ret; } ret = gpiochip_add(&tc3589x_gpio->chip); if (ret) { dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); - goto out_freeirq; + return ret; + } + + ret = gpiochip_irqchip_add(&tc3589x_gpio->chip, + &tc3589x_gpio_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(&pdev->dev, + "could not connect irqchip to gpiochip\n"); + return ret; } if (pdata && pdata->setup) @@ -379,12 +306,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tc3589x_gpio); return 0; - -out_freeirq: - free_irq(irq, tc3589x_gpio); -out_free: - kfree(tc3589x_gpio); - return ret; } static int tc3589x_gpio_remove(struct platform_device *pdev) @@ -392,7 +313,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev) struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; - int irq = platform_get_irq(pdev, 0); int ret; if (pdata && pdata->remove) @@ -405,10 +325,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev) return ret; } - free_irq(irq, tc3589x_gpio); - - kfree(tc3589x_gpio); - return 0; } diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 2b49f878b56..4e8fb8261a8 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -408,7 +408,7 @@ static struct tegra_gpio_soc_config tegra30_gpio_config = { .upper_offset = 0x80, }; -static struct of_device_id tegra_gpio_of_match[] = { +static const struct of_device_id tegra_gpio_of_match[] = { { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, { }, @@ -458,10 +458,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) tegra_gpio_banks = devm_kzalloc(&pdev->dev, tegra_gpio_bank_count * sizeof(*tegra_gpio_banks), GFP_KERNEL); - if (!tegra_gpio_banks) { - dev_err(&pdev->dev, "Couldn't allocate bank structure\n"); + if (!tegra_gpio_banks) return -ENODEV; - } irq_domain = irq_domain_add_linear(pdev->dev.of_node, tegra_gpio_chip.ngpio, diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index f9a8fbde108..efc7c129016 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -224,6 +224,7 @@ static struct irq_chip timbgpio_irqchip = { static int timbgpio_probe(struct platform_device *pdev) { int err, i; + struct device *dev = &pdev->dev; struct gpio_chip *gc; struct timbgpio *tgpio; struct resource *iomem; @@ -231,35 +232,35 @@ static int timbgpio_probe(struct platform_device *pdev) int irq = platform_get_irq(pdev, 0); if (!pdata || pdata->nr_pins > 32) { - err = -EINVAL; - goto err_mem; + dev_err(dev, "Invalid platform data\n"); + return -EINVAL; } iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!iomem) { - err = -EINVAL; - goto err_mem; + dev_err(dev, "Unable to get resource\n"); + return -EINVAL; } - tgpio = kzalloc(sizeof(*tgpio), GFP_KERNEL); + tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL); if (!tgpio) { - err = -EINVAL; - goto err_mem; + dev_err(dev, "Memory alloc failed\n"); + return -EINVAL; } tgpio->irq_base = pdata->irq_base; spin_lock_init(&tgpio->lock); - if (!request_mem_region(iomem->start, resource_size(iomem), - DRIVER_NAME)) { - err = -EBUSY; - goto err_request; + if (!devm_request_mem_region(dev, iomem->start, resource_size(iomem), + DRIVER_NAME)) { + dev_err(dev, "Region already claimed\n"); + return -EBUSY; } - tgpio->membase = ioremap(iomem->start, resource_size(iomem)); + tgpio->membase = devm_ioremap(dev, iomem->start, resource_size(iomem)); if (!tgpio->membase) { - err = -ENOMEM; - goto err_ioremap; + dev_err(dev, "Cannot ioremap\n"); + return -ENOMEM; } gc = &tgpio->gpio; @@ -279,7 +280,7 @@ static int timbgpio_probe(struct platform_device *pdev) err = gpiochip_add(gc); if (err) - goto err_chipadd; + return err; platform_set_drvdata(pdev, tgpio); @@ -302,17 +303,6 @@ static int timbgpio_probe(struct platform_device *pdev) irq_set_chained_handler(irq, timbgpio_irq); return 0; - -err_chipadd: - iounmap(tgpio->membase); -err_ioremap: - release_mem_region(iomem->start, resource_size(iomem)); -err_request: - kfree(tgpio); -err_mem: - printk(KERN_ERR DRIVER_NAME": Failed to register GPIOs: %d\n", err); - - return err; } static int timbgpio_remove(struct platform_device *pdev) @@ -320,7 +310,6 @@ static int timbgpio_remove(struct platform_device *pdev) int err; struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct timbgpio *tgpio = platform_get_drvdata(pdev); - struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); if (irq >= 0 && tgpio->irq_base > 0) { @@ -338,10 +327,6 @@ static int timbgpio_remove(struct platform_device *pdev) if (err) printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n"); - iounmap(tgpio->membase); - release_mem_region(iomem->start, resource_size(iomem)); - kfree(tgpio); - return 0; } diff --git a/drivers/gpio/gpio-tnetv107x.c b/drivers/gpio/gpio-tnetv107x.c deleted file mode 100644 index 4aa481579a0..00000000000 --- a/drivers/gpio/gpio-tnetv107x.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Texas Instruments TNETV107X GPIO Controller - * - * Copyright (C) 2010 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/gpio.h> -#include <linux/platform_data/gpio-davinci.h> - -#include <mach/common.h> -#include <mach/tnetv107x.h> - -struct tnetv107x_gpio_regs { - u32 idver; - u32 data_in[3]; - u32 data_out[3]; - u32 direction[3]; - u32 enable[3]; -}; - -#define gpio_reg_index(gpio) ((gpio) >> 5) -#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f) - -#define gpio_reg_rmw(reg, mask, val) \ - __raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg)) - -#define gpio_reg_set_bit(reg, gpio) \ - gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio)) - -#define gpio_reg_clear_bit(reg, gpio) \ - gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0) - -#define gpio_reg_get_bit(reg, gpio) \ - (__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio)) - -#define chip2controller(chip) \ - container_of(chip, struct davinci_gpio_controller, chip) - -#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32) - -static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS]; - -static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - gpio_reg_set_bit(regs->enable, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); - - return 0; -} - -static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - gpio_reg_clear_bit(regs->enable, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); -} - -static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - gpio_reg_set_bit(regs->direction, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); - - return 0; -} - -static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - if (value) - gpio_reg_set_bit(regs->data_out, gpio); - else - gpio_reg_clear_bit(regs->data_out, gpio); - - gpio_reg_clear_bit(regs->direction, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); - - return 0; -} - -static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - int ret; - - ret = gpio_reg_get_bit(regs->data_in, gpio); - - return ret ? 1 : 0; -} - -static void tnetv107x_gpio_set(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct davinci_gpio_controller *ctlr = chip2controller(chip); - struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; - unsigned gpio = chip->base + offset; - unsigned long flags; - - spin_lock_irqsave(&ctlr->lock, flags); - - if (value) - gpio_reg_set_bit(regs->data_out, gpio); - else - gpio_reg_clear_bit(regs->data_out, gpio); - - spin_unlock_irqrestore(&ctlr->lock, flags); -} - -static int __init tnetv107x_gpio_setup(void) -{ - int i, base; - unsigned ngpio; - struct davinci_soc_info *soc_info = &davinci_soc_info; - struct tnetv107x_gpio_regs *regs; - struct davinci_gpio_controller *ctlr; - - if (soc_info->gpio_type != GPIO_TYPE_TNETV107X) - return 0; - - ngpio = soc_info->gpio_num; - if (ngpio == 0) { - pr_err("GPIO setup: how many GPIOs?\n"); - return -EINVAL; - } - - if (WARN_ON(TNETV107X_N_GPIO < ngpio)) - ngpio = TNETV107X_N_GPIO; - - regs = ioremap(soc_info->gpio_base, SZ_4K); - if (WARN_ON(!regs)) - return -EINVAL; - - for (i = 0, base = 0; base < ngpio; i++, base += 32) { - ctlr = &chips[i]; - - ctlr->chip.label = "tnetv107x"; - ctlr->chip.can_sleep = false; - ctlr->chip.base = base; - ctlr->chip.ngpio = ngpio - base; - if (ctlr->chip.ngpio > 32) - ctlr->chip.ngpio = 32; - - ctlr->chip.request = tnetv107x_gpio_request; - ctlr->chip.free = tnetv107x_gpio_free; - ctlr->chip.direction_input = tnetv107x_gpio_dir_in; - ctlr->chip.get = tnetv107x_gpio_get; - ctlr->chip.direction_output = tnetv107x_gpio_dir_out; - ctlr->chip.set = tnetv107x_gpio_set; - - spin_lock_init(&ctlr->lock); - - ctlr->regs = regs; - ctlr->set_data = ®s->data_out[i]; - ctlr->clr_data = ®s->data_out[i]; - ctlr->in_data = ®s->data_in[i]; - - gpiochip_add(&ctlr->chip); - } - - soc_info->gpio_ctlrs = chips; - soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32); - return 0; -} -pure_initcall(tnetv107x_gpio_setup); diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index 8994dfa1349..a69fbea4125 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -97,10 +97,8 @@ static int tps6586x_gpio_probe(struct platform_device *pdev) pdata = dev_get_platdata(pdev->dev.parent); tps6586x_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps6586x_gpio), GFP_KERNEL); - if (!tps6586x_gpio) { - dev_err(&pdev->dev, "Could not allocate tps6586x_gpio\n"); + if (!tps6586x_gpio) return -ENOMEM; - } tps6586x_gpio->parent = pdev->dev.parent; diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index b6e818e6800..e2f8cda235e 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -123,10 +123,8 @@ static int tps65910_gpio_probe(struct platform_device *pdev) tps65910_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps65910_gpio), GFP_KERNEL); - if (!tps65910_gpio) { - dev_err(&pdev->dev, "Could not allocate tps65910_gpio\n"); + if (!tps65910_gpio) return -ENOMEM; - } tps65910_gpio->tps65910 = tps65910; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 8b88ca2eda9..3ebb1a5ff22 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -139,7 +139,6 @@ static u8 cached_leden; static void twl4030_led_set_value(int led, int value) { u8 mask = LEDEN_LEDAON | LEDEN_LEDAPWM; - int status; if (led) mask <<= 1; @@ -148,8 +147,9 @@ static void twl4030_led_set_value(int led, int value) cached_leden &= ~mask; else cached_leden |= mask; - status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, - TWL4030_LED_LEDEN_REG); + + WARN_ON_ONCE(twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, + TWL4030_LED_LEDEN_REG)); } static int twl4030_set_gpio_direction(int gpio, int is_input) diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index 23e06139241..5246a60eff6 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -488,26 +488,26 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) gc->chip_types[0].handler = handle_level_irq; gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS; gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[0].chip.irq_startup = gpio_startup_irq, - gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit, - gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit, - gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit, - gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type, - gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake, - gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + gc->chip_types[0].chip.irq_startup = gpio_startup_irq; + gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type; + gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake; + gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* edge chip type */ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; gc->chip_types[1].handler = handle_edge_irq; gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS; gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN; - gc->chip_types[1].chip.irq_startup = gpio_startup_irq, - gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit, - gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit, - gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit, - gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type, - gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake, - gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND, + gc->chip_types[1].chip.irq_startup = gpio_startup_irq; + gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit; + gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type; + gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake; + gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* Setup chained handler for this GPIO bank */ irq_set_handler_data(bank->irq, bank); diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index 9902732a382..66cbcc108e6 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -81,6 +81,7 @@ static DEFINE_SPINLOCK(giu_lock); static unsigned long giu_flags; static void __iomem *giu_base; +static struct gpio_chip vr41xx_gpio_chip; #define giu_read(offset) readw(giu_base + (offset)) #define giu_write(offset, value) writew((value), giu_base + (offset)) @@ -135,12 +136,31 @@ static void unmask_giuint_low(struct irq_data *d) giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq)); } +static unsigned int startup_giuint(struct irq_data *data) +{ + if (gpio_lock_as_irq(&vr41xx_gpio_chip, data->hwirq)) + dev_err(vr41xx_gpio_chip.dev, + "unable to lock HW IRQ %lu for IRQ\n", + data->hwirq); + /* Satisfy the .enable semantics by unmasking the line */ + unmask_giuint_low(data); + return 0; +} + +static void shutdown_giuint(struct irq_data *data) +{ + mask_giuint_low(data); + gpio_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq); +} + static struct irq_chip giuint_low_irq_chip = { .name = "GIUINTL", .irq_ack = ack_giuint_low, .irq_mask = mask_giuint_low, .irq_mask_ack = mask_ack_giuint_low, .irq_unmask = unmask_giuint_low, + .irq_startup = startup_giuint, + .irq_shutdown = shutdown_giuint, }; static void ack_giuint_high(struct irq_data *d) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 792a05ad464..12481867daf 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -289,7 +289,7 @@ static int xgpio_of_probe(struct device_node *np) return 0; } -static struct of_device_id xgpio_of_match[] = { +static const struct of_device_id xgpio_of_match[] = { { .compatible = "xlnx,xps-gpio-1.00.a", }, { /* end of list */ }, }; diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c index 1d136eceda6..7081304d679 100644 --- a/drivers/gpio/gpio-xtensa.c +++ b/drivers/gpio/gpio-xtensa.c @@ -40,6 +40,8 @@ #error GPIO32 option is not enabled for your xtensa core variant #endif +#if XCHAL_HAVE_CP + static inline unsigned long enable_cp(unsigned long *cpenable) { unsigned long flags; @@ -57,6 +59,20 @@ static inline void disable_cp(unsigned long flags, unsigned long cpenable) local_irq_restore(flags); } +#else + +static inline unsigned long enable_cp(unsigned long *cpenable) +{ + *cpenable = 0; /* avoid uninitialized value warning */ + return 0; +} + +static inline void disable_cp(unsigned long flags, unsigned long cpenable) +{ +} + +#endif /* XCHAL_HAVE_CP */ + static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset) { return 1; /* input only */ diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c new file mode 100644 index 00000000000..54e54e4cc6c --- /dev/null +++ b/drivers/gpio/gpio-zevio.c @@ -0,0 +1,224 @@ +/* + * GPIO controller in LSI ZEVIO SoCs. + * + * Author: Fabian Vogt <fabian@ritter-vogt.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/slab.h> +#include <linux/gpio.h> + +/* + * Memory layout: + * This chip has four gpio sections, each controls 8 GPIOs. + * Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10. + * Disclaimer: Reverse engineered! + * For more information refer to: + * http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29 + * + * 0x00-0x3F: Section 0 + * +0x00: Masked interrupt status (read-only) + * +0x04: R: Interrupt status W: Reset interrupt status + * +0x08: R: Interrupt mask W: Mask interrupt + * +0x0C: W: Unmask interrupt (write-only) + * +0x10: Direction: I/O=1/0 + * +0x14: Output + * +0x18: Input (read-only) + * +0x20: R: Level interrupt W: Set as level interrupt + * 0x40-0x7F: Section 1 + * 0x80-0xBF: Section 2 + * 0xC0-0xFF: Section 3 + */ + +#define ZEVIO_GPIO_SECTION_SIZE 0x40 + +/* Offsets to various registers */ +#define ZEVIO_GPIO_INT_MASKED_STATUS 0x00 +#define ZEVIO_GPIO_INT_STATUS 0x04 +#define ZEVIO_GPIO_INT_UNMASK 0x08 +#define ZEVIO_GPIO_INT_MASK 0x0C +#define ZEVIO_GPIO_DIRECTION 0x10 +#define ZEVIO_GPIO_OUTPUT 0x14 +#define ZEVIO_GPIO_INPUT 0x18 +#define ZEVIO_GPIO_INT_STICKY 0x20 + +#define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \ + struct zevio_gpio, chip) + +/* Bit number of GPIO in its section */ +#define ZEVIO_GPIO_BIT(gpio) (gpio&7) + +struct zevio_gpio { + spinlock_t lock; + struct of_mm_gpio_chip chip; +}; + +static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin, + unsigned port_offset) +{ + unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; + return readl(IOMEM(c->chip.regs + section_offset + port_offset)); +} + +static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin, + unsigned port_offset, u32 val) +{ + unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE; + writel(val, IOMEM(c->chip.regs + section_offset + port_offset)); +} + +/* Functions for struct gpio_chip */ +static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val, dir; + + spin_lock(&controller->lock); + dir = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); + if (dir & BIT(ZEVIO_GPIO_BIT(pin))) + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT); + else + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); + spin_unlock(&controller->lock); + + return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1; +} + +static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val; + + spin_lock(&controller->lock); + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); + if (value) + val |= BIT(ZEVIO_GPIO_BIT(pin)); + else + val &= ~BIT(ZEVIO_GPIO_BIT(pin)); + + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); + spin_unlock(&controller->lock); +} + +static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val; + + spin_lock(&controller->lock); + + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); + val |= BIT(ZEVIO_GPIO_BIT(pin)); + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); + + spin_unlock(&controller->lock); + + return 0; +} + +static int zevio_gpio_direction_output(struct gpio_chip *chip, + unsigned pin, int value) +{ + struct zevio_gpio *controller = to_zevio_gpio(chip); + u32 val; + + spin_lock(&controller->lock); + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT); + if (value) + val |= BIT(ZEVIO_GPIO_BIT(pin)); + else + val &= ~BIT(ZEVIO_GPIO_BIT(pin)); + + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val); + val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION); + val &= ~BIT(ZEVIO_GPIO_BIT(pin)); + zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val); + + spin_unlock(&controller->lock); + + return 0; +} + +static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin) +{ + /* + * TODO: Implement IRQs. + * Not implemented yet due to weird lockups + */ + + return -ENXIO; +} + +static struct gpio_chip zevio_gpio_chip = { + .direction_input = zevio_gpio_direction_input, + .direction_output = zevio_gpio_direction_output, + .set = zevio_gpio_set, + .get = zevio_gpio_get, + .to_irq = zevio_gpio_to_irq, + .base = 0, + .owner = THIS_MODULE, + .ngpio = 32, + .of_gpio_n_cells = 2, +}; + +/* Initialization */ +static int zevio_gpio_probe(struct platform_device *pdev) +{ + struct zevio_gpio *controller; + int status, i; + + controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL); + if (!controller) + return -ENOMEM; + + /* Copy our reference */ + controller->chip.gc = zevio_gpio_chip; + controller->chip.gc.dev = &pdev->dev; + + status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip)); + if (status) { + dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status); + return status; + } + + spin_lock_init(&controller->lock); + + /* Disable interrupts, they only cause errors */ + for (i = 0; i < controller->chip.gc.ngpio; i += 8) + zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF); + + dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n"); + + return 0; +} + +static const struct of_device_id zevio_gpio_of_match[] = { + { .compatible = "lsi,zevio-gpio", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, zevio_gpio_of_match); + +static struct platform_driver zevio_gpio_driver = { + .driver = { + .name = "gpio-zevio", + .owner = THIS_MODULE, + .of_match_table = zevio_gpio_of_match, + }, + .probe = zevio_gpio_probe, +}; +module_platform_driver(zevio_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>"); +MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver"); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 716ee984311..4a987917c18 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -16,16 +16,35 @@ #include <linux/export.h> #include <linux/acpi.h> #include <linux/interrupt.h> +#include <linux/mutex.h> #include "gpiolib.h" -struct acpi_gpio_evt_pin { +struct acpi_gpio_event { struct list_head node; - acpi_handle *evt_handle; + acpi_handle handle; unsigned int pin; unsigned int irq; }; +struct acpi_gpio_connection { + struct list_head node; + struct gpio_desc *desc; +}; + +struct acpi_gpio_chip { + /* + * ACPICA requires that the first field of the context parameter + * passed to acpi_install_address_space_handler() is large enough + * to hold struct acpi_connection_info. + */ + struct acpi_connection_info conn_info; + struct list_head conns; + struct mutex conn_lock; + struct gpio_chip *chip; + struct list_head events; +}; + static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) { if (!gc->dev) @@ -60,176 +79,195 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) if (pin < 0 || pin > chip->ngpio) return ERR_PTR(-EINVAL); - return gpio_to_desc(chip->base + pin); + return gpiochip_get_desc(chip, pin); } static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) { - acpi_handle handle = data; + struct acpi_gpio_event *event = data; - acpi_evaluate_object(handle, NULL, NULL, NULL); + acpi_evaluate_object(event->handle, NULL, NULL, NULL); return IRQ_HANDLED; } static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data) { - struct acpi_gpio_evt_pin *evt_pin = data; + struct acpi_gpio_event *event = data; - acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin); + acpi_execute_simple_method(event->handle, NULL, event->pin); return IRQ_HANDLED; } -static void acpi_gpio_evt_dh(acpi_handle handle, void *data) +static void acpi_gpio_chip_dh(acpi_handle handle, void *data) { /* The address of this function is used as a key. */ } -/** - * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events - * @chip: gpio chip - * - * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are - * handled by ACPI event methods which need to be called from the GPIO - * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which - * gpio pins have acpi event methods and assigns interrupt handlers that calls - * the acpi event methods for those pins. - */ -static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) +static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, + void *context) { - struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; - struct acpi_resource *res; + struct acpi_gpio_chip *acpi_gpio = context; + struct gpio_chip *chip = acpi_gpio->chip; + struct acpi_resource_gpio *agpio; acpi_handle handle, evt_handle; - struct list_head *evt_pins = NULL; - acpi_status status; - unsigned int pin; - int irq, ret; - char ev_name[5]; + struct acpi_gpio_event *event; + irq_handler_t handler = NULL; + struct gpio_desc *desc; + unsigned long irqflags; + int ret, pin, irq; - if (!chip->dev || !chip->to_irq) - return; + if (ares->type != ACPI_RESOURCE_TYPE_GPIO) + return AE_OK; - handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; + agpio = &ares->data.gpio; + if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT) + return AE_OK; - status = acpi_get_event_resources(handle, &buf); - if (ACPI_FAILURE(status)) - return; + handle = ACPI_HANDLE(chip->dev); + pin = agpio->pin_table[0]; + + if (pin <= 255) { + char ev_name[5]; + sprintf(ev_name, "_%c%02X", + agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L', + pin); + if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle))) + handler = acpi_gpio_irq_handler; + } + if (!handler) { + if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle))) + handler = acpi_gpio_irq_handler_evt; + } + if (!handler) + return AE_BAD_PARAMETER; - status = acpi_get_handle(handle, "_EVT", &evt_handle); - if (ACPI_SUCCESS(status)) { - evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL); - if (evt_pins) { - INIT_LIST_HEAD(evt_pins); - status = acpi_attach_data(handle, acpi_gpio_evt_dh, - evt_pins); - if (ACPI_FAILURE(status)) { - kfree(evt_pins); - evt_pins = NULL; - } - } + desc = gpiochip_get_desc(chip, pin); + if (IS_ERR(desc)) { + dev_err(chip->dev, "Failed to get GPIO descriptor\n"); + return AE_ERROR; } - /* - * If a GPIO interrupt has an ACPI event handler method, or _EVT is - * present, set up an interrupt handler that calls the ACPI event - * handler. - */ - for (res = buf.pointer; - res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); - res = ACPI_NEXT_RESOURCE(res)) { - irq_handler_t handler = NULL; - void *data; - - if (res->type != ACPI_RESOURCE_TYPE_GPIO || - res->data.gpio.connection_type != - ACPI_RESOURCE_GPIO_TYPE_INT) - continue; + ret = gpiochip_request_own_desc(desc, "ACPI:Event"); + if (ret) { + dev_err(chip->dev, "Failed to request GPIO\n"); + return AE_ERROR; + } - pin = res->data.gpio.pin_table[0]; - if (pin > chip->ngpio) - continue; + gpiod_direction_input(desc); - irq = chip->to_irq(chip, pin); - if (irq < 0) - continue; + ret = gpiod_lock_as_irq(desc); + if (ret) { + dev_err(chip->dev, "Failed to lock GPIO as interrupt\n"); + goto fail_free_desc; + } - if (pin <= 255) { - acpi_handle ev_handle; + irq = gpiod_to_irq(desc); + if (irq < 0) { + dev_err(chip->dev, "Failed to translate GPIO to IRQ\n"); + goto fail_unlock_irq; + } - sprintf(ev_name, "_%c%02X", - res->data.gpio.triggering ? 'E' : 'L', pin); - status = acpi_get_handle(handle, ev_name, &ev_handle); - if (ACPI_SUCCESS(status)) { - handler = acpi_gpio_irq_handler; - data = ev_handle; - } + irqflags = IRQF_ONESHOT; + if (agpio->triggering == ACPI_LEVEL_SENSITIVE) { + if (agpio->polarity == ACPI_ACTIVE_HIGH) + irqflags |= IRQF_TRIGGER_HIGH; + else + irqflags |= IRQF_TRIGGER_LOW; + } else { + switch (agpio->polarity) { + case ACPI_ACTIVE_HIGH: + irqflags |= IRQF_TRIGGER_RISING; + break; + case ACPI_ACTIVE_LOW: + irqflags |= IRQF_TRIGGER_FALLING; + break; + default: + irqflags |= IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING; + break; } - if (!handler && evt_pins) { - struct acpi_gpio_evt_pin *evt_pin; + } - evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL); - if (!evt_pin) - continue; + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + goto fail_unlock_irq; - list_add_tail(&evt_pin->node, evt_pins); - evt_pin->evt_handle = evt_handle; - evt_pin->pin = pin; - evt_pin->irq = irq; - handler = acpi_gpio_irq_handler_evt; - data = evt_pin; - } - if (!handler) - continue; + event->handle = evt_handle; + event->irq = irq; + event->pin = pin; - /* Assume BIOS sets the triggering, so no flags */ - ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler, - 0, "GPIO-signaled-ACPI-event", - data); - if (ret) - dev_err(chip->dev, - "Failed to request IRQ %d ACPI event handler\n", - irq); + ret = request_threaded_irq(event->irq, NULL, handler, irqflags, + "ACPI:Event", event); + if (ret) { + dev_err(chip->dev, "Failed to setup interrupt handler for %d\n", + event->irq); + goto fail_free_event; } + + list_add_tail(&event->node, &acpi_gpio->events); + return AE_OK; + +fail_free_event: + kfree(event); +fail_unlock_irq: + gpiod_unlock_as_irq(desc); +fail_free_desc: + gpiochip_free_own_desc(desc); + + return AE_ERROR; } /** - * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. - * @chip: gpio chip - * - * Free interrupts associated with the _EVT method for the given GPIO chip. + * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events + * @acpi_gpio: ACPI GPIO chip * - * The remaining ACPI event interrupts associated with the chip are freed - * automatically. + * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are + * handled by ACPI event methods which need to be called from the GPIO + * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which + * gpio pins have acpi event methods and assigns interrupt handlers that calls + * the acpi event methods for those pins. */ -static void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) +static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) { - acpi_handle handle; - acpi_status status; - struct list_head *evt_pins; - struct acpi_gpio_evt_pin *evt_pin, *ep; + struct gpio_chip *chip = acpi_gpio->chip; - if (!chip->dev || !chip->to_irq) + if (!chip->to_irq) return; - handle = ACPI_HANDLE(chip->dev); - if (!handle) - return; + INIT_LIST_HEAD(&acpi_gpio->events); + acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI", + acpi_gpiochip_request_interrupt, acpi_gpio); +} - status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins); - if (ACPI_FAILURE(status)) +/** + * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts. + * @acpi_gpio: ACPI GPIO chip + * + * Free interrupts associated with GPIO ACPI event method for the given + * GPIO chip. + */ +static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) +{ + struct acpi_gpio_event *event, *ep; + struct gpio_chip *chip = acpi_gpio->chip; + + if (!chip->to_irq) 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); - } + list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { + struct gpio_desc *desc; - acpi_detach_data(handle, acpi_gpio_evt_dh); - kfree(evt_pins); + free_irq(event->irq, event); + desc = gpiochip_get_desc(chip, event->pin); + if (WARN_ON(IS_ERR(desc))) + continue; + gpiod_unlock_as_irq(desc); + gpiochip_free_own_desc(desc); + list_del(&event->node); + kfree(event); + } } struct acpi_gpio_lookup { @@ -310,12 +348,209 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index, return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT); } +static acpi_status +acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, + u32 bits, u64 *value, void *handler_context, + void *region_context) +{ + struct acpi_gpio_chip *achip = region_context; + struct gpio_chip *chip = achip->chip; + struct acpi_resource_gpio *agpio; + struct acpi_resource *ares; + acpi_status status; + bool pull_up; + int i; + + status = acpi_buffer_to_resource(achip->conn_info.connection, + achip->conn_info.length, &ares); + if (ACPI_FAILURE(status)) + return status; + + if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) { + ACPI_FREE(ares); + return AE_BAD_PARAMETER; + } + + agpio = &ares->data.gpio; + pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP; + + if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT && + function == ACPI_WRITE)) { + ACPI_FREE(ares); + return AE_BAD_PARAMETER; + } + + for (i = 0; i < agpio->pin_table_length; i++) { + unsigned pin = agpio->pin_table[i]; + struct acpi_gpio_connection *conn; + struct gpio_desc *desc; + bool found; + + desc = gpiochip_get_desc(chip, pin); + if (IS_ERR(desc)) { + status = AE_ERROR; + goto out; + } + + mutex_lock(&achip->conn_lock); + + found = false; + list_for_each_entry(conn, &achip->conns, node) { + if (conn->desc == desc) { + found = true; + break; + } + } + if (!found) { + int ret; + + ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion"); + if (ret) { + status = AE_ERROR; + mutex_unlock(&achip->conn_lock); + goto out; + } + + switch (agpio->io_restriction) { + case ACPI_IO_RESTRICT_INPUT: + gpiod_direction_input(desc); + break; + case ACPI_IO_RESTRICT_OUTPUT: + /* + * ACPI GPIO resources don't contain an + * initial value for the GPIO. Therefore we + * deduce that value from the pull field + * instead. If the pin is pulled up we + * assume default to be high, otherwise + * low. + */ + gpiod_direction_output(desc, pull_up); + break; + default: + /* + * Assume that the BIOS has configured the + * direction and pull accordingly. + */ + break; + } + + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) { + status = AE_NO_MEMORY; + gpiochip_free_own_desc(desc); + mutex_unlock(&achip->conn_lock); + goto out; + } + + conn->desc = desc; + list_add_tail(&conn->node, &achip->conns); + } + + mutex_unlock(&achip->conn_lock); + + if (function == ACPI_WRITE) + gpiod_set_raw_value_cansleep(desc, + !!((1 << i) & *value)); + else + *value |= (u64)gpiod_get_raw_value_cansleep(desc) << i; + } + +out: + ACPI_FREE(ares); + return status; +} + +static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip) +{ + struct gpio_chip *chip = achip->chip; + acpi_handle handle = ACPI_HANDLE(chip->dev); + acpi_status status; + + INIT_LIST_HEAD(&achip->conns); + mutex_init(&achip->conn_lock); + status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO, + acpi_gpio_adr_space_handler, + NULL, achip); + if (ACPI_FAILURE(status)) + dev_err(chip->dev, "Failed to install GPIO OpRegion handler\n"); +} + +static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip) +{ + struct gpio_chip *chip = achip->chip; + acpi_handle handle = ACPI_HANDLE(chip->dev); + struct acpi_gpio_connection *conn, *tmp; + acpi_status status; + + status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO, + acpi_gpio_adr_space_handler); + if (ACPI_FAILURE(status)) { + dev_err(chip->dev, "Failed to remove GPIO OpRegion handler\n"); + return; + } + + list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) { + gpiochip_free_own_desc(conn->desc); + list_del(&conn->node); + kfree(conn); + } +} + void acpi_gpiochip_add(struct gpio_chip *chip) { - acpi_gpiochip_request_interrupts(chip); + struct acpi_gpio_chip *acpi_gpio; + acpi_handle handle; + acpi_status status; + + if (!chip || !chip->dev) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL); + if (!acpi_gpio) { + dev_err(chip->dev, + "Failed to allocate memory for ACPI GPIO chip\n"); + return; + } + + acpi_gpio->chip = chip; + + status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio); + if (ACPI_FAILURE(status)) { + dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n"); + kfree(acpi_gpio); + return; + } + + acpi_gpiochip_request_interrupts(acpi_gpio); + acpi_gpiochip_request_regions(acpi_gpio); } void acpi_gpiochip_remove(struct gpio_chip *chip) { - acpi_gpiochip_free_interrupts(chip); + struct acpi_gpio_chip *acpi_gpio; + acpi_handle handle; + acpi_status status; + + if (!chip || !chip->dev) + return; + + handle = ACPI_HANDLE(chip->dev); + if (!handle) + return; + + status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio); + if (ACPI_FAILURE(status)) { + dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n"); + return; + } + + acpi_gpiochip_free_regions(acpi_gpio); + acpi_gpiochip_free_interrupts(acpi_gpio); + + acpi_detach_data(handle, acpi_gpio_chip_dh); + kfree(acpi_gpio); } diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index e0a98f581f5..af7e25c9a9a 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -12,6 +12,7 @@ */ #include <linux/device.h> +#include <linux/err.h> #include <linux/errno.h> #include <linux/module.h> #include <linux/io.h> @@ -47,7 +48,7 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) if (ret < 0) return false; - gg_data->out_gpio = gpio_to_desc(ret + gc->base); + gg_data->out_gpio = gpiochip_get_desc(gc, ret); return true; } @@ -90,11 +91,25 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, of_node_put(gg_data.gpiospec.np); pr_debug("%s exited with status %d\n", __func__, - PTR_RET(gg_data.out_gpio)); + PTR_ERR_OR_ZERO(gg_data.out_gpio)); return gg_data.out_gpio; } EXPORT_SYMBOL(of_get_named_gpiod_flags); +int of_get_named_gpio_flags(struct device_node *np, const char *list_name, + int index, enum of_gpio_flags *flags) +{ + struct gpio_desc *desc; + + desc = of_get_named_gpiod_flags(np, list_name, index, flags); + + if (IS_ERR(desc)) + return PTR_ERR(desc); + else + return desc_to_gpio(desc); +} +EXPORT_SYMBOL(of_get_named_gpio_flags); + /** * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags * @gc: pointer to the gpio_chip structure diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 50c4922fe53..2ebc9071e35 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -164,16 +164,17 @@ struct gpio_desc *gpio_to_desc(unsigned gpio) EXPORT_SYMBOL_GPL(gpio_to_desc); /** - * Convert an offset on a certain chip to a corresponding descriptor + * Get the GPIO descriptor corresponding to the given hw number for this chip. */ -static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip, - unsigned int offset) +struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, + u16 hwnum) { - if (offset >= chip->ngpio) + if (hwnum >= chip->ngpio) return ERR_PTR(-EINVAL); - return &chip->desc[offset]; + return &chip->desc[hwnum]; } +EXPORT_SYMBOL_GPL(gpiochip_get_desc); /** * Convert a GPIO descriptor to the integer namespace. @@ -350,9 +351,9 @@ static ssize_t gpio_direction_store(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else if (sysfs_streq(buf, "high")) - status = gpiod_direction_output(desc, 1); + status = gpiod_direction_output_raw(desc, 1); else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) - status = gpiod_direction_output(desc, 0); + status = gpiod_direction_output_raw(desc, 0); else if (sysfs_streq(buf, "in")) status = gpiod_direction_input(desc); else @@ -1253,6 +1254,9 @@ fail: } EXPORT_SYMBOL_GPL(gpiochip_add); +/* Forward-declaration */ +static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip); + /** * gpiochip_remove() - unregister a gpio_chip * @chip: the chip to unregister @@ -1265,11 +1269,13 @@ int gpiochip_remove(struct gpio_chip *chip) int status = 0; unsigned id; + acpi_gpiochip_remove(chip); + spin_lock_irqsave(&gpio_lock, flags); + gpiochip_irqchip_remove(chip); gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); - acpi_gpiochip_remove(chip); for (id = 0; id < chip->ngpio; id++) { if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) { @@ -1337,6 +1343,240 @@ static struct gpio_chip *find_chip_by_name(const char *name) return gpiochip_find((void *)name, gpiochip_match_name); } +#ifdef CONFIG_GPIOLIB_IRQCHIP + +/* + * The following is irqchip helper code for gpiochips. + */ + +/** + * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip + * @gpiochip: the gpiochip to add the irqchip to + * @irqchip: the irqchip to add to the gpiochip + * @parent_irq: the irq number corresponding to the parent IRQ for this + * chained irqchip + * @parent_handler: the parent interrupt handler for the accumulated IRQ + * coming out of the gpiochip + */ +void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + int parent_irq, + irq_flow_handler_t parent_handler) +{ + if (gpiochip->can_sleep) { + chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n"); + return; + } + + irq_set_chained_handler(parent_irq, parent_handler); + /* + * The parent irqchip is already using the chip_data for this + * irqchip, so our callbacks simply use the handler_data. + */ + irq_set_handler_data(parent_irq, gpiochip); +} +EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); + +/* + * 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 gpiochip_irq_lock_class; + +/** + * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip + * @d: the irqdomain used by this irqchip + * @irq: the global irq number used by this GPIO irqchip irq + * @hwirq: the local IRQ/GPIO line offset on this gpiochip + * + * This function will set up the mapping for a certain IRQ line on a + * gpiochip by assigning the gpiochip as chip data, and using the irqchip + * stored inside the gpiochip. + */ +static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct gpio_chip *chip = d->host_data; + + irq_set_chip_data(irq, chip); + irq_set_lockdep_class(irq, &gpiochip_irq_lock_class); + irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); + /* Chips that can sleep need nested thread handlers */ + if (chip->can_sleep) + irq_set_nested_thread(irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + irq_set_noprobe(irq); +#endif + /* + * No set-up of the hardware will happen if IRQ_TYPE_NONE + * is passed as default type. + */ + if (chip->irq_default_type != IRQ_TYPE_NONE) + irq_set_irq_type(irq, chip->irq_default_type); + + return 0; +} + +static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + struct gpio_chip *chip = d->host_data; + +#ifdef CONFIG_ARM + set_irq_flags(irq, 0); +#endif + if (chip->can_sleep) + irq_set_nested_thread(irq, 0); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static const struct irq_domain_ops gpiochip_domain_ops = { + .map = gpiochip_irq_map, + .unmap = gpiochip_irq_unmap, + /* Virtually all GPIO irqchips are twocell:ed */ + .xlate = irq_domain_xlate_twocell, +}; + +static int gpiochip_irq_reqres(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + if (gpio_lock_as_irq(chip, d->hwirq)) { + chip_err(chip, + "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + return -EINVAL; + } + return 0; +} + +static void gpiochip_irq_relres(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + gpio_unlock_as_irq(chip, d->hwirq); +} + +static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return irq_find_mapping(chip->irqdomain, offset); +} + +/** + * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip + * @gpiochip: the gpiochip to remove the irqchip from + * + * This is called only from gpiochip_remove() + */ +static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) +{ + unsigned int offset; + + /* Remove all IRQ mappings and delete the domain */ + if (gpiochip->irqdomain) { + for (offset = 0; offset < gpiochip->ngpio; offset++) + irq_dispose_mapping(gpiochip->irq_base + offset); + irq_domain_remove(gpiochip->irqdomain); + } + + if (gpiochip->irqchip) { + gpiochip->irqchip->irq_request_resources = NULL; + gpiochip->irqchip->irq_release_resources = NULL; + gpiochip->irqchip = NULL; + } +} + +/** + * gpiochip_irqchip_add() - adds an irqchip to a gpiochip + * @gpiochip: the gpiochip to add the irqchip to + * @irqchip: the irqchip to add to the gpiochip + * @first_irq: if not dynamically assigned, the base (first) IRQ to + * allocate gpiochip irqs from + * @handler: the irq handler to use (often a predefined irq core function) + * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE + * to have the core avoid setting up any default type in the hardware. + * + * This function closely associates a certain irqchip with a certain + * gpiochip, providing an irq domain to translate the local IRQs to + * global irqs in the gpiolib core, and making sure that the gpiochip + * is passed as chip data to all related functions. Driver callbacks + * need to use container_of() to get their local state containers back + * from the gpiochip passed as chip data. An irqdomain will be stored + * in the gpiochip that shall be used by the driver to handle IRQ number + * translation. The gpiochip will need to be initialized and registered + * before calling this function. + * + * This function will handle two cell:ed simple IRQs and assumes all + * the pins on the gpiochip can generate a unique IRQ. Everything else + * need to be open coded. + */ +int gpiochip_irqchip_add(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + unsigned int first_irq, + irq_flow_handler_t handler, + unsigned int type) +{ + struct device_node *of_node; + unsigned int offset; + unsigned irq_base = 0; + + if (!gpiochip || !irqchip) + return -EINVAL; + + if (!gpiochip->dev) { + pr_err("missing gpiochip .dev parent pointer\n"); + return -EINVAL; + } + of_node = gpiochip->dev->of_node; +#ifdef CONFIG_OF_GPIO + /* + * If the gpiochip has an assigned OF node this takes precendence + * FIXME: get rid of this and use gpiochip->dev->of_node everywhere + */ + if (gpiochip->of_node) + of_node = gpiochip->of_node; +#endif + gpiochip->irqchip = irqchip; + gpiochip->irq_handler = handler; + gpiochip->irq_default_type = type; + gpiochip->to_irq = gpiochip_to_irq; + gpiochip->irqdomain = irq_domain_add_simple(of_node, + gpiochip->ngpio, first_irq, + &gpiochip_domain_ops, gpiochip); + if (!gpiochip->irqdomain) { + gpiochip->irqchip = NULL; + return -EINVAL; + } + irqchip->irq_request_resources = gpiochip_irq_reqres; + irqchip->irq_release_resources = gpiochip_irq_relres; + + /* + * Prepare the mapping since the irqchip shall be orthogonal to + * any gpiochip calls. If the first_irq was zero, this is + * necessary to allocate descriptors for all IRQs. + */ + for (offset = 0; offset < gpiochip->ngpio; offset++) { + irq_base = irq_create_mapping(gpiochip->irqdomain, offset); + if (offset == 0) + /* + * Store the base into the gpiochip to be used when + * unmapping the irqs. + */ + gpiochip->irq_base = irq_base; + } + + return 0; +} +EXPORT_SYMBOL_GPL(gpiochip_irqchip_add); + +#else /* CONFIG_GPIOLIB_IRQCHIP */ + +static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} + +#endif /* CONFIG_GPIOLIB_IRQCHIP */ + #ifdef CONFIG_PINCTRL /** @@ -1457,26 +1697,14 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. */ -static int gpiod_request(struct gpio_desc *desc, const char *label) +static int __gpiod_request(struct gpio_desc *desc, const char *label) { - struct gpio_chip *chip; - int status = -EPROBE_DEFER; + struct gpio_chip *chip = desc->chip; + int status; unsigned long flags; - if (!desc) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - spin_lock_irqsave(&gpio_lock, flags); - chip = desc->chip; - if (chip == NULL) - goto done; - - if (!try_module_get(chip->owner)) - goto done; - /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled, for non-sleeping (SOC) GPIOs. */ @@ -1486,7 +1714,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) status = 0; } else { status = -EBUSY; - module_put(chip->owner); goto done; } @@ -1498,7 +1725,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) if (status < 0) { desc_set_label(desc, NULL); - module_put(chip->owner); clear_bit(FLAG_REQUESTED, &desc->flags); goto done; } @@ -1510,9 +1736,34 @@ static int gpiod_request(struct gpio_desc *desc, const char *label) spin_lock_irqsave(&gpio_lock, flags); } done: + spin_unlock_irqrestore(&gpio_lock, flags); + return status; +} + +static int gpiod_request(struct gpio_desc *desc, const char *label) +{ + int status = -EPROBE_DEFER; + struct gpio_chip *chip; + + if (!desc) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + + chip = desc->chip; + if (!chip) + goto done; + + if (try_module_get(chip->owner)) { + status = __gpiod_request(desc, label); + if (status < 0) + module_put(chip->owner); + } + +done: if (status) gpiod_dbg(desc, "%s: status %d\n", __func__, status); - spin_unlock_irqrestore(&gpio_lock, flags); + return status; } @@ -1522,18 +1773,14 @@ int gpio_request(unsigned gpio, const char *label) } EXPORT_SYMBOL_GPL(gpio_request); -static void gpiod_free(struct gpio_desc *desc) +static bool __gpiod_free(struct gpio_desc *desc) { + bool ret = false; unsigned long flags; struct gpio_chip *chip; might_sleep(); - if (!desc) { - WARN_ON(extra_checks); - return; - } - gpiod_unexport(desc); spin_lock_irqsave(&gpio_lock, flags); @@ -1547,15 +1794,23 @@ static void gpiod_free(struct gpio_desc *desc) spin_lock_irqsave(&gpio_lock, flags); } desc_set_label(desc, NULL); - module_put(desc->chip->owner); clear_bit(FLAG_ACTIVE_LOW, &desc->flags); clear_bit(FLAG_REQUESTED, &desc->flags); clear_bit(FLAG_OPEN_DRAIN, &desc->flags); clear_bit(FLAG_OPEN_SOURCE, &desc->flags); - } else - WARN_ON(extra_checks); + ret = true; + } spin_unlock_irqrestore(&gpio_lock, flags); + return ret; +} + +static void gpiod_free(struct gpio_desc *desc) +{ + if (desc && __gpiod_free(desc)) + module_put(desc->chip->owner); + else + WARN_ON(extra_checks); } void gpio_free(unsigned gpio) @@ -1590,7 +1845,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) if (flags & GPIOF_DIR_IN) err = gpiod_direction_input(desc); else - err = gpiod_direction_output(desc, + err = gpiod_direction_output_raw(desc, (flags & GPIOF_INIT_HIGH) ? 1 : 0); if (err) @@ -1677,6 +1932,37 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) } EXPORT_SYMBOL_GPL(gpiochip_is_requested); +/** + * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor + * @desc: GPIO descriptor to request + * @label: label for the GPIO + * + * Function allows GPIO chip drivers to request and use their own GPIO + * descriptors via gpiolib API. Difference to gpiod_request() is that this + * function will not increase reference count of the GPIO chip module. This + * allows the GPIO chip module to be unloaded as needed (we assume that the + * GPIO chip driver handles freeing the GPIOs it has requested). + */ +int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label) +{ + if (!desc || !desc->chip) + return -EINVAL; + + return __gpiod_request(desc, label); +} + +/** + * gpiochip_free_own_desc - Free GPIO requested by the chip driver + * @desc: GPIO descriptor to free + * + * Function frees the given GPIO requested previously with + * gpiochip_request_own_desc(). + */ +void gpiochip_free_own_desc(struct gpio_desc *desc) +{ + if (desc) + __gpiod_free(desc); +} /* Drivers MUST set GPIO direction before making get/set calls. In * some cases this is done in early boot, before IRQs are enabled. @@ -1756,28 +2042,13 @@ fail: } EXPORT_SYMBOL_GPL(gpiod_direction_input); -/** - * gpiod_direction_output - set the GPIO direction to input - * @desc: GPIO to set to output - * @value: initial output value of the GPIO - * - * Set the direction of the passed GPIO to output, such as gpiod_set_value() can - * be called safely on it. The initial value of the output must be specified. - * - * Return 0 in case of success, else an error code. - */ -int gpiod_direction_output(struct gpio_desc *desc, int value) +static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value) { unsigned long flags; struct gpio_chip *chip; int status = -EINVAL; int offset; - if (!desc || !desc->chip) { - pr_warn("%s: invalid GPIO\n", __func__); - return -EINVAL; - } - /* GPIOs used for IRQs shall not be set as output */ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { gpiod_err(desc, @@ -1840,6 +2111,50 @@ fail: gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); return status; } + +/** + * gpiod_direction_output_raw - set the GPIO direction to output + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as raw value on the physical line without regard for the ACTIVE_LOW status. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output_raw(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + return _gpiod_direction_output_raw(desc, value); +} +EXPORT_SYMBOL_GPL(gpiod_direction_output_raw); + +/** + * gpiod_direction_output - set the GPIO direction to output + * @desc: GPIO to set to output + * @value: initial output value of the GPIO + * + * Set the direction of the passed GPIO to output, such as gpiod_set_value() can + * be called safely on it. The initial value of the output must be specified + * as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into + * account. + * + * Return 0 in case of success, else an error code. + */ +int gpiod_direction_output(struct gpio_desc *desc, int value) +{ + if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + value = !value; + return _gpiod_direction_output_raw(desc, value); +} EXPORT_SYMBOL_GPL(gpiod_direction_output); /** @@ -1928,15 +2243,15 @@ EXPORT_SYMBOL_GPL(gpiod_is_active_low); * that the GPIO was actually requested. */ -static int _gpiod_get_raw_value(const struct gpio_desc *desc) +static bool _gpiod_get_raw_value(const struct gpio_desc *desc) { struct gpio_chip *chip; - int value; + bool value; int offset; chip = desc->chip; offset = gpio_chip_hwgpio(desc); - value = chip->get ? chip->get(chip, offset) : 0; + value = chip->get ? chip->get(chip, offset) : false; trace_gpio_value(desc_to_gpio(desc), 1, value); return value; } @@ -1992,7 +2307,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) +static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value) { int err = 0; struct gpio_chip *chip = desc->chip; @@ -2019,7 +2334,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) * @desc: gpio descriptor whose state need to be set. * @value: Non-zero for setting it HIGH otherise it will set to LOW. */ -static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) +static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value) { int err = 0; struct gpio_chip *chip = desc->chip; @@ -2041,7 +2356,7 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) __func__, err); } -static void _gpiod_set_raw_value(struct gpio_desc *desc, int value) +static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value) { struct gpio_chip *chip; @@ -2137,10 +2452,7 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq); * @gpio: the GPIO line to lock as used for IRQ * * This is used directly by GPIO drivers that want to lock down - * a certain GPIO line to be used as IRQs, for example in the - * .to_irq() callback of their gpio_chip, or in the .irq_enable() - * of its irq_chip implementation if the GPIO is known from that - * code. + * a certain GPIO line to be used for IRQs. */ int gpiod_lock_as_irq(struct gpio_desc *desc) { @@ -2161,7 +2473,7 @@ EXPORT_SYMBOL_GPL(gpiod_lock_as_irq); int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) { - return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset)); + return gpiod_lock_as_irq(gpiochip_get_desc(chip, offset)); } EXPORT_SYMBOL_GPL(gpio_lock_as_irq); @@ -2183,7 +2495,7 @@ EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq); void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) { - return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset)); + return gpiod_unlock_as_irq(gpiochip_get_desc(chip, offset)); } EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); @@ -2284,22 +2596,27 @@ void gpiod_add_lookup_table(struct gpiod_lookup_table *table) mutex_unlock(&gpio_lookup_lock); } -#ifdef CONFIG_OF static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) { + static const char *suffixes[] = { "gpios", "gpio" }; char prop_name[32]; /* 32 is max size of property name */ enum of_gpio_flags of_flags; struct gpio_desc *desc; + unsigned int i; - if (con_id) - snprintf(prop_name, 32, "%s-gpios", con_id); - else - snprintf(prop_name, 32, "gpios"); + for (i = 0; i < ARRAY_SIZE(suffixes); i++) { + if (con_id) + snprintf(prop_name, 32, "%s-%s", con_id, suffixes[i]); + else + snprintf(prop_name, 32, "%s", suffixes[i]); - desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, - &of_flags); + desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, + &of_flags); + if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER)) + break; + } if (IS_ERR(desc)) return desc; @@ -2309,14 +2626,6 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, return desc; } -#else -static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, - unsigned int idx, - enum gpio_lookup_flags *flags) -{ - return ERR_PTR(-ENODEV); -} -#endif static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, unsigned int idx, @@ -2404,7 +2713,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, return ERR_PTR(-EINVAL); } - desc = gpiochip_offset_to_desc(chip, p->chip_hwnum); + desc = gpiochip_get_desc(chip, p->chip_hwnum); *flags = p->flags; return desc; @@ -2414,7 +2723,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, } /** - * gpio_get - obtain a GPIO for a given GPIO function + * gpiod_get - obtain a GPIO for a given GPIO function * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer * @@ -2429,6 +2738,22 @@ struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id) EXPORT_SYMBOL_GPL(gpiod_get); /** + * gpiod_get_optional - obtain an optional GPIO for a given GPIO function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * + * This is equivalent to gpiod_get(), except that when no GPIO was assigned to + * the requested function it will return NULL. This is convenient for drivers + * that need to handle optional GPIOs. + */ +struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, + const char *con_id) +{ + return gpiod_get_index_optional(dev, con_id, 0); +} +EXPORT_SYMBOL_GPL(gpiod_get_optional); + +/** * gpiod_get_index - obtain a GPIO from a multi-index GPIO function * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer @@ -2491,6 +2816,33 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, EXPORT_SYMBOL_GPL(gpiod_get_index); /** + * gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO + * function + * @dev: GPIO consumer, can be NULL for system-global GPIOs + * @con_id: function within the GPIO consumer + * @index: index of the GPIO to obtain in the consumer + * + * This is equivalent to gpiod_get_index(), except that when no GPIO with the + * specified index was assigned to the requested function it will return NULL. + * This is convenient for drivers that need to handle optional GPIOs. + */ +struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, + const char *con_id, + unsigned int index) +{ + struct gpio_desc *desc; + + desc = gpiod_get_index(dev, con_id, index); + if (IS_ERR(desc)) { + if (PTR_ERR(desc) == -ENOENT) + return NULL; + } + + return desc; +} +EXPORT_SYMBOL_GPL(gpiod_get_index_optional); + +/** * gpiod_put - dispose of a GPIO descriptor * @desc: GPIO descriptor to dispose of * diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 82be586c1f9..1a4103dd38d 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -15,6 +15,8 @@ #include <linux/err.h> #include <linux/device.h> +enum of_gpio_flags; + /** * struct acpi_gpio_info - ACPI GPIO specific information * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo @@ -43,4 +45,10 @@ acpi_get_gpiod_by_index(struct device *dev, int index, } #endif +int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label); +void gpiochip_free_own_desc(struct gpio_desc *desc); + +struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, + const char *list_name, int index, enum of_gpio_flags *flags); + #endif /* GPIOLIB_H */ |
