diff options
Diffstat (limited to 'drivers/gpio')
45 files changed, 1648 insertions, 605 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9b1bcb4d0df7..23ca51ee6b28 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -204,14 +204,15 @@ config GPIO_GE_FPGA and write pin state) for GPIO implemented in a number of GE single board computers. -config GPIO_GEMINI - bool "Gemini GPIO" - depends on ARCH_GEMINI +config GPIO_FTGPIO010 + bool "Faraday FTGPIO010 GPIO" depends on OF_GPIO select GPIO_GENERIC select GPIOLIB_IRQCHIP + default (ARCH_GEMINI || ARCH_MOXART) help - Support for common GPIOs found in Cortina systems Gemini platforms. + Support for common GPIOs from the Faraday FTGPIO010 IP core, found in + Cortina systems Gemini platforms, Moxa ART and others. config GPIO_GENERIC_PLATFORM tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" @@ -308,14 +309,6 @@ config GPIO_MOCKUP tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in it. -config GPIO_MOXART - bool "MOXART GPIO support" - depends on ARCH_MOXART || COMPILE_TEST - select GPIO_GENERIC - help - Select this option to enable GPIO driver for - MOXA ART SoC devices. - config GPIO_MPC5200 def_bool y depends on PPC_MPC52xx @@ -387,6 +380,12 @@ config GPIO_RCAR help Say yes here to support GPIO on Renesas R-Car SoCs. +config GPIO_REG + bool + help + A 32-bit single register GPIO fixed in/out implementation. This + can be used to represent any register as a set of GPIO signals. + config GPIO_SPEAR_SPICS bool "ST SPEAr13xx SPI Chip Select as GPIO support" depends on PLAT_SPEAR @@ -505,7 +504,7 @@ config GPIO_XILINX config GPIO_XLP tristate "Netlogic XLP GPIO support" - depends on OF_GPIO && (CPU_XLP || ARCH_VULCAN || COMPILE_TEST) + depends on OF_GPIO && (CPU_XLP || ARCH_VULCAN || ARCH_THUNDER2 || COMPILE_TEST) select GPIOLIB_IRQCHIP help This driver provides support for GPIO interface on Netlogic XLP MIPS64 @@ -557,7 +556,7 @@ menu "Port-mapped I/O GPIO drivers" config GPIO_104_DIO_48E tristate "ACCES 104-DIO-48E GPIO support" - depends on ISA_BUS_API + depends on PC104 && ISA_BUS_API select GPIOLIB_IRQCHIP help Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, @@ -567,7 +566,7 @@ config GPIO_104_DIO_48E config GPIO_104_IDIO_16 tristate "ACCES 104-IDIO-16 GPIO support" - depends on ISA_BUS_API + depends on PC104 && ISA_BUS_API select GPIOLIB_IRQCHIP help Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16, @@ -578,7 +577,7 @@ config GPIO_104_IDIO_16 config GPIO_104_IDI_48 tristate "ACCES 104-IDI-48 GPIO support" - depends on ISA_BUS_API + depends on PC104 && ISA_BUS_API select GPIOLIB_IRQCHIP help Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A, @@ -598,7 +597,7 @@ config GPIO_F7188X config GPIO_GPIO_MM tristate "Diamond Systems GPIO-MM GPIO support" - depends on ISA_BUS_API + depends on PC104 && ISA_BUS_API help Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12. @@ -753,7 +752,7 @@ config GPIO_PCA953X 4 bits: pca9536, pca9537 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554, - pca9556, pca9557, pca9574, tca6408, xra1202 + pca9556, pca9557, pca9574, tca6408, tca9554, xra1202 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575, tca6416 @@ -845,6 +844,17 @@ config GPIO_ARIZONA help Support for GPIOs on Wolfson Arizona class devices. +config GPIO_BD9571MWV + tristate "ROHM BD9571 GPIO support" + depends on MFD_BD9571MWV + help + Support for GPIOs on ROHM BD9571 PMIC. There are two GPIOs + available on the ROHM PMIC in total, both of which can also + generate interrupts. + + This driver can also be built as a module. If so, the module + will be called gpio-bd9571mwv. + config GPIO_CRYSTAL_COVE tristate "GPIO support for Crystal Cove PMIC" depends on (X86 || COMPILE_TEST) && INTEL_SOC_PMIC diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index becb96c724fe..68b96277d9fa 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o +obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o @@ -48,8 +49,8 @@ obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o +obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o -obj-$(CONFIG_GPIO_GEMINI) += gpio-gemini.o obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o @@ -80,7 +81,6 @@ obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o -obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o @@ -99,6 +99,7 @@ obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o +obj-$(CONFIG_GPIO_REG) += gpio-reg.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 7031eea165c9..a75511d1ea5d 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -136,7 +136,7 @@ EXPORT_SYMBOL(devm_gpiod_get_index); * GPIO descriptors returned from this function are automatically disposed on * driver detach. * - * On successfull request the GPIO pin is configured in accordance with + * On successful request the GPIO pin is configured in accordance with * provided @flags. */ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev, diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index 17bd2ab4ebe2..61b50c40b87b 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -55,7 +55,7 @@ struct dio48e_gpio { unsigned char io_state[6]; unsigned char out_state[6]; unsigned char control[2]; - spinlock_t lock; + raw_spinlock_t lock; unsigned base; unsigned char irq_mask; }; @@ -78,7 +78,7 @@ static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset) unsigned long flags; unsigned control; - spin_lock_irqsave(&dio48egpio->lock, flags); + raw_spin_lock_irqsave(&dio48egpio->lock, flags); /* Check if configuring Port C */ if (io_port == 2 || io_port == 5) { @@ -103,7 +103,7 @@ static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset) control &= ~BIT(7); outb(control, control_addr); - spin_unlock_irqrestore(&dio48egpio->lock, flags); + raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); return 0; } @@ -120,7 +120,7 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned offset, unsigned long flags; unsigned control; - spin_lock_irqsave(&dio48egpio->lock, flags); + raw_spin_lock_irqsave(&dio48egpio->lock, flags); /* Check if configuring Port C */ if (io_port == 2 || io_port == 5) { @@ -153,7 +153,7 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned offset, control &= ~BIT(7); outb(control, control_addr); - spin_unlock_irqrestore(&dio48egpio->lock, flags); + raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); return 0; } @@ -167,17 +167,17 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset) unsigned long flags; unsigned port_state; - spin_lock_irqsave(&dio48egpio->lock, flags); + raw_spin_lock_irqsave(&dio48egpio->lock, flags); /* ensure that GPIO is set for input */ if (!(dio48egpio->io_state[port] & mask)) { - spin_unlock_irqrestore(&dio48egpio->lock, flags); + raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); return -EINVAL; } port_state = inb(dio48egpio->base + in_port); - spin_unlock_irqrestore(&dio48egpio->lock, flags); + raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); return !!(port_state & mask); } @@ -190,7 +190,7 @@ static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value) const unsigned out_port = (port > 2) ? port + 1 : port; unsigned long flags; - spin_lock_irqsave(&dio48egpio->lock, flags); + raw_spin_lock_irqsave(&dio48egpio->lock, flags); if (value) dio48egpio->out_state[port] |= mask; @@ -199,7 +199,7 @@ static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value) outb(dio48egpio->out_state[port], dio48egpio->base + out_port); - spin_unlock_irqrestore(&dio48egpio->lock, flags); + raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); } static void dio48e_gpio_set_multiple(struct gpio_chip *chip, @@ -225,14 +225,14 @@ static void dio48e_gpio_set_multiple(struct gpio_chip *chip, out_port = (port > 2) ? port + 1 : port; bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)]; - spin_lock_irqsave(&dio48egpio->lock, flags); + raw_spin_lock_irqsave(&dio48egpio->lock, flags); /* update output state data and set device gpio register */ dio48egpio->out_state[port] &= ~mask[BIT_WORD(i)]; dio48egpio->out_state[port] |= bitmask; outb(dio48egpio->out_state[port], dio48egpio->base + out_port); - spin_unlock_irqrestore(&dio48egpio->lock, flags); + raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); /* prepare for next gpio register set */ mask[BIT_WORD(i)] >>= gpio_reg_size; @@ -255,7 +255,7 @@ static void dio48e_irq_mask(struct irq_data *data) if (offset != 19 && offset != 43) return; - spin_lock_irqsave(&dio48egpio->lock, flags); + raw_spin_lock_irqsave(&dio48egpio->lock, flags); if (offset == 19) dio48egpio->irq_mask &= ~BIT(0); @@ -266,7 +266,7 @@ static void dio48e_irq_mask(struct irq_data *data) /* disable interrupts */ inb(dio48egpio->base + 0xB); - spin_unlock_irqrestore(&dio48egpio->lock, flags); + raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); } static void dio48e_irq_unmask(struct irq_data *data) @@ -280,7 +280,7 @@ static void dio48e_irq_unmask(struct irq_data *data) if (offset != 19 && offset != 43) return; - spin_lock_irqsave(&dio48egpio->lock, flags); + raw_spin_lock_irqsave(&dio48egpio->lock, flags); if (!dio48egpio->irq_mask) { /* enable interrupts */ @@ -293,7 +293,7 @@ static void dio48e_irq_unmask(struct irq_data *data) else dio48egpio->irq_mask |= BIT(1); - spin_unlock_irqrestore(&dio48egpio->lock, flags); + raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); } static int dio48e_irq_set_type(struct irq_data *data, unsigned flow_type) @@ -329,11 +329,11 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id) generic_handle_irq(irq_find_mapping(chip->irqdomain, 19 + gpio*24)); - spin_lock(&dio48egpio->lock); + raw_spin_lock(&dio48egpio->lock); outb(0x00, dio48egpio->base + 0xF); - spin_unlock(&dio48egpio->lock); + raw_spin_unlock(&dio48egpio->lock); return IRQ_HANDLED; } @@ -388,7 +388,7 @@ static int dio48e_probe(struct device *dev, unsigned int id) dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple; dio48egpio->base = base[id]; - spin_lock_init(&dio48egpio->lock); + raw_spin_lock_init(&dio48egpio->lock); err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); if (err) { diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index 568375a7ebc2..337c048168d8 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -51,7 +51,7 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers"); */ struct idi_48_gpio { struct gpio_chip chip; - spinlock_t lock; + raw_spinlock_t lock; spinlock_t ack_lock; unsigned char irq_mask[6]; unsigned base; @@ -112,11 +112,12 @@ static void idi_48_irq_mask(struct irq_data *data) if (!idi48gpio->irq_mask[boundary]) { idi48gpio->cos_enb &= ~BIT(boundary); - spin_lock_irqsave(&idi48gpio->lock, flags); + raw_spin_lock_irqsave(&idi48gpio->lock, flags); outb(idi48gpio->cos_enb, idi48gpio->base + 7); - spin_unlock_irqrestore(&idi48gpio->lock, flags); + raw_spin_unlock_irqrestore(&idi48gpio->lock, + flags); } return; @@ -145,11 +146,12 @@ static void idi_48_irq_unmask(struct irq_data *data) if (!prev_irq_mask) { idi48gpio->cos_enb |= BIT(boundary); - spin_lock_irqsave(&idi48gpio->lock, flags); + raw_spin_lock_irqsave(&idi48gpio->lock, flags); outb(idi48gpio->cos_enb, idi48gpio->base + 7); - spin_unlock_irqrestore(&idi48gpio->lock, flags); + raw_spin_unlock_irqrestore(&idi48gpio->lock, + flags); } return; @@ -186,11 +188,11 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) spin_lock(&idi48gpio->ack_lock); - spin_lock(&idi48gpio->lock); + raw_spin_lock(&idi48gpio->lock); cos_status = inb(idi48gpio->base + 7); - spin_unlock(&idi48gpio->lock); + raw_spin_unlock(&idi48gpio->lock); /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */ if (cos_status & BIT(6)) { @@ -256,7 +258,7 @@ static int idi_48_probe(struct device *dev, unsigned int id) idi48gpio->chip.get = idi_48_gpio_get; idi48gpio->base = base[id]; - spin_lock_init(&idi48gpio->lock); + raw_spin_lock_init(&idi48gpio->lock); spin_lock_init(&idi48gpio->ack_lock); err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio); diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index 7053cf736648..5281e1cedb01 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -50,7 +50,7 @@ MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers"); */ struct idio_16_gpio { struct gpio_chip chip; - spinlock_t lock; + raw_spinlock_t lock; unsigned long irq_mask; unsigned base; unsigned out_state; @@ -99,7 +99,7 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value) if (offset > 15) return; - spin_lock_irqsave(&idio16gpio->lock, flags); + raw_spin_lock_irqsave(&idio16gpio->lock, flags); if (value) idio16gpio->out_state |= mask; @@ -111,7 +111,7 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value) else outb(idio16gpio->out_state, idio16gpio->base); - spin_unlock_irqrestore(&idio16gpio->lock, flags); + raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } static void idio_16_gpio_set_multiple(struct gpio_chip *chip, @@ -120,7 +120,7 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip, struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); unsigned long flags; - spin_lock_irqsave(&idio16gpio->lock, flags); + raw_spin_lock_irqsave(&idio16gpio->lock, flags); idio16gpio->out_state &= ~*mask; idio16gpio->out_state |= *mask & *bits; @@ -130,7 +130,7 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip, if ((*mask >> 8) & 0xFF) outb(idio16gpio->out_state >> 8, idio16gpio->base + 4); - spin_unlock_irqrestore(&idio16gpio->lock, flags); + raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } static void idio_16_irq_ack(struct irq_data *data) @@ -147,11 +147,11 @@ static void idio_16_irq_mask(struct irq_data *data) idio16gpio->irq_mask &= ~mask; if (!idio16gpio->irq_mask) { - spin_lock_irqsave(&idio16gpio->lock, flags); + raw_spin_lock_irqsave(&idio16gpio->lock, flags); outb(0, idio16gpio->base + 2); - spin_unlock_irqrestore(&idio16gpio->lock, flags); + raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } } @@ -166,11 +166,11 @@ static void idio_16_irq_unmask(struct irq_data *data) idio16gpio->irq_mask |= mask; if (!prev_irq_mask) { - spin_lock_irqsave(&idio16gpio->lock, flags); + raw_spin_lock_irqsave(&idio16gpio->lock, flags); inb(idio16gpio->base + 2); - spin_unlock_irqrestore(&idio16gpio->lock, flags); + raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } } @@ -201,11 +201,11 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio) generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio)); - spin_lock(&idio16gpio->lock); + raw_spin_lock(&idio16gpio->lock); outb(0, idio16gpio->base + 1); - spin_unlock(&idio16gpio->lock); + raw_spin_unlock(&idio16gpio->lock); return IRQ_HANDLED; } @@ -249,7 +249,7 @@ static int idio_16_probe(struct device *dev, unsigned int id) idio16gpio->base = base[id]; idio16gpio->out_state = 0xFFFF; - spin_lock_init(&idio16gpio->lock); + raw_spin_lock_init(&idio16gpio->lock); err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); if (err) { diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 3fe6a21e05a5..17485dc20384 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -38,7 +38,7 @@ */ struct altera_gpio_chip { struct of_mm_gpio_chip mmchip; - spinlock_t gpio_lock; + raw_spinlock_t gpio_lock; int interrupt_trigger; int mapped_irq; }; @@ -53,12 +53,12 @@ static void altera_gpio_irq_unmask(struct irq_data *d) altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); mm_gc = &altera_gc->mmchip; - spin_lock_irqsave(&altera_gc->gpio_lock, flags); + raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); /* Set ALTERA_GPIO_IRQ_MASK bit to unmask */ intmask |= BIT(irqd_to_hwirq(d)); writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); - spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); + raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); } static void altera_gpio_irq_mask(struct irq_data *d) @@ -71,12 +71,12 @@ static void altera_gpio_irq_mask(struct irq_data *d) altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d)); mm_gc = &altera_gc->mmchip; - spin_lock_irqsave(&altera_gc->gpio_lock, flags); + raw_spin_lock_irqsave(&altera_gc->gpio_lock, flags); intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK); /* Clear ALTERA_GPIO_IRQ_MASK bit to mask */ intmask &= ~BIT(irqd_to_hwirq(d)); writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK); - spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); + raw_spin_unlock_irqrestore(&altera_gc->gpio_lock, flags); } /** @@ -140,14 +140,14 @@ static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value) mm_gc = to_of_mm_gpio_chip(gc); chip = gpiochip_get_data(gc); - spin_lock_irqsave(&chip->gpio_lock, flags); + raw_spin_lock_irqsave(&chip->gpio_lock, flags); data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); if (value) data_reg |= BIT(offset); else data_reg &= ~BIT(offset); writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); } static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset) @@ -160,12 +160,12 @@ static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset) mm_gc = to_of_mm_gpio_chip(gc); chip = gpiochip_get_data(gc); - spin_lock_irqsave(&chip->gpio_lock, flags); + raw_spin_lock_irqsave(&chip->gpio_lock, flags); /* Set pin as input, assumes software controlled IP */ gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); gpio_ddr &= ~BIT(offset); writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); return 0; } @@ -181,7 +181,7 @@ static int altera_gpio_direction_output(struct gpio_chip *gc, mm_gc = to_of_mm_gpio_chip(gc); chip = gpiochip_get_data(gc); - spin_lock_irqsave(&chip->gpio_lock, flags); + raw_spin_lock_irqsave(&chip->gpio_lock, flags); /* Sets the GPIO value */ data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA); if (value) @@ -194,7 +194,7 @@ static int altera_gpio_direction_output(struct gpio_chip *gc, gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR); gpio_ddr |= BIT(offset); writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR); - spin_unlock_irqrestore(&chip->gpio_lock, flags); + raw_spin_unlock_irqrestore(&chip->gpio_lock, flags); return 0; } @@ -262,7 +262,7 @@ static int altera_gpio_probe(struct platform_device *pdev) if (!altera_gc) return -ENOMEM; - spin_lock_init(&altera_gc->gpio_lock); + raw_spin_lock_init(&altera_gc->gpio_lock); if (of_property_read_u32(node, "altr,ngpio", ®)) /* By default assume maximum ngpio */ diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 1f91557717a6..cd23fd727f95 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/gpio.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/seq_file.h> #include <linux/mfd/arizona/core.h> @@ -41,13 +42,38 @@ static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset) { struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip); struct arizona *arizona = arizona_gpio->arizona; - unsigned int val; + unsigned int reg, val; int ret; - ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val); + reg = ARIZONA_GPIO1_CTRL + offset; + ret = regmap_read(arizona->regmap, reg, &val); if (ret < 0) return ret; + /* Resume to read actual registers for input pins */ + if (val & ARIZONA_GPN_DIR) { + ret = pm_runtime_get_sync(chip->parent); + if (ret < 0) { + dev_err(chip->parent, "Failed to resume: %d\n", ret); + return ret; + } + + /* Register is cached, drop it to ensure a physical read */ + ret = regcache_drop_region(arizona->regmap, reg, reg); + if (ret < 0) { + dev_err(chip->parent, "Failed to drop cache: %d\n", + ret); + return ret; + } + + ret = regmap_read(arizona->regmap, reg, &val); + if (ret < 0) + return ret; + + pm_runtime_mark_last_busy(chip->parent); + pm_runtime_put_autosuspend(chip->parent); + } + if (val & ARIZONA_GPN_LVL) return 1; else diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index fb16cc771c0d..ccea609676ee 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -9,14 +9,18 @@ * 2 of the License, or (at your option) any later version. */ -#include <linux/module.h> -#include <linux/kernel.h> +#include <asm/div64.h> +#include <linux/clk.h> +#include <linux/gpio/driver.h> +#include <linux/hashtable.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spinlock.h> -#include <linux/platform_device.h> -#include <linux/gpio/driver.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/string.h> struct aspeed_bank_props { unsigned int bank; @@ -29,59 +33,85 @@ struct aspeed_gpio_config { const struct aspeed_bank_props *props; }; +/* + * @offset_timer: Maps an offset to an @timer_users index, or zero if disabled + * @timer_users: Tracks the number of users for each timer + * + * The @timer_users has four elements but the first element is unused. This is + * to simplify accounting and indexing, as a zero value in @offset_timer + * represents disabled debouncing for the GPIO. Any other value for an element + * of @offset_timer is used as an index into @timer_users. This behaviour of + * the zero value aligns with the behaviour of zero built from the timer + * configuration registers (i.e. debouncing is disabled). + */ struct aspeed_gpio { struct gpio_chip chip; spinlock_t lock; void __iomem *base; int irq; const struct aspeed_gpio_config *config; + + u8 *offset_timer; + unsigned int timer_users[4]; + struct clk *clk; }; struct aspeed_gpio_bank { uint16_t val_regs; uint16_t irq_regs; + uint16_t debounce_regs; const char names[4][3]; }; +static const int debounce_timers[4] = { 0x00, 0x50, 0x54, 0x58 }; + static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { { .val_regs = 0x0000, .irq_regs = 0x0008, + .debounce_regs = 0x0040, .names = { "A", "B", "C", "D" }, }, { .val_regs = 0x0020, .irq_regs = 0x0028, + .debounce_regs = 0x0048, .names = { "E", "F", "G", "H" }, }, { .val_regs = 0x0070, .irq_regs = 0x0098, + .debounce_regs = 0x00b0, .names = { "I", "J", "K", "L" }, }, { .val_regs = 0x0078, .irq_regs = 0x00e8, + .debounce_regs = 0x0100, .names = { "M", "N", "O", "P" }, }, { .val_regs = 0x0080, .irq_regs = 0x0118, + .debounce_regs = 0x0130, .names = { "Q", "R", "S", "T" }, }, { .val_regs = 0x0088, .irq_regs = 0x0148, + .debounce_regs = 0x0160, .names = { "U", "V", "W", "X" }, }, { .val_regs = 0x01E0, .irq_regs = 0x0178, + .debounce_regs = 0x0190, .names = { "Y", "Z", "AA", "AB" }, }, { .val_regs = 0x01E8, .irq_regs = 0x01A8, + .debounce_regs = 0x01c0, .names = { "AC", "", "", "" }, }, }; @@ -99,6 +129,13 @@ static const struct aspeed_gpio_bank aspeed_gpio_banks[] = { #define GPIO_IRQ_TYPE2 0x0c #define GPIO_IRQ_STATUS 0x10 +#define GPIO_DEBOUNCE_SEL1 0x00 +#define GPIO_DEBOUNCE_SEL2 0x04 + +#define _GPIO_SET_DEBOUNCE(t, o, i) ((!!((t) & BIT(i))) << GPIO_OFFSET(o)) +#define GPIO_SET_DEBOUNCE1(t, o) _GPIO_SET_DEBOUNCE(t, o, 1) +#define GPIO_SET_DEBOUNCE2(t, o) _GPIO_SET_DEBOUNCE(t, o, 0) + static const struct aspeed_gpio_bank *to_bank(unsigned int offset) { unsigned int bank = GPIO_BANK(offset); @@ -144,6 +181,7 @@ static inline bool have_input(struct aspeed_gpio *gpio, unsigned int offset) } #define have_irq(g, o) have_input((g), (o)) +#define have_debounce(g, o) have_input((g), (o)) static inline bool have_output(struct aspeed_gpio *gpio, unsigned int offset) { @@ -506,6 +544,231 @@ static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset) pinctrl_free_gpio(chip->base + offset); } +static inline void __iomem *bank_debounce_reg(struct aspeed_gpio *gpio, + const struct aspeed_gpio_bank *bank, + unsigned int reg) +{ + return gpio->base + bank->debounce_regs + reg; +} + +static int usecs_to_cycles(struct aspeed_gpio *gpio, unsigned long usecs, + u32 *cycles) +{ + u64 rate; + u64 n; + u32 r; + + rate = clk_get_rate(gpio->clk); + if (!rate) + return -ENOTSUPP; + + n = rate * usecs; + r = do_div(n, 1000000); + + if (n >= U32_MAX) + return -ERANGE; + + /* At least as long as the requested time */ + *cycles = n + (!!r); + + return 0; +} + +/* Call under gpio->lock */ +static int register_allocated_timer(struct aspeed_gpio *gpio, + unsigned int offset, unsigned int timer) +{ + if (WARN(gpio->offset_timer[offset] != 0, + "Offset %d already allocated timer %d\n", + offset, gpio->offset_timer[offset])) + return -EINVAL; + + if (WARN(gpio->timer_users[timer] == UINT_MAX, + "Timer user count would overflow\n")) + return -EPERM; + + gpio->offset_timer[offset] = timer; + gpio->timer_users[timer]++; + + return 0; +} + +/* Call under gpio->lock */ +static int unregister_allocated_timer(struct aspeed_gpio *gpio, + unsigned int offset) +{ + if (WARN(gpio->offset_timer[offset] == 0, + "No timer allocated to offset %d\n", offset)) + return -EINVAL; + + if (WARN(gpio->timer_users[gpio->offset_timer[offset]] == 0, + "No users recorded for timer %d\n", + gpio->offset_timer[offset])) + return -EINVAL; + + gpio->timer_users[gpio->offset_timer[offset]]--; + gpio->offset_timer[offset] = 0; + + return 0; +} + +/* Call under gpio->lock */ +static inline bool timer_allocation_registered(struct aspeed_gpio *gpio, + unsigned int offset) +{ + return gpio->offset_timer[offset] > 0; +} + +/* Call under gpio->lock */ +static void configure_timer(struct aspeed_gpio *gpio, unsigned int offset, + unsigned int timer) +{ + const struct aspeed_gpio_bank *bank = to_bank(offset); + const u32 mask = GPIO_BIT(offset); + void __iomem *addr; + u32 val; + + addr = bank_debounce_reg(gpio, bank, GPIO_DEBOUNCE_SEL1); + val = ioread32(addr); + iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE1(timer, offset), addr); + + addr = bank_debounce_reg(gpio, bank, GPIO_DEBOUNCE_SEL2); + val = ioread32(addr); + iowrite32((val & ~mask) | GPIO_SET_DEBOUNCE2(timer, offset), addr); +} + +static int enable_debounce(struct gpio_chip *chip, unsigned int offset, + unsigned long usecs) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + u32 requested_cycles; + unsigned long flags; + int rc; + int i; + + rc = usecs_to_cycles(gpio, usecs, &requested_cycles); + if (rc < 0) { + dev_warn(chip->parent, "Failed to convert %luus to cycles at %luHz: %d\n", + usecs, clk_get_rate(gpio->clk), rc); + return rc; + } + + spin_lock_irqsave(&gpio->lock, flags); + + if (timer_allocation_registered(gpio, offset)) { + rc = unregister_allocated_timer(gpio, offset); + if (rc < 0) + goto out; + } + + /* Try to find a timer already configured for the debounce period */ + for (i = 1; i < ARRAY_SIZE(debounce_timers); i++) { + u32 cycles; + + cycles = ioread32(gpio->base + debounce_timers[i]); + if (requested_cycles == cycles) + break; + } + + if (i == ARRAY_SIZE(debounce_timers)) { + int j; + + /* + * As there are no timers configured for the requested debounce + * period, find an unused timer instead + */ + for (j = 1; j < ARRAY_SIZE(gpio->timer_users); j++) { + if (gpio->timer_users[j] == 0) + break; + } + + if (j == ARRAY_SIZE(gpio->timer_users)) { + dev_warn(chip->parent, + "Debounce timers exhausted, cannot debounce for period %luus\n", + usecs); + + rc = -EPERM; + + /* + * We already adjusted the accounting to remove @offset + * as a user of its previous timer, so also configure + * the hardware so @offset has timers disabled for + * consistency. + */ + configure_timer(gpio, offset, 0); + goto out; + } + + i = j; + + iowrite32(requested_cycles, gpio->base + debounce_timers[i]); + } + + if (WARN(i == 0, "Cannot register index of disabled timer\n")) { + rc = -EINVAL; + goto out; + } + + register_allocated_timer(gpio, offset, i); + configure_timer(gpio, offset, i); + +out: + spin_unlock_irqrestore(&gpio->lock, flags); + + return rc; +} + +static int disable_debounce(struct gpio_chip *chip, unsigned int offset) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + unsigned long flags; + int rc; + + spin_lock_irqsave(&gpio->lock, flags); + + rc = unregister_allocated_timer(gpio, offset); + if (!rc) + configure_timer(gpio, offset, 0); + + spin_unlock_irqrestore(&gpio->lock, flags); + + return rc; +} + +static int set_debounce(struct gpio_chip *chip, unsigned int offset, + unsigned long usecs) +{ + struct aspeed_gpio *gpio = gpiochip_get_data(chip); + + if (!have_debounce(gpio, offset)) + return -ENOTSUPP; + + if (usecs) + return enable_debounce(chip, offset, usecs); + + return disable_debounce(chip, offset); +} + +static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + unsigned long param = pinconf_to_config_param(config); + u32 arg = pinconf_to_config_argument(config); + + if (param == PIN_CONFIG_INPUT_DEBOUNCE) + return set_debounce(chip, offset, arg); + else if (param == PIN_CONFIG_BIAS_DISABLE || + param == PIN_CONFIG_BIAS_PULL_DOWN || + param == PIN_CONFIG_DRIVE_STRENGTH) + return pinctrl_gpio_set_config(offset, config); + else if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN || + param == PIN_CONFIG_DRIVE_OPEN_SOURCE) + /* Return -ENOTSUPP to trigger emulation, as per datasheet */ + return -ENOTSUPP; + + return -ENOTSUPP; +} + /* * Any banks not specified in a struct aspeed_bank_props array are assumed to * have the properties: @@ -565,8 +828,16 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) if (!gpio_id) return -EINVAL; + gpio->clk = of_clk_get(pdev->dev.of_node, 0); + if (IS_ERR(gpio->clk)) { + dev_warn(&pdev->dev, + "No HPLL clock phandle provided, debouncing disabled\n"); + gpio->clk = NULL; + } + gpio->config = gpio_id->data; + gpio->chip.parent = &pdev->dev; gpio->chip.ngpio = gpio->config->nr_gpios; gpio->chip.parent = &pdev->dev; gpio->chip.direction_input = aspeed_gpio_dir_in; @@ -576,6 +847,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) gpio->chip.free = aspeed_gpio_free; gpio->chip.get = aspeed_gpio_get; gpio->chip.set = aspeed_gpio_set; + gpio->chip.set_config = aspeed_gpio_set_config; gpio->chip.label = dev_name(&pdev->dev); gpio->chip.base = -1; gpio->chip.irq_need_valid_mask = true; @@ -584,6 +856,9 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev) if (rc < 0) return rc; + gpio->offset_timer = + devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL); + return aspeed_gpio_setup_irqs(gpio, pdev); } diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index dc37dbe4b46d..f33d4a5fe671 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -32,7 +32,7 @@ struct ath79_gpio_ctrl { struct gpio_chip gc; void __iomem *base; - spinlock_t lock; + raw_spinlock_t lock; unsigned long both_edges; }; @@ -74,9 +74,9 @@ static void ath79_gpio_irq_unmask(struct irq_data *data) u32 mask = BIT(irqd_to_hwirq(data)); unsigned long flags; - spin_lock_irqsave(&ctrl->lock, flags); + raw_spin_lock_irqsave(&ctrl->lock, flags); ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask); - spin_unlock_irqrestore(&ctrl->lock, flags); + raw_spin_unlock_irqrestore(&ctrl->lock, flags); } static void ath79_gpio_irq_mask(struct irq_data *data) @@ -85,9 +85,9 @@ static void ath79_gpio_irq_mask(struct irq_data *data) u32 mask = BIT(irqd_to_hwirq(data)); unsigned long flags; - spin_lock_irqsave(&ctrl->lock, flags); + raw_spin_lock_irqsave(&ctrl->lock, flags); ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0); - spin_unlock_irqrestore(&ctrl->lock, flags); + raw_spin_unlock_irqrestore(&ctrl->lock, flags); } static void ath79_gpio_irq_enable(struct irq_data *data) @@ -96,10 +96,10 @@ static void ath79_gpio_irq_enable(struct irq_data *data) u32 mask = BIT(irqd_to_hwirq(data)); unsigned long flags; - spin_lock_irqsave(&ctrl->lock, flags); + raw_spin_lock_irqsave(&ctrl->lock, flags); ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, mask); ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, mask); - spin_unlock_irqrestore(&ctrl->lock, flags); + raw_spin_unlock_irqrestore(&ctrl->lock, flags); } static void ath79_gpio_irq_disable(struct irq_data *data) @@ -108,10 +108,10 @@ static void ath79_gpio_irq_disable(struct irq_data *data) u32 mask = BIT(irqd_to_hwirq(data)); unsigned long flags; - spin_lock_irqsave(&ctrl->lock, flags); + raw_spin_lock_irqsave(&ctrl->lock, flags); ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_MASK, mask, 0); ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, 0); - spin_unlock_irqrestore(&ctrl->lock, flags); + raw_spin_unlock_irqrestore(&ctrl->lock, flags); } static int ath79_gpio_irq_set_type(struct irq_data *data, @@ -140,7 +140,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data, return -EINVAL; } - spin_lock_irqsave(&ctrl->lock, flags); + raw_spin_lock_irqsave(&ctrl->lock, flags); if (flow_type == IRQ_TYPE_EDGE_BOTH) { ctrl->both_edges |= mask; @@ -165,7 +165,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data, ath79_gpio_update_bits( ctrl, AR71XX_GPIO_REG_INT_ENABLE, mask, mask); - spin_unlock_irqrestore(&ctrl->lock, flags); + raw_spin_unlock_irqrestore(&ctrl->lock, flags); return 0; } @@ -191,7 +191,7 @@ static void ath79_gpio_irq_handler(struct irq_desc *desc) chained_irq_enter(irqchip, desc); - spin_lock_irqsave(&ctrl->lock, flags); + raw_spin_lock_irqsave(&ctrl->lock, flags); pending = ath79_gpio_read(ctrl, AR71XX_GPIO_REG_INT_PENDING); @@ -203,7 +203,7 @@ static void ath79_gpio_irq_handler(struct irq_desc *desc) both_edges, ~state); } - spin_unlock_irqrestore(&ctrl->lock, flags); + raw_spin_unlock_irqrestore(&ctrl->lock, flags); if (pending) { for_each_set_bit(irq, &pending, gc->ngpio) @@ -262,7 +262,7 @@ static int ath79_gpio_probe(struct platform_device *pdev) if (!ctrl->base) return -ENOMEM; - spin_lock_init(&ctrl->lock); + raw_spin_lock_init(&ctrl->lock); err = bgpio_init(&ctrl->gc, &pdev->dev, 4, ctrl->base + AR71XX_GPIO_REG_IN, ctrl->base + AR71XX_GPIO_REG_SET, diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 41d0ac142580..dfcf56ee3c61 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -67,7 +67,7 @@ struct bcm_kona_gpio { void __iomem *reg_base; int num_bank; - spinlock_t lock; + raw_spinlock_t lock; struct gpio_chip gpio_chip; struct irq_domain *irq_domain; struct bcm_kona_gpio_bank *banks; @@ -95,13 +95,13 @@ static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio, unsigned long flags; int bank_id = GPIO_BANK(gpio); - spin_lock_irqsave(&kona_gpio->lock, flags); + raw_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); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); } static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio, @@ -111,13 +111,13 @@ static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio, unsigned long flags; int bank_id = GPIO_BANK(gpio); - spin_lock_irqsave(&kona_gpio->lock, flags); + raw_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); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); } static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio) @@ -141,7 +141,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) kona_gpio = gpiochip_get_data(chip); reg_base = kona_gpio->reg_base; - spin_lock_irqsave(&kona_gpio->lock, flags); + raw_spin_lock_irqsave(&kona_gpio->lock, flags); /* this function only applies to output pin */ if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN) @@ -154,7 +154,7 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) writel(val, reg_base + reg_offset); out: - spin_unlock_irqrestore(&kona_gpio->lock, flags); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); } static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) @@ -168,7 +168,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) kona_gpio = gpiochip_get_data(chip); reg_base = kona_gpio->reg_base; - spin_lock_irqsave(&kona_gpio->lock, flags); + raw_spin_lock_irqsave(&kona_gpio->lock, flags); if (bcm_kona_gpio_get_dir(chip, gpio) == GPIOF_DIR_IN) reg_offset = GPIO_IN_STATUS(bank_id); @@ -178,7 +178,7 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio) /* read the GPIO bank status */ val = readl(reg_base + reg_offset); - spin_unlock_irqrestore(&kona_gpio->lock, flags); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); /* return the specified bit status */ return !!(val & BIT(bit)); @@ -208,14 +208,14 @@ static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) kona_gpio = gpiochip_get_data(chip); reg_base = kona_gpio->reg_base; - spin_lock_irqsave(&kona_gpio->lock, flags); + raw_spin_lock_irqsave(&kona_gpio->lock, flags); 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)); - spin_unlock_irqrestore(&kona_gpio->lock, flags); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; } @@ -232,7 +232,7 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, kona_gpio = gpiochip_get_data(chip); reg_base = kona_gpio->reg_base; - spin_lock_irqsave(&kona_gpio->lock, flags); + raw_spin_lock_irqsave(&kona_gpio->lock, flags); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_IOTR_MASK; @@ -244,7 +244,7 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip, val |= BIT(bit); writel(val, reg_base + reg_offset); - spin_unlock_irqrestore(&kona_gpio->lock, flags); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; } @@ -288,7 +288,7 @@ 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); + raw_spin_lock_irqsave(&kona_gpio->lock, flags); val = readl(reg_base + GPIO_CONTROL(gpio)); val &= ~GPIO_GPCTR0_DBR_MASK; @@ -303,7 +303,7 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio, writel(val, reg_base + GPIO_CONTROL(gpio)); - spin_unlock_irqrestore(&kona_gpio->lock, flags); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; } @@ -347,13 +347,13 @@ 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); + raw_spin_lock_irqsave(&kona_gpio->lock, flags); val = readl(reg_base + GPIO_INT_STATUS(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_STATUS(bank_id)); - spin_unlock_irqrestore(&kona_gpio->lock, flags); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); } static void bcm_kona_gpio_irq_mask(struct irq_data *d) @@ -368,13 +368,13 @@ 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); + raw_spin_lock_irqsave(&kona_gpio->lock, flags); val = readl(reg_base + GPIO_INT_MASK(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MASK(bank_id)); - spin_unlock_irqrestore(&kona_gpio->lock, flags); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); } static void bcm_kona_gpio_irq_unmask(struct irq_data *d) @@ -389,13 +389,13 @@ 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); + raw_spin_lock_irqsave(&kona_gpio->lock, flags); val = readl(reg_base + GPIO_INT_MSKCLR(bank_id)); val |= BIT(bit); writel(val, reg_base + GPIO_INT_MSKCLR(bank_id)); - spin_unlock_irqrestore(&kona_gpio->lock, flags); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); } static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) @@ -431,14 +431,14 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - spin_lock_irqsave(&kona_gpio->lock, flags); + raw_spin_lock_irqsave(&kona_gpio->lock, flags); 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)); - spin_unlock_irqrestore(&kona_gpio->lock, flags); + raw_spin_unlock_irqrestore(&kona_gpio->lock, flags); return 0; } @@ -655,7 +655,7 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev) bank); } - spin_lock_init(&kona_gpio->lock); + raw_spin_lock_init(&kona_gpio->lock); return 0; diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c new file mode 100644 index 000000000000..5224a946e8ab --- /dev/null +++ b/drivers/gpio/gpio-bd9571mwv.c @@ -0,0 +1,144 @@ +/* + * ROHM BD9571MWV-M GPIO driver + * + * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether expressed or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2 for more details. + * + * Based on the TPS65086 driver + * + * NOTE: Interrupts are not supported yet. + */ + +#include <linux/gpio/driver.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <linux/mfd/bd9571mwv.h> + +struct bd9571mwv_gpio { + struct gpio_chip chip; + struct bd9571mwv *bd; +}; + +static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); + int ret, val; + + ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val); + if (ret < 0) + return ret; + + return val & BIT(offset); +} + +static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); + + regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR, + BIT(offset), 0); + + return 0; +} + +static int bd9571mwv_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); + + /* Set the initial value */ + regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT, + BIT(offset), value ? BIT(offset) : 0); + regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR, + BIT(offset), BIT(offset)); + + return 0; +} + +static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); + int ret, val; + + ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_IN, &val); + if (ret < 0) + return ret; + + return val & BIT(offset); +} + +static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); + + regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT, + BIT(offset), value ? BIT(offset) : 0); +} + +static const struct gpio_chip template_chip = { + .label = "bd9571mwv-gpio", + .owner = THIS_MODULE, + .get_direction = bd9571mwv_gpio_get_direction, + .direction_input = bd9571mwv_gpio_direction_input, + .direction_output = bd9571mwv_gpio_direction_output, + .get = bd9571mwv_gpio_get, + .set = bd9571mwv_gpio_set, + .base = -1, + .ngpio = 2, + .can_sleep = true, +}; + +static int bd9571mwv_gpio_probe(struct platform_device *pdev) +{ + struct bd9571mwv_gpio *gpio; + int ret; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + platform_set_drvdata(pdev, gpio); + + gpio->bd = dev_get_drvdata(pdev->dev.parent); + gpio->chip = template_chip; + gpio->chip.parent = gpio->bd->dev; + + ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + return ret; + } + + return 0; +} + +static const struct platform_device_id bd9571mwv_gpio_id_table[] = { + { "bd9571mwv-gpio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table); + +static struct platform_driver bd9571mwv_gpio_driver = { + .driver = { + .name = "bd9571mwv-gpio", + }, + .probe = bd9571mwv_gpio_probe, + .id_table = bd9571mwv_gpio_id_table, +}; +module_platform_driver(bd9571mwv_gpio_driver); + +MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>"); +MODULE_DESCRIPTION("BD9571MWV GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 72f49d1e110d..ac173575d3f6 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -483,7 +483,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) clk_prepare_enable(clk); if (!pdata->gpio_unbanked) { - irq = irq_alloc_descs(-1, 0, ngpio, 0); + irq = devm_irq_alloc_descs(dev, -1, 0, ngpio, 0); if (irq < 0) { dev_err(dev, "Couldn't allocate IRQ numbers\n"); return irq; diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 9c15ee4ef4e9..f051c4552af5 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -21,6 +21,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/property.h> @@ -55,6 +56,14 @@ #define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR) #define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR) +#define GPIO_REG_OFFSET_V2 1 + +#define GPIO_INTMASK_V2 0x44 +#define GPIO_INTTYPE_LEVEL_V2 0x34 +#define GPIO_INT_POLARITY_V2 0x38 +#define GPIO_INTSTATUS_V2 0x3c +#define GPIO_PORTA_EOI_V2 0x40 + struct dwapb_gpio; #ifdef CONFIG_PM_SLEEP @@ -87,14 +96,41 @@ struct dwapb_gpio { struct dwapb_gpio_port *ports; unsigned int nr_ports; struct irq_domain *domain; + unsigned int flags; }; +static inline u32 gpio_reg_v2_convert(unsigned int offset) +{ + switch (offset) { + case GPIO_INTMASK: + return GPIO_INTMASK_V2; + case GPIO_INTTYPE_LEVEL: + return GPIO_INTTYPE_LEVEL_V2; + case GPIO_INT_POLARITY: + return GPIO_INT_POLARITY_V2; + case GPIO_INTSTATUS: + return GPIO_INTSTATUS_V2; + case GPIO_PORTA_EOI: + return GPIO_PORTA_EOI_V2; + } + + return offset; +} + +static inline u32 gpio_reg_convert(struct dwapb_gpio *gpio, unsigned int offset) +{ + if (gpio->flags & GPIO_REG_OFFSET_V2) + return gpio_reg_v2_convert(offset); + + return offset; +} + static inline u32 dwapb_read(struct dwapb_gpio *gpio, unsigned int offset) { struct gpio_chip *gc = &gpio->ports[0].gc; void __iomem *reg_base = gpio->regs; - return gc->read_reg(reg_base + offset); + return gc->read_reg(reg_base + gpio_reg_convert(gpio, offset)); } static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset, @@ -103,7 +139,7 @@ static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset, struct gpio_chip *gc = &gpio->ports[0].gc; void __iomem *reg_base = gpio->regs; - gc->write_reg(reg_base + offset, val); + gc->write_reg(reg_base + gpio_reg_convert(gpio, offset), val); } static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset) @@ -128,7 +164,7 @@ static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs) static u32 dwapb_do_irq(struct dwapb_gpio *gpio) { - u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS); + u32 irq_status = dwapb_read(gpio, GPIO_INTSTATUS); u32 ret = irq_status; while (irq_status) { @@ -348,8 +384,8 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, 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->regs.ack = gpio_reg_convert(gpio, GPIO_PORTA_EOI); + ct->regs.mask = gpio_reg_convert(gpio, GPIO_INTMASK); ct->type = IRQ_TYPE_LEVEL_MASK; } @@ -532,6 +568,21 @@ dwapb_gpio_get_pdata(struct device *dev) return pdata; } +static const struct of_device_id dwapb_of_match[] = { + { .compatible = "snps,dw-apb-gpio", .data = (void *)0}, + { .compatible = "apm,xgene-gpio-v2", .data = (void *)GPIO_REG_OFFSET_V2}, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dwapb_of_match); + +static const struct acpi_device_id dwapb_acpi_match[] = { + {"HISI0181", 0}, + {"APMC0D07", 0}, + {"APMC0D81", GPIO_REG_OFFSET_V2}, + { } +}; +MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match); + static int dwapb_gpio_probe(struct platform_device *pdev) { unsigned int i; @@ -567,6 +618,25 @@ static int dwapb_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpio->regs)) return PTR_ERR(gpio->regs); + gpio->flags = 0; + if (dev->of_node) { + const struct of_device_id *of_devid; + + of_devid = of_match_device(dwapb_of_match, dev); + if (of_devid) { + if (of_devid->data) + gpio->flags = (uintptr_t)of_devid->data; + } + } else if (has_acpi_companion(dev)) { + const struct acpi_device_id *acpi_id; + + acpi_id = acpi_match_device(dwapb_acpi_match, dev); + if (acpi_id) { + if (acpi_id->driver_data) + gpio->flags = acpi_id->driver_data; + } + } + for (i = 0; i < gpio->nr_ports; i++) { err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i); if (err) @@ -593,19 +663,6 @@ static int dwapb_gpio_remove(struct platform_device *pdev) 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 const struct acpi_device_id dwapb_acpi_match[] = { - {"HISI0181", 0}, - {"APMC0D07", 0}, - { } -}; -MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match); - #ifdef CONFIG_PM_SLEEP static int dwapb_gpio_suspend(struct device *dev) { diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index a254d5b07b94..14c6aac26780 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -54,7 +54,7 @@ struct etraxfs_gpio_info; struct etraxfs_gpio_block { - spinlock_t lock; + raw_spinlock_t lock; u32 mask; u32 cfg; u32 pins; @@ -233,10 +233,10 @@ static void etraxfs_gpio_irq_mask(struct irq_data *d) struct etraxfs_gpio_block *block = chip->block; unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); - spin_lock(&block->lock); + raw_spin_lock(&block->lock); block->mask &= ~BIT(grpirq); writel(block->mask, block->regs + block->info->rw_intr_mask); - spin_unlock(&block->lock); + raw_spin_unlock(&block->lock); } static void etraxfs_gpio_irq_unmask(struct irq_data *d) @@ -246,10 +246,10 @@ static void etraxfs_gpio_irq_unmask(struct irq_data *d) struct etraxfs_gpio_block *block = chip->block; unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); - spin_lock(&block->lock); + raw_spin_lock(&block->lock); block->mask |= BIT(grpirq); writel(block->mask, block->regs + block->info->rw_intr_mask); - spin_unlock(&block->lock); + raw_spin_unlock(&block->lock); } static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type) @@ -280,11 +280,11 @@ static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type) return -EINVAL; } - spin_lock(&block->lock); + raw_spin_lock(&block->lock); block->cfg &= ~(0x7 << (grpirq * 3)); block->cfg |= (cfg << (grpirq * 3)); writel(block->cfg, block->regs + block->info->rw_intr_cfg); - spin_unlock(&block->lock); + raw_spin_unlock(&block->lock); return 0; } @@ -297,7 +297,7 @@ static int etraxfs_gpio_irq_request_resources(struct irq_data *d) unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); int ret = -EBUSY; - spin_lock(&block->lock); + raw_spin_lock(&block->lock); if (block->group[grpirq]) goto out; @@ -316,7 +316,7 @@ static int etraxfs_gpio_irq_request_resources(struct irq_data *d) } out: - spin_unlock(&block->lock); + raw_spin_unlock(&block->lock); return ret; } @@ -327,10 +327,10 @@ static void etraxfs_gpio_irq_release_resources(struct irq_data *d) struct etraxfs_gpio_block *block = chip->block; unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); - spin_lock(&block->lock); + raw_spin_lock(&block->lock); block->group[grpirq] = 0; gpiochip_unlock_as_irq(&chip->gc, d->hwirq); - spin_unlock(&block->lock); + raw_spin_unlock(&block->lock); } static struct irq_chip etraxfs_gpio_irq_chip = { @@ -391,7 +391,7 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) if (!block) return -ENOMEM; - spin_lock_init(&block->lock); + raw_spin_lock_init(&block->lock); block->regs = regs; block->info = info; diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c index 05c8946d6446..081076771217 100644 --- a/drivers/gpio/gpio-exar.c +++ b/drivers/gpio/gpio-exar.c @@ -59,17 +59,6 @@ static int exar_set_direction(struct gpio_chip *chip, int direction, return 0; } -static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, - int value) -{ - return exar_set_direction(chip, 0, offset); -} - -static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) -{ - return exar_set_direction(chip, 1, offset); -} - static int exar_get(struct gpio_chip *chip, unsigned int reg) { struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); @@ -116,6 +105,18 @@ static void exar_set_value(struct gpio_chip *chip, unsigned int offset, exar_update(chip, addr, value, offset % 8); } +static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, + int value) +{ + exar_set_value(chip, offset, value); + return exar_set_direction(chip, 0, offset); +} + +static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + return exar_set_direction(chip, 1, offset); +} + static int gpio_exar_probe(struct platform_device *pdev) { struct pci_dev *pcidev = platform_get_drvdata(pdev); diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 56bd76c33767..13350c9d7f5e 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -37,14 +37,16 @@ #define SIO_F71869A_ID 0x1007 /* F71869A chipset ID */ #define SIO_F71882_ID 0x0541 /* F71882 chipset ID */ #define SIO_F71889_ID 0x0909 /* F71889 chipset ID */ +#define SIO_F71889A_ID 0x1005 /* F71889A chipset ID */ #define SIO_F81866_ID 0x1010 /* F81866 chipset ID */ -enum chips { f71869, f71869a, f71882fg, f71889f, f81866 }; +enum chips { f71869, f71869a, f71882fg, f71889a, f71889f, f81866 }; static const char * const f7188x_names[] = { "f71869", "f71869a", "f71882fg", + "f71889a", "f71889f", "f81866", }; @@ -187,6 +189,17 @@ static struct f7188x_gpio_bank f71882_gpio_bank[] = { F7188X_GPIO_BANK(40, 4, 0xB0), }; +static struct f7188x_gpio_bank f71889a_gpio_bank[] = { + F7188X_GPIO_BANK(0, 7, 0xF0), + F7188X_GPIO_BANK(10, 7, 0xE0), + F7188X_GPIO_BANK(20, 8, 0xD0), + F7188X_GPIO_BANK(30, 8, 0xC0), + F7188X_GPIO_BANK(40, 8, 0xB0), + F7188X_GPIO_BANK(50, 5, 0xA0), + F7188X_GPIO_BANK(60, 8, 0x90), + F7188X_GPIO_BANK(70, 8, 0x80), +}; + static struct f7188x_gpio_bank f71889_gpio_bank[] = { F7188X_GPIO_BANK(0, 7, 0xF0), F7188X_GPIO_BANK(10, 7, 0xE0), @@ -382,6 +395,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev) data->nr_bank = ARRAY_SIZE(f71882_gpio_bank); data->bank = f71882_gpio_bank; break; + case f71889a: + data->nr_bank = ARRAY_SIZE(f71889a_gpio_bank); + data->bank = f71889a_gpio_bank; + break; case f71889f: data->nr_bank = ARRAY_SIZE(f71889_gpio_bank); data->bank = f71889_gpio_bank; @@ -443,6 +460,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) case SIO_F71882_ID: sio->type = f71882fg; break; + case SIO_F71889A_ID: + sio->type = f71889a; + break; case SIO_F71889_ID: sio->type = f71889f; break; @@ -538,6 +558,6 @@ static void __exit f7188x_gpio_exit(void) } module_exit(f7188x_gpio_exit); -MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG, F71889F and F81866"); +MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG, F71889A, F71889F and F81866"); MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-gemini.c b/drivers/gpio/gpio-ftgpio010.c index 962485163b7f..e9386f8b67f5 100644 --- a/drivers/gpio/gpio-gemini.c +++ b/drivers/gpio/gpio-ftgpio010.c @@ -1,5 +1,5 @@ /* - * Gemini gpiochip and interrupt routines + * Faraday Technolog FTGPIO010 gpiochip and interrupt routines * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> * * Based on arch/arm/mach-gemini/gpio.c: @@ -35,28 +35,28 @@ #define GPIO_DEBOUNCE_PRESCALE 0x44 /** - * struct gemini_gpio - Gemini GPIO state container + * struct ftgpio_gpio - Gemini GPIO state container * @dev: containing device for this instance * @gc: gpiochip for this instance */ -struct gemini_gpio { +struct ftgpio_gpio { struct device *dev; struct gpio_chip gc; void __iomem *base; }; -static void gemini_gpio_ack_irq(struct irq_data *d) +static void ftgpio_gpio_ack_irq(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct gemini_gpio *g = gpiochip_get_data(gc); + struct ftgpio_gpio *g = gpiochip_get_data(gc); writel(BIT(irqd_to_hwirq(d)), g->base + GPIO_INT_CLR); } -static void gemini_gpio_mask_irq(struct irq_data *d) +static void ftgpio_gpio_mask_irq(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct gemini_gpio *g = gpiochip_get_data(gc); + struct ftgpio_gpio *g = gpiochip_get_data(gc); u32 val; val = readl(g->base + GPIO_INT_EN); @@ -64,10 +64,10 @@ static void gemini_gpio_mask_irq(struct irq_data *d) writel(val, g->base + GPIO_INT_EN); } -static void gemini_gpio_unmask_irq(struct irq_data *d) +static void ftgpio_gpio_unmask_irq(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct gemini_gpio *g = gpiochip_get_data(gc); + struct ftgpio_gpio *g = gpiochip_get_data(gc); u32 val; val = readl(g->base + GPIO_INT_EN); @@ -75,10 +75,10 @@ static void gemini_gpio_unmask_irq(struct irq_data *d) writel(val, g->base + GPIO_INT_EN); } -static int gemini_gpio_set_irq_type(struct irq_data *d, unsigned int type) +static int ftgpio_gpio_set_irq_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct gemini_gpio *g = gpiochip_get_data(gc); + struct ftgpio_gpio *g = gpiochip_get_data(gc); u32 mask = BIT(irqd_to_hwirq(d)); u32 reg_both, reg_level, reg_type; @@ -123,23 +123,23 @@ static int gemini_gpio_set_irq_type(struct irq_data *d, unsigned int type) writel(reg_level, g->base + GPIO_INT_LEVEL); writel(reg_both, g->base + GPIO_INT_BOTH_EDGE); - gemini_gpio_ack_irq(d); + ftgpio_gpio_ack_irq(d); return 0; } -static struct irq_chip gemini_gpio_irqchip = { - .name = "GPIO", - .irq_ack = gemini_gpio_ack_irq, - .irq_mask = gemini_gpio_mask_irq, - .irq_unmask = gemini_gpio_unmask_irq, - .irq_set_type = gemini_gpio_set_irq_type, +static struct irq_chip ftgpio_gpio_irqchip = { + .name = "FTGPIO010", + .irq_ack = ftgpio_gpio_ack_irq, + .irq_mask = ftgpio_gpio_mask_irq, + .irq_unmask = ftgpio_gpio_unmask_irq, + .irq_set_type = ftgpio_gpio_set_irq_type, }; -static void gemini_gpio_irq_handler(struct irq_desc *desc) +static void ftgpio_gpio_irq_handler(struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct gemini_gpio *g = gpiochip_get_data(gc); + struct ftgpio_gpio *g = gpiochip_get_data(gc); struct irq_chip *irqchip = irq_desc_get_chip(desc); int offset; unsigned long stat; @@ -155,11 +155,11 @@ static void gemini_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(irqchip, desc); } -static int gemini_gpio_probe(struct platform_device *pdev) +static int ftgpio_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; - struct gemini_gpio *g; + struct ftgpio_gpio *g; int irq; int ret; @@ -189,7 +189,7 @@ static int gemini_gpio_probe(struct platform_device *pdev) dev_err(dev, "unable to init generic GPIO\n"); return ret; } - g->gc.label = "Gemini"; + g->gc.label = "FTGPIO010"; g->gc.base = -1; g->gc.parent = dev; g->gc.owner = THIS_MODULE; @@ -204,33 +204,39 @@ static int gemini_gpio_probe(struct platform_device *pdev) writel(0x0, g->base + GPIO_INT_MASK); writel(~0x0, g->base + GPIO_INT_CLR); - ret = gpiochip_irqchip_add(&g->gc, &gemini_gpio_irqchip, + ret = gpiochip_irqchip_add(&g->gc, &ftgpio_gpio_irqchip, 0, handle_bad_irq, IRQ_TYPE_NONE); if (ret) { dev_info(dev, "could not add irqchip\n"); return ret; } - gpiochip_set_chained_irqchip(&g->gc, &gemini_gpio_irqchip, - irq, gemini_gpio_irq_handler); + gpiochip_set_chained_irqchip(&g->gc, &ftgpio_gpio_irqchip, + irq, ftgpio_gpio_irq_handler); - dev_info(dev, "Gemini GPIO @%p registered\n", g->base); + dev_info(dev, "FTGPIO010 @%p registered\n", g->base); return 0; } -static const struct of_device_id gemini_gpio_of_match[] = { +static const struct of_device_id ftgpio_gpio_of_match[] = { { .compatible = "cortina,gemini-gpio", }, + { + .compatible = "moxa,moxart-gpio", + }, + { + .compatible = "faraday,ftgpio010", + }, {}, }; -static struct platform_driver gemini_gpio_driver = { +static struct platform_driver ftgpio_gpio_driver = { .driver = { - .name = "gemini-gpio", - .of_match_table = of_match_ptr(gemini_gpio_of_match), + .name = "ftgpio010-gpio", + .of_match_table = of_match_ptr(ftgpio_gpio_of_match), }, - .probe = gemini_gpio_probe, + .probe = ftgpio_gpio_probe, }; -builtin_platform_driver(gemini_gpio_driver); +builtin_platform_driver(ftgpio_gpio_driver); diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index f40088d268c1..9dbdc3672f5e 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -166,7 +166,7 @@ static int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - return (readl(gpdr) & BIT(offset % 32)) ? GPIOF_DIR_OUT : GPIOF_DIR_IN; + return !(readl(gpdr) & BIT(offset % 32)); } static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 796a5a4bc4f5..78896a869fd9 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -459,41 +459,31 @@ static int ioh_gpio_probe(struct pci_dev *pdev, chip = chip_save; for (j = 0; j < 8; j++, chip++) { - irq_base = irq_alloc_descs(-1, IOH_IRQ_BASE, num_ports[j], - NUMA_NO_NODE); + irq_base = devm_irq_alloc_descs(&pdev->dev, -1, IOH_IRQ_BASE, + num_ports[j], NUMA_NO_NODE); if (irq_base < 0) { dev_warn(&pdev->dev, "ml_ioh_gpio: Failed to get IRQ base num\n"); - chip->irq_base = -1; ret = irq_base; - goto err_irq_alloc_descs; + goto err_gpiochip_add; } chip->irq_base = irq_base; ioh_gpio_alloc_generic_chip(chip, irq_base, num_ports[j]); } chip = chip_save; - ret = request_irq(pdev->irq, ioh_gpio_handler, - IRQF_SHARED, KBUILD_MODNAME, chip); + ret = devm_request_irq(&pdev->dev, pdev->irq, ioh_gpio_handler, + IRQF_SHARED, KBUILD_MODNAME, chip); if (ret != 0) { dev_err(&pdev->dev, "%s request_irq failed\n", __func__); - goto err_request_irq; + goto err_gpiochip_add; } pci_set_drvdata(pdev, chip); return 0; -err_request_irq: - chip = chip_save; -err_irq_alloc_descs: - while (--j >= 0) { - chip--; - irq_free_descs(chip->irq_base, num_ports[j]); - } - - chip = chip_save; err_gpiochip_add: while (--i >= 0) { chip--; @@ -524,12 +514,8 @@ static void ioh_gpio_remove(struct pci_dev *pdev) chip_save = chip; - free_irq(pdev->irq, chip); - - for (i = 0; i < 8; i++, chip++) { - irq_free_descs(chip->irq_base, num_ports[i]); + for (i = 0; i < 8; i++, chip++) gpiochip_remove(&chip->gpio); - } chip = chip_save; pci_iounmap(pdev, chip->base); diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index d7d03ad052d0..f7da40e46c55 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -575,6 +575,7 @@ static void __iomem *bgpio_map(struct platform_device *pdev, static const struct of_device_id bgpio_of_match[] = { { .compatible = "brcm,bcm6345-gpio" }, { .compatible = "wd,mbl-gpio" }, + { .compatible = "ni,169445-nand-gpio" }, { } }; MODULE_DEVICE_TABLE(of, bgpio_of_match); diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index d99338689213..c6dadac70593 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -169,7 +169,7 @@ static int gpio_mockup_irqchip_setup(struct device *dev, struct gpio_chip *gc = &chip->gc; int irq_base, i; - irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0); + irq_base = devm_irq_alloc_descs(dev, -1, 0, gc->ngpio, 0); if (irq_base < 0) return irq_base; @@ -372,25 +372,11 @@ static int gpio_mockup_probe(struct platform_device *pdev) return 0; } -static int gpio_mockup_remove(struct platform_device *pdev) -{ - struct gpio_mockup_chip *chips; - int i; - - chips = platform_get_drvdata(pdev); - - for (i = 0; i < gpio_mockup_params_nr >> 1; i++) - irq_free_descs(chips[i].gc.irq_base, chips[i].gc.ngpio); - - return 0; -} - static struct platform_driver gpio_mockup_driver = { .driver = { .name = GPIO_MOCKUP_NAME, }, .probe = gpio_mockup_probe, - .remove = gpio_mockup_remove, }; static struct platform_device *pdev; diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c deleted file mode 100644 index d58d38906ba6..000000000000 --- a/drivers/gpio/gpio-moxart.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * MOXA ART SoCs GPIO driver. - * - * Copyright (C) 2013 Jonas Jensen - * - * Jonas Jensen <jonas.jensen@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 - * warranty of any kind, whether express or implied. - */ - -#include <linux/err.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/of_address.h> -#include <linux/of_gpio.h> -#include <linux/pinctrl/consumer.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/bitops.h> -#include <linux/gpio/driver.h> - -#define GPIO_DATA_OUT 0x00 -#define GPIO_DATA_IN 0x04 -#define GPIO_PIN_DIRECTION 0x08 - -static int moxart_gpio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *res; - struct gpio_chip *gc; - void __iomem *base; - int ret; - - gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); - if (!gc) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - ret = bgpio_init(gc, dev, 4, base + GPIO_DATA_IN, - base + GPIO_DATA_OUT, NULL, - base + GPIO_PIN_DIRECTION, NULL, - BGPIOF_READ_OUTPUT_REG_SET); - if (ret) { - dev_err(&pdev->dev, "bgpio_init failed\n"); - return ret; - } - - gc->label = "moxart-gpio"; - gc->request = gpiochip_generic_request; - gc->free = gpiochip_generic_free; - gc->base = 0; - gc->owner = THIS_MODULE; - - ret = devm_gpiochip_add_data(dev, gc, NULL); - if (ret) { - dev_err(dev, "%s: gpiochip_add failed\n", - dev->of_node->full_name); - return ret; - } - - return ret; -} - -static const struct of_device_id moxart_gpio_match[] = { - { .compatible = "moxa,moxart-gpio" }, - { } -}; - -static struct platform_driver moxart_gpio_driver = { - .driver = { - .name = "moxart-gpio", - .of_match_table = moxart_gpio_match, - }, - .probe = moxart_gpio_probe, -}; -builtin_platform_driver(moxart_gpio_driver); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index a649556ac3ca..19a92efabbef 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -42,29 +42,44 @@ #include <linux/io.h> #include <linux/of_irq.h> #include <linux/of_device.h> +#include <linux/pwm.h> #include <linux/clk.h> #include <linux/pinctrl/consumer.h> #include <linux/irqchip/chained_irq.h> +#include <linux/platform_device.h> +#include <linux/bitops.h> + +#include "gpiolib.h" /* * GPIO unit register offsets. */ -#define GPIO_OUT_OFF 0x0000 -#define GPIO_IO_CONF_OFF 0x0004 -#define GPIO_BLINK_EN_OFF 0x0008 -#define GPIO_IN_POL_OFF 0x000c -#define GPIO_DATA_IN_OFF 0x0010 -#define GPIO_EDGE_CAUSE_OFF 0x0014 -#define GPIO_EDGE_MASK_OFF 0x0018 -#define GPIO_LEVEL_MASK_OFF 0x001c +#define GPIO_OUT_OFF 0x0000 +#define GPIO_IO_CONF_OFF 0x0004 +#define GPIO_BLINK_EN_OFF 0x0008 +#define GPIO_IN_POL_OFF 0x000c +#define GPIO_DATA_IN_OFF 0x0010 +#define GPIO_EDGE_CAUSE_OFF 0x0014 +#define GPIO_EDGE_MASK_OFF 0x0018 +#define GPIO_LEVEL_MASK_OFF 0x001c +#define GPIO_BLINK_CNT_SELECT_OFF 0x0020 + +/* + * PWM register offsets. + */ +#define PWM_BLINK_ON_DURATION_OFF 0x0 +#define PWM_BLINK_OFF_DURATION_OFF 0x4 + /* The MV78200 has per-CPU registers for edge mask and level mask */ #define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) #define GPIO_LEVEL_MASK_MV78200_OFF(cpu) ((cpu) ? 0x34 : 0x1C) -/* The Armada XP has per-CPU registers for interrupt cause, interrupt +/* + * The Armada XP has per-CPU registers for interrupt cause, interrupt * mask and interrupt level mask. Those are relative to the - * percpu_membase. */ + * percpu_membase. + */ #define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4) #define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4) #define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4) @@ -75,6 +90,20 @@ #define MVEBU_MAX_GPIO_PER_BANK 32 +struct mvebu_pwm { + void __iomem *membase; + unsigned long clk_rate; + struct gpio_desc *gpiod; + struct pwm_chip chip; + spinlock_t lock; + struct mvebu_gpio_chip *mvchip; + + /* Used to preserve GPIO/PWM registers across suspend/resume */ + u32 blink_select; + u32 blink_on_duration; + u32 blink_off_duration; +}; + struct mvebu_gpio_chip { struct gpio_chip chip; spinlock_t lock; @@ -84,48 +113,55 @@ struct mvebu_gpio_chip { struct irq_domain *domain; int soc_variant; + /* Used for PWM support */ + struct clk *clk; + struct mvebu_pwm *mvpwm; + /* Used to preserve GPIO registers across suspend/resume */ - u32 out_reg; - u32 io_conf_reg; - u32 blink_en_reg; - u32 in_pol_reg; - u32 edge_mask_regs[4]; - u32 level_mask_regs[4]; + u32 out_reg; + u32 io_conf_reg; + u32 blink_en_reg; + u32 in_pol_reg; + u32 edge_mask_regs[4]; + u32 level_mask_regs[4]; }; /* * Functions returning addresses of individual registers for a given * GPIO controller. */ -static inline void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip) +static void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_OUT_OFF; } -static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) +static void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_BLINK_EN_OFF; } -static inline void __iomem * -mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) +static void __iomem *mvebu_gpioreg_blink_counter_select(struct mvebu_gpio_chip + *mvchip) +{ + return mvchip->membase + GPIO_BLINK_CNT_SELECT_OFF; +} + +static void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_IO_CONF_OFF; } -static inline void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip) +static void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_IN_POL_OFF; } -static inline void __iomem * -mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip) +static void __iomem *mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_DATA_IN_OFF; } -static inline void __iomem * -mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) +static void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) { int cpu; @@ -142,8 +178,7 @@ mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip) } } -static inline void __iomem * -mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip) +static void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip) { int cpu; @@ -182,10 +217,23 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) } /* - * Functions implementing the gpio_chip methods + * Functions returning addresses of individual registers for a given + * PWM controller. */ +static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm) +{ + return mvpwm->membase + PWM_BLINK_ON_DURATION_OFF; +} + +static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm) +{ + return mvpwm->membase + PWM_BLINK_OFF_DURATION_OFF; +} -static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value) +/* + * Functions implementing the gpio_chip methods + */ +static void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); unsigned long flags; @@ -194,19 +242,19 @@ static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value) spin_lock_irqsave(&mvchip->lock, flags); u = readl_relaxed(mvebu_gpioreg_out(mvchip)); if (value) - u |= 1 << pin; + u |= BIT(pin); else - u &= ~(1 << pin); + u &= ~BIT(pin); writel_relaxed(u, mvebu_gpioreg_out(mvchip)); spin_unlock_irqrestore(&mvchip->lock, flags); } -static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin) +static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); u32 u; - if (readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin)) { + if (readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & BIT(pin)) { u = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) ^ readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); } else { @@ -216,7 +264,8 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin) return (u >> pin) & 1; } -static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value) +static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned int pin, + int value) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); unsigned long flags; @@ -225,36 +274,38 @@ static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value) spin_lock_irqsave(&mvchip->lock, flags); u = readl_relaxed(mvebu_gpioreg_blink(mvchip)); if (value) - u |= 1 << pin; + u |= BIT(pin); else - u &= ~(1 << pin); + u &= ~BIT(pin); writel_relaxed(u, mvebu_gpioreg_blink(mvchip)); spin_unlock_irqrestore(&mvchip->lock, flags); } -static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin) +static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); unsigned long flags; int ret; u32 u; - /* Check with the pinctrl driver whether this pin is usable as - * an input GPIO */ + /* + * Check with the pinctrl driver whether this pin is usable as + * an input GPIO + */ ret = pinctrl_gpio_direction_input(chip->base + pin); if (ret) return ret; spin_lock_irqsave(&mvchip->lock, flags); u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)); - u |= 1 << pin; + u |= BIT(pin); writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip)); spin_unlock_irqrestore(&mvchip->lock, flags); return 0; } -static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin, +static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, int value) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); @@ -262,8 +313,10 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int ret; u32 u; - /* Check with the pinctrl driver whether this pin is usable as - * an output GPIO */ + /* + * Check with the pinctrl driver whether this pin is usable as + * an output GPIO + */ ret = pinctrl_gpio_direction_output(chip->base + pin); if (ret) return ret; @@ -273,16 +326,17 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin, spin_lock_irqsave(&mvchip->lock, flags); u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)); - u &= ~(1 << pin); + u &= ~BIT(pin); writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip)); spin_unlock_irqrestore(&mvchip->lock, flags); return 0; } -static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned pin) +static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin) { struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); + return irq_create_mapping(mvchip->domain, pin); } @@ -389,7 +443,7 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin = d->hwirq; - u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin); + u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & BIT(pin); if (!u) return -EINVAL; @@ -409,13 +463,13 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); - u &= ~(1 << pin); + u &= ~BIT(pin); writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip)); break; case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_LEVEL_LOW: u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); - u |= 1 << pin; + u |= BIT(pin); writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip)); break; case IRQ_TYPE_EDGE_BOTH: { @@ -428,10 +482,10 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) * set initial polarity based on current input level */ u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); - if (v & (1 << pin)) - u |= 1 << pin; /* falling */ + if (v & BIT(pin)) + u |= BIT(pin); /* falling */ else - u &= ~(1 << pin); /* rising */ + u &= ~BIT(pin); /* rising */ writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip)); break; } @@ -461,7 +515,7 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) irq = irq_find_mapping(mvchip->domain, i); - if (!(cause & (1 << i))) + if (!(cause & BIT(i))) continue; type = irq_get_trigger_type(irq); @@ -470,7 +524,7 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) u32 polarity; polarity = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)); - polarity ^= 1 << i; + polarity ^= BIT(i); writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip)); } @@ -480,6 +534,246 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } +/* + * Functions implementing the pwm_chip methods + */ +static struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct mvebu_pwm, chip); +} + +static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); + struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; + struct gpio_desc *desc; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&mvpwm->lock, flags); + + if (mvpwm->gpiod) { + ret = -EBUSY; + } else { + desc = gpio_to_desc(mvchip->chip.base + pwm->hwpwm); + if (!desc) { + ret = -ENODEV; + goto out; + } + + ret = gpiod_request(desc, "mvebu-pwm"); + if (ret) + goto out; + + ret = gpiod_direction_output(desc, 0); + if (ret) { + gpiod_free(desc); + goto out; + } + + mvpwm->gpiod = desc; + } +out: + spin_unlock_irqrestore(&mvpwm->lock, flags); + return ret; +} + +static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); + unsigned long flags; + + spin_lock_irqsave(&mvpwm->lock, flags); + gpiod_free(mvpwm->gpiod); + mvpwm->gpiod = NULL; + spin_unlock_irqrestore(&mvpwm->lock, flags); +} + +static void mvebu_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { + + struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); + struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; + unsigned long long val; + unsigned long flags; + u32 u; + + spin_lock_irqsave(&mvpwm->lock, flags); + + val = (unsigned long long) + readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm)); + val *= NSEC_PER_SEC; + do_div(val, mvpwm->clk_rate); + if (val > UINT_MAX) + state->duty_cycle = UINT_MAX; + else if (val) + state->duty_cycle = val; + else + state->duty_cycle = 1; + + val = (unsigned long long) + readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm)); + val *= NSEC_PER_SEC; + do_div(val, mvpwm->clk_rate); + if (val < state->duty_cycle) { + state->period = 1; + } else { + val -= state->duty_cycle; + if (val > UINT_MAX) + state->period = UINT_MAX; + else if (val) + state->period = val; + else + state->period = 1; + } + + u = readl_relaxed(mvebu_gpioreg_blink(mvchip)); + if (u) + state->enabled = true; + else + state->enabled = false; + + spin_unlock_irqrestore(&mvpwm->lock, flags); +} + +static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); + struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; + unsigned long long val; + unsigned long flags; + unsigned int on, off; + + val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle; + do_div(val, NSEC_PER_SEC); + if (val > UINT_MAX) + return -EINVAL; + if (val) + on = val; + else + on = 1; + + val = (unsigned long long) mvpwm->clk_rate * + (state->period - state->duty_cycle); + do_div(val, NSEC_PER_SEC); + if (val > UINT_MAX) + return -EINVAL; + if (val) + off = val; + else + off = 1; + + spin_lock_irqsave(&mvpwm->lock, flags); + + writel_relaxed(on, mvebu_pwmreg_blink_on_duration(mvpwm)); + writel_relaxed(off, mvebu_pwmreg_blink_off_duration(mvpwm)); + if (state->enabled) + mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1); + else + mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 0); + + spin_unlock_irqrestore(&mvpwm->lock, flags); + + return 0; +} + +static const struct pwm_ops mvebu_pwm_ops = { + .request = mvebu_pwm_request, + .free = mvebu_pwm_free, + .get_state = mvebu_pwm_get_state, + .apply = mvebu_pwm_apply, + .owner = THIS_MODULE, +}; + +static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip) +{ + struct mvebu_pwm *mvpwm = mvchip->mvpwm; + + mvpwm->blink_select = + readl_relaxed(mvebu_gpioreg_blink_counter_select(mvchip)); + mvpwm->blink_on_duration = + readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm)); + mvpwm->blink_off_duration = + readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm)); +} + +static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip) +{ + struct mvebu_pwm *mvpwm = mvchip->mvpwm; + + writel_relaxed(mvpwm->blink_select, + mvebu_gpioreg_blink_counter_select(mvchip)); + writel_relaxed(mvpwm->blink_on_duration, + mvebu_pwmreg_blink_on_duration(mvpwm)); + writel_relaxed(mvpwm->blink_off_duration, + mvebu_pwmreg_blink_off_duration(mvpwm)); +} + +static int mvebu_pwm_probe(struct platform_device *pdev, + struct mvebu_gpio_chip *mvchip, + int id) +{ + struct device *dev = &pdev->dev; + struct mvebu_pwm *mvpwm; + struct resource *res; + u32 set; + + if (!of_device_is_compatible(mvchip->chip.of_node, + "marvell,armada-370-xp-gpio")) + return 0; + + if (IS_ERR(mvchip->clk)) + return PTR_ERR(mvchip->clk); + + /* + * There are only two sets of PWM configuration registers for + * all the GPIO lines on those SoCs which this driver reserves + * for the first two GPIO chips. So if the resource is missing + * we can't treat it as an error. + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"); + if (!res) + return 0; + + /* + * Use set A for lines of GPIO chip with id 0, B for GPIO chip + * with id 1. Don't allow further GPIO chips to be used for PWM. + */ + if (id == 0) + set = 0; + else if (id == 1) + set = U32_MAX; + else + return -EINVAL; + writel_relaxed(0, mvebu_gpioreg_blink_counter_select(mvchip)); + + mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL); + if (!mvpwm) + return -ENOMEM; + mvchip->mvpwm = mvpwm; + mvpwm->mvchip = mvchip; + + mvpwm->membase = devm_ioremap_resource(dev, res); + if (IS_ERR(mvpwm->membase)) + return PTR_ERR(mvpwm->membase); + + mvpwm->clk_rate = clk_get_rate(mvchip->clk); + if (!mvpwm->clk_rate) { + dev_err(dev, "failed to get clock rate\n"); + return -EINVAL; + } + + mvpwm->chip.dev = dev; + mvpwm->chip.ops = &mvebu_pwm_ops; + mvpwm->chip.npwm = mvchip->chip.ngpio; + + spin_lock_init(&mvpwm->lock); + + return pwmchip_add(&mvpwm->chip); +} + #ifdef CONFIG_DEBUG_FS #include <linux/seq_file.h> @@ -507,7 +801,7 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) if (!label) continue; - msk = 1 << i; + msk = BIT(i); is_out = !(io_conf & msk); seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label); @@ -551,6 +845,10 @@ static const struct of_device_id mvebu_gpio_of_match[] = { .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, }, { + .compatible = "marvell,armada-370-xp-gpio", + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, + }, + { /* sentinel */ }, }; @@ -596,6 +894,9 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) BUG(); } + if (IS_ENABLED(CONFIG_PWM)) + mvebu_pwm_suspend(mvchip); + return 0; } @@ -639,6 +940,9 @@ static int mvebu_gpio_resume(struct platform_device *pdev) BUG(); } + if (IS_ENABLED(CONFIG_PWM)) + mvebu_pwm_resume(mvchip); + return 0; } @@ -650,7 +954,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) struct resource *res; struct irq_chip_generic *gc; struct irq_chip_type *ct; - struct clk *clk; unsigned int ngpios; bool have_irqs; int soc_variant; @@ -684,10 +987,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev) return id; } - clk = devm_clk_get(&pdev->dev, NULL); + mvchip->clk = devm_clk_get(&pdev->dev, NULL); /* Not all SoCs require a clock.*/ - if (!IS_ERR(clk)) - clk_prepare_enable(clk); + if (!IS_ERR(mvchip->clk)) + clk_prepare_enable(mvchip->clk); mvchip->soc_variant = soc_variant; mvchip->chip.label = dev_name(&pdev->dev); @@ -712,8 +1015,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev) if (IS_ERR(mvchip->membase)) return PTR_ERR(mvchip->membase); - /* The Armada XP has a second range of registers for the - * per-CPU registers */ + /* + * The Armada XP has a second range of registers for the + * per-CPU registers + */ if (soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) { res = platform_get_resource(pdev, IORESOURCE_MEM, 1); mvchip->percpu_membase = devm_ioremap_resource(&pdev->dev, @@ -780,7 +1085,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) goto err_domain; } - /* NOTE: The common accessors cannot be used because of the percpu + /* + * NOTE: The common accessors cannot be used because of the percpu * access to the mask registers */ gc = irq_get_domain_generic_chip(mvchip->domain, 0); @@ -801,7 +1107,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) ct->handler = handle_edge_irq; ct->chip.name = mvchip->chip.label; - /* Setup the interrupt handlers. Each chip can have up to 4 + /* + * Setup the interrupt handlers. Each chip can have up to 4 * interrupt handlers, with each handler dealing with 8 GPIO * pins. */ @@ -814,6 +1121,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip); } + /* Armada 370/XP has simple PWM support for GPIO lines */ + if (IS_ENABLED(CONFIG_PWM)) + return mvebu_pwm_probe(pdev, mvchip, id); + return 0; err_domain: diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index c1a1e00b8cb0..3abea3f0b307 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -471,7 +471,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) if (err) goto out_bgio; - irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); + irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id()); if (irq_base < 0) { err = irq_base; goto out_bgio; @@ -481,7 +481,7 @@ static int mxc_gpio_probe(struct platform_device *pdev) &irq_domain_simple_ops, NULL); if (!port->domain) { err = -ENODEV; - goto out_irqdesc_free; + goto out_bgio; } /* gpio-mxc can be a generic irq chip */ @@ -495,8 +495,6 @@ static int mxc_gpio_probe(struct platform_device *pdev) out_irqdomain_remove: irq_domain_remove(port->domain); -out_irqdesc_free: - irq_free_descs(irq_base, 32); out_bgio: dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err); return err; diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 2292742eac8f..6ae583f36733 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -328,7 +328,7 @@ static int mxs_gpio_probe(struct platform_device *pdev) /* clear address has to be used to clear IRQSTAT bits */ writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); - irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); + irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 32, numa_node_id()); if (irq_base < 0) { err = irq_base; goto out_iounmap; @@ -338,7 +338,7 @@ static int mxs_gpio_probe(struct platform_device *pdev) &irq_domain_simple_ops, NULL); if (!port->domain) { err = -ENODEV; - goto out_irqdesc_free; + goto out_iounmap; } /* gpio-mxs can be a generic irq chip */ @@ -370,8 +370,6 @@ static int mxs_gpio_probe(struct platform_device *pdev) out_irqdomain_remove: irq_domain_remove(port->domain); -out_irqdesc_free: - irq_free_descs(irq_base, 32); out_iounmap: iounmap(port->base); return err; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index efc85a279d54..f8c550de6c72 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -208,9 +208,11 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) * OMAP's debounce time is in 31us steps * <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 * so we need to convert and round up to the closest unit. + * + * Return: 0 on success, negative error otherwise. */ -static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, - unsigned debounce) +static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, + unsigned debounce) { void __iomem *reg; u32 val; @@ -218,11 +220,12 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, bool enable = !!debounce; if (!bank->dbck_flag) - return; + return -ENOTSUPP; if (enable) { debounce = DIV_ROUND_UP(debounce, 31) - 1; - debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK; + if ((debounce & OMAP4_GPIO_DEBOUNCINGTIME_MASK) != debounce) + return -EINVAL; } l = BIT(offset); @@ -255,6 +258,8 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, bank->context.debounce = debounce; bank->context.debounce_en = val; } + + return 0; } /** @@ -964,14 +969,20 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, { struct gpio_bank *bank; unsigned long flags; + int ret; bank = gpiochip_get_data(chip); raw_spin_lock_irqsave(&bank->lock, flags); - omap2_set_gpio_debounce(bank, offset, debounce); + ret = omap2_set_gpio_debounce(bank, offset, debounce); raw_spin_unlock_irqrestore(&bank->lock, flags); - return 0; + if (ret) + dev_info(chip->parent, + "Could not set line %u debounce to %u microseconds (%d)", + offset, debounce, ret); + + return ret; } static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset, @@ -1085,7 +1096,8 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) * 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); + irq_base = devm_irq_alloc_descs(bank->chip.parent, + -1, 0, bank->width, 0); if (irq_base < 0) { dev_err(bank->chip.parent, "Couldn't allocate IRQ numbers\n"); return -ENODEV; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index d44232aadb6c..4c9e21300a26 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -11,18 +11,19 @@ * the Free Software Foundation; version 2 of the License. */ -#include <linux/module.h> -#include <linux/init.h> +#include <linux/acpi.h> #include <linux/gpio.h> #include <linux/gpio/consumer.h> -#include <linux/interrupt.h> #include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of_platform.h> #include <linux/platform_data/pca953x.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> + #include <asm/unaligned.h> -#include <linux/of_platform.h> -#include <linux/acpi.h> -#include <linux/regulator/consumer.h> #define PCA953X_INPUT 0 #define PCA953X_OUTPUT 1 @@ -81,6 +82,7 @@ static const struct i2c_device_id pca953x_id[] = { { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, { "tca6424", 24 | PCA953X_TYPE | PCA_INT, }, { "tca9539", 16 | PCA953X_TYPE | PCA_INT, }, + { "tca9554", 8 | PCA953X_TYPE | PCA_INT, }, { "xra1202", 8 | PCA953X_TYPE }, { } }; @@ -363,6 +365,21 @@ exit: mutex_unlock(&chip->i2c_lock); } +static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off) +{ + struct pca953x_chip *chip = gpiochip_get_data(gc); + u32 reg_val; + int ret; + + mutex_lock(&chip->i2c_lock); + ret = pca953x_read_single(chip, chip->regs->direction, ®_val, off); + mutex_unlock(&chip->i2c_lock); + if (ret < 0) + return ret; + + return !!(reg_val & (1u << (off % BANK_SZ))); +} + static void pca953x_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, unsigned long *bits) { @@ -408,6 +425,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->direction_output = pca953x_gpio_direction_output; gc->get = pca953x_gpio_get_value; gc->set = pca953x_gpio_set_value; + gc->get_direction = pca953x_gpio_get_direction; gc->set_multiple = pca953x_gpio_set_multiple; gc->can_sleep = true; @@ -760,7 +778,13 @@ static int pca953x_probe(struct i2c_client *client, chip->gpio_start = -1; irq_base = 0; - /* See if we need to de-assert a reset pin */ + /* + * See if we need to de-assert a reset pin. + * + * There is no known ACPI-enabled platforms that are + * using "reset" GPIO. Otherwise any of those platform + * must use _DSD method with corresponding property. + */ reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(reset_gpio)) diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 895af42a4513..8ddf9302ce3b 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -46,7 +46,6 @@ static const struct i2c_device_id pcf857x_id[] = { { "pca9675", 16 }, { "max7328", 8 }, { "max7329", 8 }, - { "tca9554", 8 }, { } }; MODULE_DEVICE_TABLE(i2c, pcf857x_id); @@ -66,7 +65,6 @@ static const struct of_device_id pcf857x_of_table[] = { { .compatible = "nxp,pca9675" }, { .compatible = "maxim,max7328" }, { .compatible = "maxim,max7329" }, - { .compatible = "ti,tca9554" }, { } }; MODULE_DEVICE_TABLE(of, pcf857x_of_table); diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 7c7135da5d4a..71bc6da11337 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -403,7 +403,8 @@ static int pch_gpio_probe(struct pci_dev *pdev, goto err_gpiochip_add; } - irq_base = irq_alloc_descs(-1, 0, gpio_pins[chip->ioh], NUMA_NO_NODE); + irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, + gpio_pins[chip->ioh], NUMA_NO_NODE); if (irq_base < 0) { dev_warn(&pdev->dev, "PCH gpio: Failed to get IRQ base num\n"); chip->irq_base = -1; @@ -416,8 +417,8 @@ static int pch_gpio_probe(struct pci_dev *pdev, iowrite32(msk, &chip->reg->imask); iowrite32(msk, &chip->reg->ien); - ret = request_irq(pdev->irq, pch_gpio_handler, - IRQF_SHARED, KBUILD_MODNAME, chip); + ret = devm_request_irq(&pdev->dev, pdev->irq, pch_gpio_handler, + IRQF_SHARED, KBUILD_MODNAME, chip); if (ret != 0) { dev_err(&pdev->dev, "%s request_irq failed\n", __func__); @@ -430,7 +431,6 @@ end: return 0; err_request_irq: - irq_free_descs(irq_base, gpio_pins[chip->ioh]); gpiochip_remove(&chip->gpio); err_gpiochip_add: @@ -452,12 +452,6 @@ static void pch_gpio_remove(struct pci_dev *pdev) { struct pch_gpio *chip = pci_get_drvdata(pdev); - if (chip->irq_base != -1) { - free_irq(pdev->irq, chip); - - irq_free_descs(chip->irq_base, gpio_pins[chip->ioh]); - } - gpiochip_remove(&chip->gpio); pci_iounmap(pdev, chip->base); pci_release_regions(pdev); diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c index 269ab628634b..7de4f6a2cb49 100644 --- a/drivers/gpio/gpio-pci-idio-16.c +++ b/drivers/gpio/gpio-pci-idio-16.c @@ -59,7 +59,7 @@ struct idio_16_gpio_reg { */ struct idio_16_gpio { struct gpio_chip chip; - spinlock_t lock; + raw_spinlock_t lock; struct idio_16_gpio_reg __iomem *reg; unsigned long irq_mask; }; @@ -121,7 +121,7 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, } else base = &idio16gpio->reg->out0_7; - spin_lock_irqsave(&idio16gpio->lock, flags); + raw_spin_lock_irqsave(&idio16gpio->lock, flags); if (value) out_state = ioread8(base) | mask; @@ -130,7 +130,7 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, iowrite8(out_state, base); - spin_unlock_irqrestore(&idio16gpio->lock, flags); + raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } static void idio_16_gpio_set_multiple(struct gpio_chip *chip, @@ -140,7 +140,7 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip, unsigned long flags; unsigned int out_state; - spin_lock_irqsave(&idio16gpio->lock, flags); + raw_spin_lock_irqsave(&idio16gpio->lock, flags); /* process output lines 0-7 */ if (*mask & 0xFF) { @@ -160,7 +160,7 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip, iowrite8(out_state, &idio16gpio->reg->out8_15); } - spin_unlock_irqrestore(&idio16gpio->lock, flags); + raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } static void idio_16_irq_ack(struct irq_data *data) @@ -177,11 +177,11 @@ static void idio_16_irq_mask(struct irq_data *data) idio16gpio->irq_mask &= ~mask; if (!idio16gpio->irq_mask) { - spin_lock_irqsave(&idio16gpio->lock, flags); + raw_spin_lock_irqsave(&idio16gpio->lock, flags); iowrite8(0, &idio16gpio->reg->irq_ctl); - spin_unlock_irqrestore(&idio16gpio->lock, flags); + raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } } @@ -196,11 +196,11 @@ static void idio_16_irq_unmask(struct irq_data *data) idio16gpio->irq_mask |= mask; if (!prev_irq_mask) { - spin_lock_irqsave(&idio16gpio->lock, flags); + raw_spin_lock_irqsave(&idio16gpio->lock, flags); ioread8(&idio16gpio->reg->irq_ctl); - spin_unlock_irqrestore(&idio16gpio->lock, flags); + raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } } @@ -229,11 +229,11 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) struct gpio_chip *const chip = &idio16gpio->chip; int gpio; - spin_lock(&idio16gpio->lock); + raw_spin_lock(&idio16gpio->lock); irq_status = ioread8(&idio16gpio->reg->irq_status); - spin_unlock(&idio16gpio->lock); + raw_spin_unlock(&idio16gpio->lock); /* Make sure our device generated IRQ */ if (!(irq_status & 0x3) || !(irq_status & 0x4)) @@ -242,12 +242,12 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio) generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio)); - spin_lock(&idio16gpio->lock); + raw_spin_lock(&idio16gpio->lock); /* Clear interrupt */ iowrite8(0, &idio16gpio->reg->in0_7); - spin_unlock(&idio16gpio->lock); + raw_spin_unlock(&idio16gpio->lock); return IRQ_HANDLED; } @@ -302,7 +302,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) idio16gpio->chip.set = idio_16_gpio_set; idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; - spin_lock_init(&idio16gpio->lock); + raw_spin_lock_init(&idio16gpio->lock); err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); if (err) { diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 0a6bfd2b06e5..3d3d6b6645a7 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -50,7 +50,7 @@ struct pl061_context_save_regs { #endif struct pl061 { - spinlock_t lock; + raw_spinlock_t lock; void __iomem *base; struct gpio_chip gc; @@ -74,11 +74,11 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) unsigned long flags; unsigned char gpiodir; - spin_lock_irqsave(&pl061->lock, flags); + raw_spin_lock_irqsave(&pl061->lock, flags); gpiodir = readb(pl061->base + GPIODIR); gpiodir &= ~(BIT(offset)); writeb(gpiodir, pl061->base + GPIODIR); - spin_unlock_irqrestore(&pl061->lock, flags); + raw_spin_unlock_irqrestore(&pl061->lock, flags); return 0; } @@ -90,7 +90,7 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, unsigned long flags; unsigned char gpiodir; - spin_lock_irqsave(&pl061->lock, flags); + raw_spin_lock_irqsave(&pl061->lock, flags); writeb(!!value << offset, pl061->base + (BIT(offset + 2))); gpiodir = readb(pl061->base + GPIODIR); gpiodir |= BIT(offset); @@ -101,7 +101,7 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, * a gpio pin before configuring it in OUT mode. */ writeb(!!value << offset, pl061->base + (BIT(offset + 2))); - spin_unlock_irqrestore(&pl061->lock, flags); + raw_spin_unlock_irqrestore(&pl061->lock, flags); return 0; } @@ -143,7 +143,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) } - spin_lock_irqsave(&pl061->lock, flags); + raw_spin_lock_irqsave(&pl061->lock, flags); gpioiev = readb(pl061->base + GPIOIEV); gpiois = readb(pl061->base + GPIOIS); @@ -203,7 +203,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger) writeb(gpioibe, pl061->base + GPIOIBE); writeb(gpioiev, pl061->base + GPIOIEV); - spin_unlock_irqrestore(&pl061->lock, flags); + raw_spin_unlock_irqrestore(&pl061->lock, flags); return 0; } @@ -235,10 +235,10 @@ static void pl061_irq_mask(struct irq_data *d) u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; - spin_lock(&pl061->lock); + raw_spin_lock(&pl061->lock); gpioie = readb(pl061->base + GPIOIE) & ~mask; writeb(gpioie, pl061->base + GPIOIE); - spin_unlock(&pl061->lock); + raw_spin_unlock(&pl061->lock); } static void pl061_irq_unmask(struct irq_data *d) @@ -248,10 +248,10 @@ static void pl061_irq_unmask(struct irq_data *d) u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); u8 gpioie; - spin_lock(&pl061->lock); + raw_spin_lock(&pl061->lock); gpioie = readb(pl061->base + GPIOIE) | mask; writeb(gpioie, pl061->base + GPIOIE); - spin_unlock(&pl061->lock); + raw_spin_unlock(&pl061->lock); } /** @@ -268,9 +268,9 @@ static void pl061_irq_ack(struct irq_data *d) struct pl061 *pl061 = gpiochip_get_data(gc); u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); - spin_lock(&pl061->lock); + raw_spin_lock(&pl061->lock); writeb(mask, pl061->base + GPIOIC); - spin_unlock(&pl061->lock); + raw_spin_unlock(&pl061->lock); } static int pl061_irq_set_wake(struct irq_data *d, unsigned int state) @@ -304,7 +304,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id) if (IS_ERR(pl061->base)) return PTR_ERR(pl061->base); - spin_lock_init(&pl061->lock); + raw_spin_lock_init(&pl061->lock); if (of_property_read_bool(dev->of_node, "gpio-ranges")) { pl061->gc.request = gpiochip_generic_request; pl061->gc.free = gpiochip_generic_free; diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 76ac906b4d78..832f3e46ba9f 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -601,7 +601,7 @@ static int pxa_gpio_probe_dt(struct platform_device *pdev, nr_gpios = gpio_id->gpio_nums; pxa_last_gpio = nr_gpios - 1; - irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0); + irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, nr_gpios, 0); if (irq_base < 0) { dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); return irq_base; diff --git a/drivers/gpio/gpio-reg.c b/drivers/gpio/gpio-reg.c new file mode 100644 index 000000000000..e85903eddc68 --- /dev/null +++ b/drivers/gpio/gpio-reg.c @@ -0,0 +1,185 @@ +/* + * gpio-reg: single register individually fixed-direction GPIOs + * + * Copyright (C) 2016 Russell King + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + */ +#include <linux/gpio/driver.h> +#include <linux/gpio/gpio-reg.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +struct gpio_reg { + struct gpio_chip gc; + spinlock_t lock; + u32 direction; + u32 out; + void __iomem *reg; + struct irq_domain *irqdomain; + const int *irqs; +}; + +#define to_gpio_reg(x) container_of(x, struct gpio_reg, gc) + +static int gpio_reg_get_direction(struct gpio_chip *gc, unsigned offset) +{ + struct gpio_reg *r = to_gpio_reg(gc); + + return r->direction & BIT(offset) ? 1 : 0; +} + +static int gpio_reg_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct gpio_reg *r = to_gpio_reg(gc); + + if (r->direction & BIT(offset)) + return -ENOTSUPP; + + gc->set(gc, offset, value); + return 0; +} + +static int gpio_reg_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct gpio_reg *r = to_gpio_reg(gc); + + return r->direction & BIT(offset) ? 0 : -ENOTSUPP; +} + +static void gpio_reg_set(struct gpio_chip *gc, unsigned offset, int value) +{ + struct gpio_reg *r = to_gpio_reg(gc); + unsigned long flags; + u32 val, mask = BIT(offset); + + spin_lock_irqsave(&r->lock, flags); + val = r->out; + if (value) + val |= mask; + else + val &= ~mask; + r->out = val; + writel_relaxed(val, r->reg); + spin_unlock_irqrestore(&r->lock, flags); +} + +static int gpio_reg_get(struct gpio_chip *gc, unsigned offset) +{ + struct gpio_reg *r = to_gpio_reg(gc); + u32 val, mask = BIT(offset); + + if (r->direction & mask) { + /* + * double-read the value, some registers latch after the + * first read. + */ + readl_relaxed(r->reg); + val = readl_relaxed(r->reg); + } else { + val = r->out; + } + return !!(val & mask); +} + +static void gpio_reg_set_multiple(struct gpio_chip *gc, unsigned long *mask, + unsigned long *bits) +{ + struct gpio_reg *r = to_gpio_reg(gc); + unsigned long flags; + + spin_lock_irqsave(&r->lock, flags); + r->out = (r->out & ~*mask) | (*bits & *mask); + writel_relaxed(r->out, r->reg); + spin_unlock_irqrestore(&r->lock, flags); +} + +static int gpio_reg_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct gpio_reg *r = to_gpio_reg(gc); + int irq = r->irqs[offset]; + + if (irq >= 0 && r->irqdomain) + irq = irq_find_mapping(r->irqdomain, irq); + + return irq; +} + +/** + * gpio_reg_init - add a fixed in/out register as gpio + * @dev: optional struct device associated with this register + * @base: start gpio number, or -1 to allocate + * @num: number of GPIOs, maximum 32 + * @label: GPIO chip label + * @direction: bitmask of fixed direction, one per GPIO signal, 1 = in + * @def_out: initial GPIO output value + * @names: array of %num strings describing each GPIO signal or %NULL + * @irqdom: irq domain or %NULL + * @irqs: array of %num ints describing the interrupt mapping for each + * GPIO signal, or %NULL. If @irqdom is %NULL, then this + * describes the Linux interrupt number, otherwise it describes + * the hardware interrupt number in the specified irq domain. + * + * Add a single-register GPIO device containing up to 32 GPIO signals, + * where each GPIO has a fixed input or output configuration. Only + * input GPIOs are assumed to be readable from the register, and only + * then after a double-read. Output values are assumed not to be + * readable. + */ +struct gpio_chip *gpio_reg_init(struct device *dev, void __iomem *reg, + int base, int num, const char *label, u32 direction, u32 def_out, + const char *const *names, struct irq_domain *irqdom, const int *irqs) +{ + struct gpio_reg *r; + int ret; + + if (dev) + r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL); + else + r = kzalloc(sizeof(*r), GFP_KERNEL); + + if (!r) + return ERR_PTR(-ENOMEM); + + spin_lock_init(&r->lock); + + r->gc.label = label; + r->gc.get_direction = gpio_reg_get_direction; + r->gc.direction_input = gpio_reg_direction_input; + r->gc.direction_output = gpio_reg_direction_output; + r->gc.set = gpio_reg_set; + r->gc.get = gpio_reg_get; + r->gc.set_multiple = gpio_reg_set_multiple; + if (irqs) + r->gc.to_irq = gpio_reg_to_irq; + r->gc.base = base; + r->gc.ngpio = num; + r->gc.names = names; + r->direction = direction; + r->out = def_out; + r->reg = reg; + r->irqs = irqs; + + if (dev) + ret = devm_gpiochip_add_data(dev, &r->gc, r); + else + ret = gpiochip_add_data(&r->gc, r); + + return ret ? ERR_PTR(ret) : &r->gc; +} + +int gpio_reg_resume(struct gpio_chip *gc) +{ + struct gpio_reg *r = to_gpio_reg(gc); + unsigned long flags; + + spin_lock_irqsave(&r->lock, flags); + writel_relaxed(r->out, r->reg); + spin_unlock_irqrestore(&r->lock, flags); + + return 0; +} diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 8d8ee0ebf14c..249f433aa62d 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -12,57 +12,97 @@ #include <linux/module.h> #include <linux/io.h> #include <linux/syscore_ops.h> +#include <soc/sa1100/pwer.h> #include <mach/hardware.h> #include <mach/irqs.h> +struct sa1100_gpio_chip { + struct gpio_chip chip; + void __iomem *membase; + int irqbase; + u32 irqmask; + u32 irqrising; + u32 irqfalling; + u32 irqwake; +}; + +#define sa1100_gpio_chip(x) container_of(x, struct sa1100_gpio_chip, chip) + +enum { + R_GPLR = 0x00, + R_GPDR = 0x04, + R_GPSR = 0x08, + R_GPCR = 0x0c, + R_GRER = 0x10, + R_GFER = 0x14, + R_GEDR = 0x18, + R_GAFR = 0x1c, +}; + static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset) { - return !!(GPLR & GPIO_GPIO(offset)); + return readl_relaxed(sa1100_gpio_chip(chip)->membase + R_GPLR) & + BIT(offset); } static void sa1100_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - if (value) - GPSR = GPIO_GPIO(offset); - else - GPCR = GPIO_GPIO(offset); + int reg = value ? R_GPSR : R_GPCR; + + writel_relaxed(BIT(offset), sa1100_gpio_chip(chip)->membase + reg); +} + +static int sa1100_get_direction(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR; + + return !(readl_relaxed(gpdr) & BIT(offset)); } static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset) { + void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR; unsigned long flags; local_irq_save(flags); - GPDR &= ~GPIO_GPIO(offset); + writel_relaxed(readl_relaxed(gpdr) & ~BIT(offset), gpdr); local_irq_restore(flags); + return 0; } static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int value) { + void __iomem *gpdr = sa1100_gpio_chip(chip)->membase + R_GPDR; unsigned long flags; local_irq_save(flags); sa1100_gpio_set(chip, offset, value); - GPDR |= GPIO_GPIO(offset); + writel_relaxed(readl_relaxed(gpdr) | BIT(offset), gpdr); local_irq_restore(flags); + return 0; } static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset) { - return IRQ_GPIO0 + offset; + return sa1100_gpio_chip(chip)->irqbase + offset; } -static struct gpio_chip sa1100_gpio_chip = { - .label = "gpio", - .direction_input = sa1100_direction_input, - .direction_output = sa1100_direction_output, - .set = sa1100_gpio_set, - .get = sa1100_gpio_get, - .to_irq = sa1100_to_irq, - .base = 0, - .ngpio = GPIO_MAX + 1, +static struct sa1100_gpio_chip sa1100_gpio_chip = { + .chip = { + .label = "gpio", + .get_direction = sa1100_get_direction, + .direction_input = sa1100_direction_input, + .direction_output = sa1100_direction_output, + .set = sa1100_gpio_set, + .get = sa1100_gpio_get, + .to_irq = sa1100_to_irq, + .base = 0, + .ngpio = GPIO_MAX + 1, + }, + .membase = (void *)&GPLR, + .irqbase = IRQ_GPIO0, }; /* @@ -70,33 +110,39 @@ static struct gpio_chip sa1100_gpio_chip = { * IRQs are generated on Falling-Edge, Rising-Edge, or both. * Use this instead of directly setting GRER/GFER. */ -static int GPIO_IRQ_rising_edge; -static int GPIO_IRQ_falling_edge; -static int GPIO_IRQ_mask; +static void sa1100_update_edge_regs(struct sa1100_gpio_chip *sgc) +{ + void *base = sgc->membase; + u32 grer, gfer; + + grer = sgc->irqrising & sgc->irqmask; + gfer = sgc->irqfalling & sgc->irqmask; + + writel_relaxed(grer, base + R_GRER); + writel_relaxed(gfer, base + R_GFER); +} static int sa1100_gpio_type(struct irq_data *d, unsigned int type) { - unsigned int mask; - - mask = BIT(d->hwirq); + struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); + unsigned int mask = BIT(d->hwirq); if (type == IRQ_TYPE_PROBE) { - if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask) + if ((sgc->irqrising | sgc->irqfalling) & mask) return 0; type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; } if (type & IRQ_TYPE_EDGE_RISING) - GPIO_IRQ_rising_edge |= mask; + sgc->irqrising |= mask; else - GPIO_IRQ_rising_edge &= ~mask; + sgc->irqrising &= ~mask; if (type & IRQ_TYPE_EDGE_FALLING) - GPIO_IRQ_falling_edge |= mask; + sgc->irqfalling |= mask; else - GPIO_IRQ_falling_edge &= ~mask; + sgc->irqfalling &= ~mask; - GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; - GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; + sa1100_update_edge_regs(sgc); return 0; } @@ -106,36 +152,42 @@ static int sa1100_gpio_type(struct irq_data *d, unsigned int type) */ static void sa1100_gpio_ack(struct irq_data *d) { - GEDR = BIT(d->hwirq); + struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); + + writel_relaxed(BIT(d->hwirq), sgc->membase + R_GEDR); } static void sa1100_gpio_mask(struct irq_data *d) { + struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); unsigned int mask = BIT(d->hwirq); - GPIO_IRQ_mask &= ~mask; + sgc->irqmask &= ~mask; - GRER &= ~mask; - GFER &= ~mask; + sa1100_update_edge_regs(sgc); } static void sa1100_gpio_unmask(struct irq_data *d) { + struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); unsigned int mask = BIT(d->hwirq); - GPIO_IRQ_mask |= mask; + sgc->irqmask |= mask; - GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; - GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; + sa1100_update_edge_regs(sgc); } static int sa1100_gpio_wake(struct irq_data *d, unsigned int on) { - if (on) - PWER |= BIT(d->hwirq); - else - PWER &= ~BIT(d->hwirq); - return 0; + struct sa1100_gpio_chip *sgc = irq_data_get_irq_chip_data(d); + int ret = sa11x0_gpio_set_wake(d->hwirq, on); + if (!ret) { + if (on) + sgc->irqwake |= BIT(d->hwirq); + else + sgc->irqwake &= ~BIT(d->hwirq); + } + return ret; } /* @@ -153,8 +205,10 @@ static struct irq_chip sa1100_gpio_irq_chip = { static int sa1100_gpio_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { - irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip, - handle_edge_irq); + struct sa1100_gpio_chip *sgc = d->host_data; + + irq_set_chip_data(irq, sgc); + irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip, handle_edge_irq); irq_set_probe(irq); return 0; @@ -174,17 +228,19 @@ static struct irq_domain *sa1100_gpio_irqdomain; */ static void sa1100_gpio_handler(struct irq_desc *desc) { + struct sa1100_gpio_chip *sgc = irq_desc_get_handler_data(desc); unsigned int irq, mask; + void __iomem *gedr = sgc->membase + R_GEDR; - mask = GEDR; + mask = readl_relaxed(gedr); do { /* * clear down all currently active IRQ sources. * We will be processing them all. */ - GEDR = mask; + writel_relaxed(mask, gedr); - irq = IRQ_GPIO0; + irq = sgc->irqbase; do { if (mask & 1) generic_handle_irq(irq); @@ -192,30 +248,32 @@ static void sa1100_gpio_handler(struct irq_desc *desc) irq++; } while (mask); - mask = GEDR; + mask = readl_relaxed(gedr); } while (mask); } static int sa1100_gpio_suspend(void) { + struct sa1100_gpio_chip *sgc = &sa1100_gpio_chip; + /* * Set the appropriate edges for wakeup. */ - GRER = PWER & GPIO_IRQ_rising_edge; - GFER = PWER & GPIO_IRQ_falling_edge; + writel_relaxed(sgc->irqwake & sgc->irqrising, sgc->membase + R_GRER); + writel_relaxed(sgc->irqwake & sgc->irqfalling, sgc->membase + R_GFER); /* * Clear any pending GPIO interrupts. */ - GEDR = GEDR; + writel_relaxed(readl_relaxed(sgc->membase + R_GEDR), + sgc->membase + R_GEDR); return 0; } static void sa1100_gpio_resume(void) { - GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask; - GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask; + sa1100_update_edge_regs(&sa1100_gpio_chip); } static struct syscore_ops sa1100_gpio_syscore_ops = { @@ -231,36 +289,40 @@ static int __init sa1100_gpio_init_devicefs(void) device_initcall(sa1100_gpio_init_devicefs); +static const int sa1100_gpio_irqs[] __initconst = { + /* Install handlers for GPIO 0-10 edge detect interrupts */ + IRQ_GPIO0_SC, + IRQ_GPIO1_SC, + IRQ_GPIO2_SC, + IRQ_GPIO3_SC, + IRQ_GPIO4_SC, + IRQ_GPIO5_SC, + IRQ_GPIO6_SC, + IRQ_GPIO7_SC, + IRQ_GPIO8_SC, + IRQ_GPIO9_SC, + IRQ_GPIO10_SC, + /* Install handler for GPIO 11-27 edge detect interrupts */ + IRQ_GPIO11_27, +}; + void __init sa1100_init_gpio(void) { + struct sa1100_gpio_chip *sgc = &sa1100_gpio_chip; + int i; + /* clear all GPIO edge detects */ - GFER = 0; - GRER = 0; - GEDR = -1; + writel_relaxed(0, sgc->membase + R_GFER); + writel_relaxed(0, sgc->membase + R_GRER); + writel_relaxed(-1, sgc->membase + R_GEDR); - gpiochip_add_data(&sa1100_gpio_chip, NULL); + gpiochip_add_data(&sa1100_gpio_chip.chip, NULL); sa1100_gpio_irqdomain = irq_domain_add_simple(NULL, 28, IRQ_GPIO0, - &sa1100_gpio_irqdomain_ops, NULL); - - /* - * Install handlers for GPIO 0-10 edge detect interrupts - */ - irq_set_chained_handler(IRQ_GPIO0_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO1_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO2_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO3_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO4_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO5_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO6_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO7_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO8_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO9_SC, sa1100_gpio_handler); - irq_set_chained_handler(IRQ_GPIO10_SC, sa1100_gpio_handler); - /* - * Install handler for GPIO 11-27 edge detect interrupts - */ - irq_set_chained_handler(IRQ_GPIO11_27, sa1100_gpio_handler); + &sa1100_gpio_irqdomain_ops, sgc); + for (i = 0; i < ARRAY_SIZE(sa1100_gpio_irqs); i++) + irq_set_chained_handler_and_data(sa1100_gpio_irqs[i], + sa1100_gpio_handler, sgc); } diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index 7da9e6c4546a..f60da83349ef 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -135,7 +135,8 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, struct irq_chip_type *ct; int ret; - sd->irq_base = irq_alloc_descs(-1, 0, SDV_NUM_PUB_GPIOS, -1); + sd->irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, + SDV_NUM_PUB_GPIOS, -1); if (sd->irq_base < 0) return sd->irq_base; @@ -143,10 +144,11 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, writel(0, sd->gpio_pub_base + GPIO_INT); writel((1 << 11) - 1, sd->gpio_pub_base + GPSTR); - ret = request_irq(pdev->irq, sdv_gpio_pub_irq_handler, IRQF_SHARED, - "sdv_gpio", sd); + ret = devm_request_irq(&pdev->dev, pdev->irq, + sdv_gpio_pub_irq_handler, IRQF_SHARED, + "sdv_gpio", sd); if (ret) - goto out_free_desc; + return ret; /* * This gpio irq controller latches level irqs. Testing shows that if @@ -155,10 +157,8 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, */ sd->gc = irq_alloc_generic_chip("sdv-gpio", 1, sd->irq_base, sd->gpio_pub_base, handle_fasteoi_irq); - if (!sd->gc) { - ret = -ENOMEM; - goto out_free_irq; - } + if (!sd->gc) + return -ENOMEM; sd->gc->private = sd; ct = sd->gc->chip_types; @@ -176,16 +176,10 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, sd->id = irq_domain_add_legacy(pdev->dev.of_node, SDV_NUM_PUB_GPIOS, sd->irq_base, 0, &irq_domain_sdv_ops, sd); - if (!sd->id) { - ret = -ENODEV; - goto out_free_irq; - } + if (!sd->id) + return -ENODEV; + return 0; -out_free_irq: - free_irq(pdev->irq, sd); -out_free_desc: - irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); - return ret; } static int sdv_gpio_probe(struct pci_dev *pdev, diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 853ca23cad88..39df0620fa38 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -392,7 +392,8 @@ static int gsta_probe(struct platform_device *dev) gsta_set_config(chip, i, gpio_pdata->pinconfig[i]); /* 384 was used in previous code: be compatible for other drivers */ - err = irq_alloc_descs(-1, 384, GSTA_NR_GPIO, NUMA_NO_NODE); + err = devm_irq_alloc_descs(&dev->dev, -1, 384, + GSTA_NR_GPIO, NUMA_NO_NODE); if (err < 0) { dev_warn(&dev->dev, "sta2x11 gpio: Can't get irq base (%i)\n", -err); @@ -401,29 +402,23 @@ static int gsta_probe(struct platform_device *dev) chip->irq_base = err; gsta_alloc_irq_chip(chip); - err = request_irq(pdev->irq, gsta_gpio_handler, - IRQF_SHARED, KBUILD_MODNAME, chip); + err = devm_request_irq(&dev->dev, pdev->irq, gsta_gpio_handler, + IRQF_SHARED, KBUILD_MODNAME, chip); if (err < 0) { dev_err(&dev->dev, "sta2x11 gpio: Can't request irq (%i)\n", -err); - goto err_free_descs; + return err; } err = devm_gpiochip_add_data(&dev->dev, &chip->gpio, chip); if (err < 0) { dev_err(&dev->dev, "sta2x11 gpio: Can't register (%i)\n", -err); - goto err_free_irq; + return err; } platform_set_drvdata(dev, chip); return 0; - -err_free_irq: - free_irq(pdev->irq, chip); -err_free_descs: - irq_free_descs(chip->irq_base, GSTA_NR_GPIO); - return err; } static struct platform_driver sta2x11_gpio_platform_driver = { diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index dfcfbba74416..24f388ed46d4 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -485,7 +485,8 @@ static int gpio_twl4030_probe(struct platform_device *pdev) goto no_irqs; } - irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0); + irq_base = devm_irq_alloc_descs(&pdev->dev, -1, + 0, TWL4030_GPIO_MAX, 0); if (irq_base < 0) { dev_err(&pdev->dev, "Failed to alloc irq_descs\n"); return irq_base; diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 97613de5304e..7b1bc20be209 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -51,6 +51,8 @@ #define GROUP1_NR_IRQS 6 #define IRQ_MASK_BASE 0x4e19 #define IRQ_STATUS_BASE 0x4e0b +#define GPIO_IRQ0_MASK GENMASK(6, 0) +#define GPIO_IRQ1_MASK GENMASK(5, 0) #define UPDATE_IRQ_TYPE BIT(0) #define UPDATE_IRQ_MASK BIT(1) @@ -309,7 +311,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) return IRQ_NONE; } - pending = p[0] | (p[1] << 8); + pending = (p[0] & GPIO_IRQ0_MASK) | ((p[1] & GPIO_IRQ1_MASK) << 7); if (!pending) return IRQ_NONE; @@ -317,7 +319,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) while (pending) { /* One iteration is for all pending bits */ for_each_set_bit(gpio, (const unsigned long *)&pending, - GROUP0_NR_IRQS) { + WCOVE_GPIO_NUM) { offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0; mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) : BIT(gpio); @@ -333,7 +335,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) break; } - pending = p[0] | (p[1] << 8); + pending = (p[0] & GPIO_IRQ0_MASK) | ((p[1] & GPIO_IRQ1_MASK) << 7); } return IRQ_HANDLED; diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index 901b5ccb032d..87d63695dfcf 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -51,7 +51,7 @@ struct ws16c48_gpio { struct gpio_chip chip; unsigned char io_state[6]; unsigned char out_state[6]; - spinlock_t lock; + raw_spinlock_t lock; unsigned long irq_mask; unsigned long flow_mask; unsigned base; @@ -73,13 +73,13 @@ static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) const unsigned mask = BIT(offset % 8); unsigned long flags; - spin_lock_irqsave(&ws16c48gpio->lock, flags); + raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); ws16c48gpio->io_state[port] |= mask; ws16c48gpio->out_state[port] &= ~mask; outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port); - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); return 0; } @@ -92,7 +92,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip, const unsigned mask = BIT(offset % 8); unsigned long flags; - spin_lock_irqsave(&ws16c48gpio->lock, flags); + raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); ws16c48gpio->io_state[port] &= ~mask; if (value) @@ -101,7 +101,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip, ws16c48gpio->out_state[port] &= ~mask; outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port); - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); return 0; } @@ -114,17 +114,17 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset) unsigned long flags; unsigned port_state; - spin_lock_irqsave(&ws16c48gpio->lock, flags); + raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); /* ensure that GPIO is set for input */ if (!(ws16c48gpio->io_state[port] & mask)) { - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); return -EINVAL; } port_state = inb(ws16c48gpio->base + port); - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); return !!(port_state & mask); } @@ -136,11 +136,11 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value) const unsigned mask = BIT(offset % 8); unsigned long flags; - spin_lock_irqsave(&ws16c48gpio->lock, flags); + raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); /* ensure that GPIO is set for output */ if (ws16c48gpio->io_state[port] & mask) { - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); return; } @@ -150,7 +150,7 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ws16c48gpio->out_state[port] &= ~mask; outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port); - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } static void ws16c48_gpio_set_multiple(struct gpio_chip *chip, @@ -178,14 +178,14 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *chip, iomask = mask[BIT_WORD(i)] & ~ws16c48gpio->io_state[port]; bitmask = iomask & bits[BIT_WORD(i)]; - spin_lock_irqsave(&ws16c48gpio->lock, flags); + raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); /* update output state data and set device gpio register */ ws16c48gpio->out_state[port] &= ~iomask; ws16c48gpio->out_state[port] |= bitmask; outb(ws16c48gpio->out_state[port], ws16c48gpio->base + port); - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); /* prepare for next gpio register set */ mask[BIT_WORD(i)] >>= gpio_reg_size; @@ -207,7 +207,7 @@ static void ws16c48_irq_ack(struct irq_data *data) if (port > 2) return; - spin_lock_irqsave(&ws16c48gpio->lock, flags); + raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); port_state = ws16c48gpio->irq_mask >> (8*port); @@ -216,7 +216,7 @@ static void ws16c48_irq_ack(struct irq_data *data) outb(port_state | mask, ws16c48gpio->base + 8 + port); outb(0xC0, ws16c48gpio->base + 7); - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } static void ws16c48_irq_mask(struct irq_data *data) @@ -232,7 +232,7 @@ static void ws16c48_irq_mask(struct irq_data *data) if (port > 2) return; - spin_lock_irqsave(&ws16c48gpio->lock, flags); + raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); ws16c48gpio->irq_mask &= ~mask; @@ -240,7 +240,7 @@ static void ws16c48_irq_mask(struct irq_data *data) outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port); outb(0xC0, ws16c48gpio->base + 7); - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } static void ws16c48_irq_unmask(struct irq_data *data) @@ -256,7 +256,7 @@ static void ws16c48_irq_unmask(struct irq_data *data) if (port > 2) return; - spin_lock_irqsave(&ws16c48gpio->lock, flags); + raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); ws16c48gpio->irq_mask |= mask; @@ -264,7 +264,7 @@ static void ws16c48_irq_unmask(struct irq_data *data) outb(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port); outb(0xC0, ws16c48gpio->base + 7); - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type) @@ -280,7 +280,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type) if (port > 2) return -EINVAL; - spin_lock_irqsave(&ws16c48gpio->lock, flags); + raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); switch (flow_type) { case IRQ_TYPE_NONE: @@ -292,7 +292,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type) ws16c48gpio->flow_mask &= ~mask; break; default: - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); return -EINVAL; } @@ -300,7 +300,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type) outb(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port); outb(0xC0, ws16c48gpio->base + 7); - spin_unlock_irqrestore(&ws16c48gpio->lock, flags); + raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); return 0; } @@ -387,7 +387,7 @@ static int ws16c48_probe(struct device *dev, unsigned int id) ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple; ws16c48gpio->base = base[id]; - spin_lock_init(&ws16c48gpio->lock); + raw_spin_lock_init(&ws16c48gpio->lock); err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio); if (err) { diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 4620d050e5a8..d857e1d8e731 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -404,7 +404,9 @@ static int xlp_gpio_probe(struct platform_device *pdev) /* XLP(MIPS) has fixed range for GPIO IRQs, Vulcan(ARM64) does not */ if (soc_type != GPIO_VARIANT_VULCAN) { - irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0); + irq_base = devm_irq_alloc_descs(&pdev->dev, -1, + XLP_GPIO_IRQ_BASE, + gc->ngpio, 0); if (irq_base < 0) { dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); return irq_base; @@ -415,7 +417,7 @@ static int xlp_gpio_probe(struct platform_device *pdev) err = gpiochip_add_data(gc, priv); if (err < 0) - goto out_free_desc; + return err; err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base, handle_level_irq, IRQ_TYPE_NONE); @@ -433,14 +435,13 @@ static int xlp_gpio_probe(struct platform_device *pdev) out_gpio_remove: gpiochip_remove(gc); -out_free_desc: - irq_free_descs(irq_base, gc->ngpio); return err; } #ifdef CONFIG_ACPI static const struct acpi_device_id xlp_gpio_acpi_match[] = { { "BRCM9006", GPIO_VARIANT_VULCAN }, + { "CAV9006", GPIO_VARIANT_VULCAN }, {}, }; MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match); diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c index 93de8be0d885..be3a87da8438 100644 --- a/drivers/gpio/gpio-zx.c +++ b/drivers/gpio/gpio-zx.c @@ -41,7 +41,7 @@ #define ZX_GPIO_NR 16 struct zx_gpio { - spinlock_t lock; + raw_spinlock_t lock; void __iomem *base; struct gpio_chip gc; @@ -56,11 +56,11 @@ static int zx_direction_input(struct gpio_chip *gc, unsigned offset) if (offset >= gc->ngpio) return -EINVAL; - spin_lock_irqsave(&chip->lock, flags); + raw_spin_lock_irqsave(&chip->lock, flags); gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); gpiodir &= ~BIT(offset); writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); - spin_unlock_irqrestore(&chip->lock, flags); + raw_spin_unlock_irqrestore(&chip->lock, flags); return 0; } @@ -75,7 +75,7 @@ static int zx_direction_output(struct gpio_chip *gc, unsigned offset, if (offset >= gc->ngpio) return -EINVAL; - spin_lock_irqsave(&chip->lock, flags); + raw_spin_lock_irqsave(&chip->lock, flags); gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); gpiodir |= BIT(offset); writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); @@ -84,7 +84,7 @@ static int zx_direction_output(struct gpio_chip *gc, unsigned offset, writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1); else writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0); - spin_unlock_irqrestore(&chip->lock, flags); + raw_spin_unlock_irqrestore(&chip->lock, flags); return 0; } @@ -118,7 +118,7 @@ static int zx_irq_type(struct irq_data *d, unsigned trigger) if (offset < 0 || offset >= ZX_GPIO_NR) return -EINVAL; - spin_lock_irqsave(&chip->lock, flags); + raw_spin_lock_irqsave(&chip->lock, flags); gpioiev = readw_relaxed(chip->base + ZX_GPIO_IV); gpiois = readw_relaxed(chip->base + ZX_GPIO_IVE); @@ -151,7 +151,7 @@ static int zx_irq_type(struct irq_data *d, unsigned trigger) writew_relaxed(gpioi_epos, chip->base + ZX_GPIO_IEP); writew_relaxed(gpioi_eneg, chip->base + ZX_GPIO_IEN); writew_relaxed(gpioiev, chip->base + ZX_GPIO_IV); - spin_unlock_irqrestore(&chip->lock, flags); + raw_spin_unlock_irqrestore(&chip->lock, flags); return 0; } @@ -184,12 +184,12 @@ static void zx_irq_mask(struct irq_data *d) u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); u16 gpioie; - spin_lock(&chip->lock); + raw_spin_lock(&chip->lock); gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) | mask; writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) & ~mask; writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); - spin_unlock(&chip->lock); + raw_spin_unlock(&chip->lock); } static void zx_irq_unmask(struct irq_data *d) @@ -199,12 +199,12 @@ static void zx_irq_unmask(struct irq_data *d) u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); u16 gpioie; - spin_lock(&chip->lock); + raw_spin_lock(&chip->lock); gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) & ~mask; writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) | mask; writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); - spin_unlock(&chip->lock); + raw_spin_unlock(&chip->lock); } static struct irq_chip zx_irqchip = { @@ -230,7 +230,7 @@ static int zx_gpio_probe(struct platform_device *pdev) if (IS_ERR(chip->base)) return PTR_ERR(chip->base); - spin_lock_init(&chip->lock); + raw_spin_lock_init(&chip->lock); if (of_property_read_bool(dev->of_node, "gpio-ranges")) { chip->gc.request = gpiochip_generic_request; chip->gc.free = gpiochip_generic_free; diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 2bd683e2be02..2185232da823 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -368,6 +368,37 @@ int acpi_dev_add_driver_gpios(struct acpi_device *adev, } EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios); +static void devm_acpi_dev_release_driver_gpios(struct device *dev, void *res) +{ + acpi_dev_remove_driver_gpios(ACPI_COMPANION(dev)); +} + +int devm_acpi_dev_add_driver_gpios(struct device *dev, + const struct acpi_gpio_mapping *gpios) +{ + void *res; + int ret; + + res = devres_alloc(devm_acpi_dev_release_driver_gpios, 0, GFP_KERNEL); + if (!res) + return -ENOMEM; + + ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), gpios); + if (ret) { + devres_free(res); + return ret; + } + devres_add(dev, res); + return 0; +} +EXPORT_SYMBOL_GPL(devm_acpi_dev_add_driver_gpios); + +void devm_acpi_dev_remove_driver_gpios(struct device *dev) +{ + WARN_ON(devres_release(dev, devm_acpi_dev_release_driver_gpios, NULL, NULL)); +} +EXPORT_SYMBOL_GPL(devm_acpi_dev_remove_driver_gpios); + static bool acpi_get_driver_gpio_data(struct acpi_device *adev, const char *name, int index, struct acpi_reference_args *args) @@ -661,20 +692,24 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) { int idx, i; unsigned int irq_flags; - int ret = -ENOENT; for (i = 0, idx = 0; idx <= index; i++) { struct acpi_gpio_info info; struct gpio_desc *desc; desc = acpi_get_gpiod_by_index(adev, NULL, i, &info); - if (IS_ERR(desc)) { - ret = PTR_ERR(desc); - break; - } + + /* Ignore -EPROBE_DEFER, it only matters if idx matches */ + if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER) + return PTR_ERR(desc); + if (info.gpioint && idx++ == index) { - int irq = gpiod_to_irq(desc); + int irq; + if (IS_ERR(desc)) + return PTR_ERR(desc); + + irq = gpiod_to_irq(desc); if (irq < 0) return irq; @@ -690,7 +725,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) } } - return ret; + return -ENOENT; } EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get); @@ -1075,7 +1110,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id) break; } } - if (count >= 0) + if (count > 0) break; } @@ -1091,7 +1126,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id) if (crs_count > 0) count = crs_count; } - return count; + return count ? count : -ENOENT; } struct acpi_crs_lookup { diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 975b9f6cf408..b13b7c7c335f 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -147,7 +147,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, *flags |= GPIO_ACTIVE_LOW; if (of_flags & OF_GPIO_SINGLE_ENDED) { - if (of_flags & OF_GPIO_ACTIVE_LOW) + if (of_flags & OF_GPIO_OPEN_DRAIN) *flags |= GPIO_OPEN_DRAIN; else *flags |= GPIO_OPEN_SOURCE; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 8b4d721d6d63..1d1fa7248d63 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1522,7 +1522,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip, */ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, struct irq_chip *irqchip, - int parent_irq, + unsigned int parent_irq, irq_flow_handler_t parent_handler) { unsigned int offset; @@ -1571,7 +1571,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip, */ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, struct irq_chip *irqchip, - int parent_irq, + unsigned int parent_irq, irq_flow_handler_t parent_handler) { gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq, @@ -1588,7 +1588,7 @@ EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip); */ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip, struct irq_chip *irqchip, - int parent_irq) + unsigned int parent_irq) { if (!gpiochip->irq_nested) { chip_err(gpiochip, "tried to nest a chained gpiochip\n"); @@ -3122,10 +3122,10 @@ static int dt_gpio_count(struct device *dev, const char *con_id) gpio_suffixes[i]); ret = of_gpio_named_count(dev->of_node, propname); - if (ret >= 0) + if (ret > 0) break; } - return ret; + return ret ? ret : -ENOENT; } static int platform_gpio_count(struct device *dev, const char *con_id) @@ -3326,7 +3326,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index); * underlying firmware interface and then makes sure that the GPIO * descriptor is requested before it is returned to the caller. * - * On successfull request the GPIO pin is configured in accordance with + * On successful request the GPIO pin is configured in accordance with * provided @dflags. * * In case of error an ERR_PTR() is returned. @@ -3340,6 +3340,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, unsigned long lflags = 0; bool active_low = false; bool single_ended = false; + bool open_drain = false; int ret; if (!fwnode) @@ -3353,6 +3354,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, if (!IS_ERR(desc)) { active_low = flags & OF_GPIO_ACTIVE_LOW; single_ended = flags & OF_GPIO_SINGLE_ENDED; + open_drain = flags & OF_GPIO_OPEN_DRAIN; } } else if (is_acpi_node(fwnode)) { struct acpi_gpio_info info; @@ -3373,7 +3375,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode, lflags |= GPIO_ACTIVE_LOW; if (single_ended) { - if (active_low) + if (open_drain) lflags |= GPIO_OPEN_DRAIN; else lflags |= GPIO_OPEN_SOURCE; |