diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 11 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 7 | ||||
-rw-r--r-- | drivers/gpio/gpio-davinci.c | 455 | ||||
-rw-r--r-- | drivers/gpio/gpio-ep93xx.c | 22 | ||||
-rw-r--r-- | drivers/gpio/gpio-ks8695.c | 319 | ||||
-rw-r--r-- | drivers/gpio/gpio-langwell.c | 27 | ||||
-rw-r--r-- | drivers/gpio/gpio-lpc32xx.c | 446 | ||||
-rw-r--r-- | drivers/gpio/gpio-ml-ioh.c | 254 | ||||
-rw-r--r-- | drivers/gpio/gpio-mxc.c | 18 | ||||
-rw-r--r-- | drivers/gpio/gpio-mxs.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-nomadik.c | 130 | ||||
-rw-r--r-- | drivers/gpio/gpio-omap.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-pch.c | 250 | ||||
-rw-r--r-- | drivers/gpio/gpio-pl061.c | 31 | ||||
-rw-r--r-- | drivers/gpio/gpio-pxa.c | 338 | ||||
-rw-r--r-- | drivers/gpio/gpio-sa1100.c | 63 | ||||
-rw-r--r-- | drivers/gpio/gpio-tegra.c | 166 | ||||
-rw-r--r-- | drivers/gpio/gpio-tnetv107x.c | 205 | ||||
-rw-r--r-- | drivers/gpio/gpio-u300.c | 1190 |
19 files changed, 3353 insertions, 583 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index fbc5fd4..8b3c745 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -178,6 +178,15 @@ config GPIO_SCH The Intel Tunnel Creek processor has 5 GPIOs powered by the core power rail and 9 from suspend power supply. +config GPIO_U300 + bool "ST-Ericsson U300 COH 901 335/571 GPIO" + depends on GPIOLIB && ARCH_U300 + help + Say yes here to support GPIO interface on ST-Ericsson U300. + The names of the two IP block variants supported are + COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 + ports of 8 GPIO pins each. + config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" depends on PCI @@ -388,6 +397,7 @@ config GPIO_LANGWELL config GPIO_PCH tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GPIO" depends on PCI && X86 + select GENERIC_IRQ_CHIP help This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded processor. @@ -402,6 +412,7 @@ config GPIO_PCH config GPIO_ML_IOH tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" depends on PCI + select GENERIC_IRQ_CHIP help ML7213 is companion chip for Intel Atom E6xx series. This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9588948..19c5d27 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -14,11 +14,14 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o +obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_EXYNOS4) += gpio-exynos4.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o +obj-$(CONFIG_MACH_KS8695) += gpio-ks8695.o obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o +obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o @@ -37,18 +40,20 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o +obj-$(CONFIG_PLAT_PXA) += gpio-pxa.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o obj-$(CONFIG_GPIO_S5PC100) += gpio-s5pc100.o obj-$(CONFIG_GPIO_S5PV210) += gpio-s5pv210.o - +obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o +obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c new file mode 100644 index 0000000..df0d595 --- /dev/null +++ b/drivers/gpio/gpio-davinci.c @@ -0,0 +1,455 @@ +/* + * TI DaVinci GPIO Support + * + * Copyright (c) 2006-2007 David Brownell + * Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/gpio.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> + +#include <asm/mach/irq.h> + +struct davinci_gpio_regs { + u32 dir; + u32 out_data; + u32 set_data; + u32 clr_data; + u32 in_data; + u32 set_rising; + u32 clr_rising; + u32 set_falling; + u32 clr_falling; + u32 intstat; +}; + +#define chip2controller(chip) \ + container_of(chip, struct davinci_gpio_controller, chip) + +static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)]; +static void __iomem *gpio_base; + +static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio) +{ + void __iomem *ptr; + + if (gpio < 32 * 1) + ptr = gpio_base + 0x10; + else if (gpio < 32 * 2) + ptr = gpio_base + 0x38; + else if (gpio < 32 * 3) + ptr = gpio_base + 0x60; + else if (gpio < 32 * 4) + ptr = gpio_base + 0x88; + else if (gpio < 32 * 5) + ptr = gpio_base + 0xb0; + else + ptr = NULL; + return ptr; +} + +static inline struct davinci_gpio_regs __iomem *irq2regs(int irq) +{ + struct davinci_gpio_regs __iomem *g; + + g = (__force struct davinci_gpio_regs __iomem *)irq_get_chip_data(irq); + + return g; +} + +static int __init davinci_gpio_irq_setup(void); + +/*--------------------------------------------------------------------------*/ + +/* board setup code *MUST* setup pinmux and enable the GPIO clock. */ +static inline int __davinci_direction(struct gpio_chip *chip, + unsigned offset, bool out, int value) +{ + struct davinci_gpio_controller *d = chip2controller(chip); + struct davinci_gpio_regs __iomem *g = d->regs; + unsigned long flags; + u32 temp; + u32 mask = 1 << offset; + + spin_lock_irqsave(&d->lock, flags); + temp = __raw_readl(&g->dir); + if (out) { + temp &= ~mask; + __raw_writel(mask, value ? &g->set_data : &g->clr_data); + } else { + temp |= mask; + } + __raw_writel(temp, &g->dir); + spin_unlock_irqrestore(&d->lock, flags); + + return 0; +} + +static int davinci_direction_in(struct gpio_chip *chip, unsigned offset) +{ + return __davinci_direction(chip, offset, false, 0); +} + +static int +davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value) +{ + return __davinci_direction(chip, offset, true, value); +} + +/* + * Read the pin's value (works even if it's set up as output); + * returns zero/nonzero. + * + * Note that changes are synched to the GPIO clock, so reading values back + * right after you've set them may give old values. + */ +static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_gpio_controller *d = chip2controller(chip); + struct davinci_gpio_regs __iomem *g = d->regs; + + return (1 << offset) & __raw_readl(&g->in_data); +} + +/* + * Assuming the pin is muxed as a gpio output, set its output value. + */ +static void +davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct davinci_gpio_controller *d = chip2controller(chip); + struct davinci_gpio_regs __iomem *g = d->regs; + + __raw_writel((1 << offset), value ? &g->set_data : &g->clr_data); +} + +static int __init davinci_gpio_setup(void) +{ + int i, base; + unsigned ngpio; + struct davinci_soc_info *soc_info = &davinci_soc_info; + struct davinci_gpio_regs *regs; + + if (soc_info->gpio_type != GPIO_TYPE_DAVINCI) + return 0; + + /* + * The gpio banks conceptually expose a segmented bitmap, + * and "ngpio" is one more than the largest zero-based + * bit index that's valid. + */ + ngpio = soc_info->gpio_num; + if (ngpio == 0) { + pr_err("GPIO setup: how many GPIOs?\n"); + return -EINVAL; + } + + if (WARN_ON(DAVINCI_N_GPIO < ngpio)) + ngpio = DAVINCI_N_GPIO; + + gpio_base = ioremap(soc_info->gpio_base, SZ_4K); + if (WARN_ON(!gpio_base)) + return -ENOMEM; + + for (i = 0, base = 0; base < ngpio; i++, base += 32) { + chips[i].chip.label = "DaVinci"; + + chips[i].chip.direction_input = davinci_direction_in; + chips[i].chip.get = davinci_gpio_get; + chips[i].chip.direction_output = davinci_direction_out; + chips[i].chip.set = davinci_gpio_set; + + chips[i].chip.base = base; + chips[i].chip.ngpio = ngpio - base; + if (chips[i].chip.ngpio > 32) + chips[i].chip.ngpio = 32; + + spin_lock_init(&chips[i].lock); + + regs = gpio2regs(base); + chips[i].regs = regs; + chips[i].set_data = ®s->set_data; + chips[i].clr_data = ®s->clr_data; + chips[i].in_data = ®s->in_data; + + gpiochip_add(&chips[i].chip); + } + + soc_info->gpio_ctlrs = chips; + soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32); + + davinci_gpio_irq_setup(); + return 0; +} +pure_initcall(davinci_gpio_setup); + +/*--------------------------------------------------------------------------*/ +/* + * We expect irqs will normally be set up as input pins, but they can also be + * used as output pins ... which is convenient for testing. + * + * NOTE: The first few GPIOs also have direct INTC hookups in addition + * to their GPIOBNK0 irq, with a bit less overhead. + * + * All those INTC hookups (direct, plus several IRQ banks) can also + * serve as EDMA event triggers. + */ + +static void gpio_irq_disable(struct irq_data *d) +{ + struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); + u32 mask = (u32) irq_data_get_irq_handler_data(d); + + __raw_writel(mask, &g->clr_falling); + __raw_writel(mask, &g->clr_rising); +} + +static void gpio_irq_enable(struct irq_data *d) +{ + struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); + u32 mask = (u32) irq_data_get_irq_handler_data(d); + unsigned status = irqd_get_trigger_type(d); + + status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; + if (!status) + status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; + + if (status & IRQ_TYPE_EDGE_FALLING) + __raw_writel(mask, &g->set_falling); + if (status & IRQ_TYPE_EDGE_RISING) + __raw_writel(mask, &g->set_rising); +} + +static int gpio_irq_type(struct irq_data *d, unsigned trigger) +{ + if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + return -EINVAL; + + return 0; +} + +static struct irq_chip gpio_irqchip = { + .name = "GPIO", + .irq_enable = gpio_irq_enable, + .irq_disable = gpio_irq_disable, + .irq_set_type = gpio_irq_type, + .flags = IRQCHIP_SET_TYPE_MASKED, +}; + +static void +gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct davinci_gpio_regs __iomem *g; + u32 mask = 0xffff; + struct davinci_gpio_controller *d; + + d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc); + g = (struct davinci_gpio_regs __iomem *)d->regs; + + /* we only care about one bank */ + if (irq & 1) + mask <<= 16; + + /* temporarily mask (level sensitive) parent IRQ */ + desc->irq_data.chip->irq_mask(&desc->irq_data); + desc->irq_data.chip->irq_ack(&desc->irq_data); + while (1) { + u32 status; + int n; + int res; + + /* ack any irqs */ + status = __raw_readl(&g->intstat) & mask; + if (!status) + break; + __raw_writel(status, &g->intstat); + + /* now demux them to the right lowlevel handler */ + n = d->irq_base; + if (irq & 1) { + n += 16; + status >>= 16; + } + + while (status) { + res = ffs(status); + n += res; + generic_handle_irq(n - 1); + status >>= res; + } + } + desc->irq_data.chip->irq_unmask(&desc->irq_data); + /* now it may re-trigger */ +} + +static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_gpio_controller *d = chip2controller(chip); + + if (d->irq_base >= 0) + return d->irq_base + offset; + else + return -ENODEV; +} + +static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_soc_info *soc_info = &davinci_soc_info; + + /* NOTE: we assume for now that only irqs in the first gpio_chip + * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs). + */ + if (offset < soc_info->gpio_unbanked) + return soc_info->gpio_irq + offset; + else + return -ENODEV; +} + +static int gpio_irq_type_unbanked(struct irq_data *d, unsigned trigger) +{ + struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); + u32 mask = (u32) irq_data_get_irq_handler_data(d); + + if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + return -EINVAL; + + __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING) + ? &g->set_falling : &g->clr_falling); + __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING) + ? &g->set_rising : &g->clr_rising); + + return 0; +} + +/* + * NOTE: for suspend/resume, probably best to make a platform_device with + * suspend_late/resume_resume calls hooking into results of the set_wake() + * calls ... so if no gpios are wakeup events the clock can be disabled, + * with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0 + * (dm6446) can be set appropriately for GPIOV33 pins. + */ + +static int __init davinci_gpio_irq_setup(void) +{ + unsigned gpio, irq, bank; + struct clk *clk; + u32 binten = 0; + unsigned ngpio, bank_irq; + struct davinci_soc_info *soc_info = &davinci_soc_info; + struct davinci_gpio_regs __iomem *g; + + ngpio = soc_info->gpio_num; + + bank_irq = soc_info->gpio_irq; + if (bank_irq == 0) { + printk(KERN_ERR "Don't know first GPIO bank IRQ.\n"); + return -EINVAL; + } + + clk = clk_get(NULL, "gpio"); + if (IS_ERR(clk)) { + printk(KERN_ERR "Error %ld getting gpio clock?\n", + PTR_ERR(clk)); + return PTR_ERR(clk); + } + clk_enable(clk); + + /* Arrange gpio_to_irq() support, handling either direct IRQs or + * banked IRQs. Having GPIOs in the first GPIO bank use direct + * IRQs, while the others use banked IRQs, would need some setup + * tweaks to recognize hardware which can do that. + */ + for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) { + chips[bank].chip.to_irq = gpio_to_irq_banked; + chips[bank].irq_base = soc_info->gpio_unbanked + ? -EINVAL + : (soc_info->intc_irq_num + gpio); + } + + /* + * AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO + * controller only handling trigger modes. We currently assume no + * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. + */ + if (soc_info->gpio_unbanked) { + static struct irq_chip gpio_irqchip_unbanked; + + /* pass "bank 0" GPIO IRQs to AINTC */ + chips[0].chip.to_irq = gpio_to_irq_unbanked; + binten = BIT(0); + + /* AINTC handles mask/unmask; GPIO handles triggering */ + irq = bank_irq; + gpio_irqchip_unbanked = *irq_get_chip(irq); + gpio_irqchip_unbanked.name = "GPIO-AINTC"; + gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked; + + /* default trigger: both edges */ + g = gpio2regs(0); + __raw_writel(~0, &g->set_falling); + __raw_writel(~0, &g->set_rising); + + /* set the direct IRQs up to use that irqchip */ + for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) { + irq_set_chip(irq, &gpio_irqchip_unbanked); + irq_set_handler_data(irq, (void *)__gpio_mask(gpio)); + irq_set_chip_data(irq, (__force void *)g); + irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH); + } + + goto done; + } + + /* + * Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we + * then chain through our own handler. + */ + for (gpio = 0, irq = gpio_to_irq(0), bank = 0; + gpio < ngpio; + bank++, bank_irq++) { + unsigned i; + + /* disabled by default, enabled only as needed */ + g = gpio2regs(gpio); + __raw_writel(~0, &g->clr_falling); + __raw_writel(~0, &g->clr_rising); + + /* set up all irqs in this bank */ + irq_set_chained_handler(bank_irq, gpio_irq_handler); + + /* + * Each chip handles 32 gpios, and each irq bank consists of 16 + * gpio irqs. Pass the irq bank's corresponding controller to + * the chained irq handler. + */ + irq_set_handler_data(bank_irq, &chips[gpio / 32]); + + for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) { + irq_set_chip(irq, &gpio_irqchip); + irq_set_chip_data(irq, (__force void *)g); + irq_set_handler_data(irq, (void *)__gpio_mask(gpio)); + irq_set_handler(irq, handle_simple_irq); + set_irq_flags(irq, IRQF_VALID); + } + + binten |= BIT(bank); + } + +done: + /* BINTEN -- per-bank interrupt enable. genirq would also let these + * bits be set/cleared dynamically. + */ + __raw_writel(binten, gpio_base + 0x08); + + printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0)); + + return 0; +} diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 72fb9c6..7aafbb4 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -23,6 +23,9 @@ #include <linux/basic_mmio_gpio.h> #include <mach/hardware.h> +#include <mach/gpio-ep93xx.h> + +#define irq_to_gpio(irq) ((irq) - gpio_to_irq(0)) struct ep93xx_gpio { void __iomem *mmio_base; @@ -307,6 +310,21 @@ static int ep93xx_gpio_set_debounce(struct gpio_chip *chip, return 0; } +/* + * Map GPIO A0..A7 (0..7) to irq 64..71, + * B0..B7 (7..15) to irq 72..79, and + * F0..F7 (16..24) to irq 80..87. + */ +static int ep93xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + int gpio = chip->base + offset; + + if (gpio > EP93XX_GPIO_LINE_MAX_IRQ) + return -EINVAL; + + return 64 + gpio; +} + static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev, void __iomem *mmio_base, struct ep93xx_gpio_bank *bank) { @@ -321,8 +339,10 @@ static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev, bgc->gc.label = bank->label; bgc->gc.base = bank->base; - if (bank->has_debounce) + if (bank->has_debounce) { bgc->gc.set_debounce = ep93xx_gpio_set_debounce; + bgc->gc.to_irq = ep93xx_gpio_to_irq; + } return gpiochip_add(&bgc->gc); } diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c new file mode 100644 index 0000000..a3ac66e --- /dev/null +++ b/drivers/gpio/gpio-ks8695.c @@ -0,0 +1,319 @@ +/* + * arch/arm/mach-ks8695/gpio.c + * + * Copyright (C) 2006 Andrew Victor + * Updated to GPIOLIB, Copyright 2008 Simtec Electronics + * Daniel Silverstone <dsilvers@simtec.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/module.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <asm/mach/irq.h> + +#include <mach/regs-gpio.h> +#include <mach/gpio-ks8695.h> + +/* + * Configure a GPIO line for either GPIO function, or its internal + * function (Interrupt, Timer, etc). + */ +static void ks8695_gpio_mode(unsigned int pin, short gpio) +{ + unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN }; + unsigned long x, flags; + + if (pin > KS8695_GPIO_5) /* only GPIO 0..5 have internal functions */ + return; + + local_irq_save(flags); + + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC); + if (gpio) /* GPIO: set bit to 0 */ + x &= ~enable[pin]; + else /* Internal function: set bit to 1 */ + x |= enable[pin]; + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC); + + local_irq_restore(flags); +} + + +static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 }; + +/* + * Configure GPIO pin as external interrupt source. + */ +int ks8695_gpio_interrupt(unsigned int pin, unsigned int type) +{ + unsigned long x, flags; + + if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */ + return -EINVAL; + + local_irq_save(flags); + + /* set pin as input */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); + x &= ~IOPM(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM); + + local_irq_restore(flags); + + /* Set IRQ triggering type */ + irq_set_irq_type(gpio_irq[pin], type); + + /* enable interrupt mode */ + ks8695_gpio_mode(pin, 0); + + return 0; +} +EXPORT_SYMBOL(ks8695_gpio_interrupt); + + + +/* .... Generic GPIO interface .............................................. */ + +/* + * Configure the GPIO line as an input. + */ +static int ks8695_gpio_direction_input(struct gpio_chip *gc, unsigned int pin) +{ + unsigned long x, flags; + + if (pin > KS8695_GPIO_15) + return -EINVAL; + + /* set pin to GPIO mode */ + ks8695_gpio_mode(pin, 1); + + local_irq_save(flags); + + /* set pin as input */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); + x &= ~IOPM(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM); + + local_irq_restore(flags); + + return 0; +} + + +/* + * Configure the GPIO line as an output, with default state. + */ +static int ks8695_gpio_direction_output(struct gpio_chip *gc, + unsigned int pin, int state) +{ + unsigned long x, flags; + + if (pin > KS8695_GPIO_15) + return -EINVAL; + + /* set pin to GPIO mode */ + ks8695_gpio_mode(pin, 1); + + local_irq_save(flags); + + /* set line state */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); + if (state) + x |= IOPD(pin); + else + x &= ~IOPD(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD); + + /* set pin as output */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); + x |= IOPM(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM); + + local_irq_restore(flags); + + return 0; +} + + +/* + * Set the state of an output GPIO line. + */ +static void ks8695_gpio_set_value(struct gpio_chip *gc, + unsigned int pin, int state) +{ + unsigned long x, flags; + + if (pin > KS8695_GPIO_15) + return; + + local_irq_save(flags); + + /* set output line state */ + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); + if (state) + x |= IOPD(pin); + else + x &= ~IOPD(pin); + __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD); + + local_irq_restore(flags); +} + + +/* + * Read the state of a GPIO line. + */ +static int ks8695_gpio_get_value(struct gpio_chip *gc, unsigned int pin) +{ + unsigned long x; + + if (pin > KS8695_GPIO_15) + return -EINVAL; + + x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); + return (x & IOPD(pin)) != 0; +} + + +/* + * Map GPIO line to IRQ number. + */ +static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin) +{ + if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */ + return -EINVAL; + + return gpio_irq[pin]; +} + +/* + * Map IRQ number to GPIO line. + */ +int irq_to_gpio(unsigned int irq) +{ + if ((irq < KS8695_IRQ_EXTERN0) || (irq > KS8695_IRQ_EXTERN3)) + return -EINVAL; + + return (irq - KS8695_IRQ_EXTERN0); +} +EXPORT_SYMBOL(irq_to_gpio); + +/* GPIOLIB interface */ + +static struct gpio_chip ks8695_gpio_chip = { + .label = "KS8695", + .direction_input = ks8695_gpio_direction_input, + .direction_output = ks8695_gpio_direction_output, + .get = ks8695_gpio_get_value, + .set = ks8695_gpio_set_value, + .to_irq = ks8695_gpio_to_irq, + .base = 0, + .ngpio = 16, + .can_sleep = 0, +}; + +/* Register the GPIOs */ +void ks8695_register_gpios(void) +{ + if (gpiochip_add(&ks8695_gpio_chip)) + printk(KERN_ERR "Unable to register core GPIOs\n"); +} + +/* .... Debug interface ..................................................... */ + +#ifdef CONFIG_DEBUG_FS + +static int ks8695_gpio_show(struct seq_file *s, void *unused) +{ + unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN }; + unsigned int intmask[] = { IOPC_IOEINT0TM, IOPC_IOEINT1TM, IOPC_IOEINT2TM, IOPC_IOEINT3TM }; + unsigned long mode, ctrl, data; + int i; + + mode = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM); + ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC); + data = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD); + + seq_printf(s, "Pin\tI/O\tFunction\tState\n\n"); + + for (i = KS8695_GPIO_0; i <= KS8695_GPIO_15 ; i++) { + seq_printf(s, "%i:\t", i); + + seq_printf(s, "%s\t", (mode & IOPM(i)) ? "Output" : "Input"); + + if (i <= KS8695_GPIO_3) { + if (ctrl & enable[i]) { + seq_printf(s, "EXT%i ", i); + + switch ((ctrl & intmask[i]) >> (4 * i)) { + case IOPC_TM_LOW: + seq_printf(s, "(Low)"); break; + case IOPC_TM_HIGH: + seq_printf(s, "(High)"); break; + case IOPC_TM_RISING: + seq_printf(s, "(Rising)"); break; + case IOPC_TM_FALLING: + seq_printf(s, "(Falling)"); break; + case IOPC_TM_EDGE: + seq_printf(s, "(Edges)"); break; + } + } + else + seq_printf(s, "GPIO\t"); + } + else if (i <= KS8695_GPIO_5) { + if (ctrl & enable[i]) + seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4); + else + seq_printf(s, "GPIO\t"); + } + else + seq_printf(s, "GPIO\t"); + + seq_printf(s, "\t"); + + seq_printf(s, "%i\n", (data & IOPD(i)) ? 1 : 0); + } + return 0; +} + +static int ks8695_gpio_open(struct inode *inode, struct file *file) +{ + return single_open(file, ks8695_gpio_show, NULL); +} + +static const struct file_operations ks8695_gpio_operations = { + .open = ks8695_gpio_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init ks8695_gpio_debugfs_init(void) +{ + /* /sys/kernel/debug/ks8695_gpio */ + (void) debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL, &ks8695_gpio_operations); + return 0; +} +postcore_initcall(ks8695_gpio_debugfs_init); + +#endif diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c index d2eb57c..00692e8 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c @@ -59,6 +59,7 @@ enum GPIO_REG { GRER, /* rising edge detect */ GFER, /* falling edge detect */ GEDR, /* edge detect result */ + GAFR, /* alt function */ }; struct lnw_gpio { @@ -81,6 +82,31 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, return ptr; } +static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, + enum GPIO_REG reg_type) +{ + struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); + unsigned nreg = chip->ngpio / 32; + u8 reg = offset / 16; + void __iomem *ptr; + + ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4); + return ptr; +} + +static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); + u32 value = readl(gafr); + int shift = (offset % 16) << 1, af = (value >> shift) & 3; + + if (af) { + value &= ~(3 << shift); + writel(value, gafr); + } + return 0; +} + static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset) { void __iomem *gplr = gpio_reg(chip, offset, GPLR); @@ -321,6 +347,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, lnw->reg_base = base; lnw->irq_base = irq_base; lnw->chip.label = dev_name(&pdev->dev); + lnw->chip.request = lnw_gpio_request; lnw->chip.direction_input = lnw_gpio_direction_input; lnw->chip.direction_output = lnw_gpio_direction_output; lnw->chip.get = lnw_gpio_get; diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c new file mode 100644 index 0000000..5b69480 --- /dev/null +++ b/drivers/gpio/gpio-lpc32xx.c @@ -0,0 +1,446 @@ +/* + * arch/arm/mach-lpc32xx/gpiolib.c + * + * Author: Kevin Wells <kevin.wells@nxp.com> + * + * Copyright (C) 2010 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/errno.h> +#include <linux/gpio.h> + +#include <mach/hardware.h> +#include <mach/platform.h> +#include <mach/gpio-lpc32xx.h> + +#define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000) +#define LPC32XX_GPIO_P3_OUTP_SET _GPREG(0x004) +#define LPC32XX_GPIO_P3_OUTP_CLR _GPREG(0x008) +#define LPC32XX_GPIO_P3_OUTP_STATE _GPREG(0x00C) +#define LPC32XX_GPIO_P2_DIR_SET _GPREG(0x010) +#define LPC32XX_GPIO_P2_DIR_CLR _GPREG(0x014) +#define LPC32XX_GPIO_P2_DIR_STATE _GPREG(0x018) +#define LPC32XX_GPIO_P2_INP_STATE _GPREG(0x01C) +#define LPC32XX_GPIO_P2_OUTP_SET _GPREG(0x020) +#define LPC32XX_GPIO_P2_OUTP_CLR _GPREG(0x024) +#define LPC32XX_GPIO_P2_MUX_SET _GPREG(0x028) +#define LPC32XX_GPIO_P2_MUX_CLR _GPREG(0x02C) +#define LPC32XX_GPIO_P2_MUX_STATE _GPREG(0x030) +#define LPC32XX_GPIO_P0_INP_STATE _GPREG(0x040) +#define LPC32XX_GPIO_P0_OUTP_SET _GPREG(0x044) +#define LPC32XX_GPIO_P0_OUTP_CLR _GPREG(0x048) +#define LPC32XX_GPIO_P0_OUTP_STATE _GPREG(0x04C) +#define LPC32XX_GPIO_P0_DIR_SET _GPREG(0x050) +#define LPC32XX_GPIO_P0_DIR_CLR _GPREG(0x054) +#define LPC32XX_GPIO_P0_DIR_STATE _GPREG(0x058) +#define LPC32XX_GPIO_P1_INP_STATE _GPREG(0x060) +#define LPC32XX_GPIO_P1_OUTP_SET _GPREG(0x064) +#define LPC32XX_GPIO_P1_OUTP_CLR _GPREG(0x068) +#define LPC32XX_GPIO_P1_OUTP_STATE _GPREG(0x06C) +#define LPC32XX_GPIO_P1_DIR_SET _GPREG(0x070) +#define LPC32XX_GPIO_P1_DIR_CLR _GPREG(0x074) +#define LPC32XX_GPIO_P1_DIR_STATE _GPREG(0x078) + +#define GPIO012_PIN_TO_BIT(x) (1 << (x)) +#define GPIO3_PIN_TO_BIT(x) (1 << ((x) + 25)) +#define GPO3_PIN_TO_BIT(x) (1 << (x)) +#define GPIO012_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) +#define GPIO3_PIN_IN_SHIFT(x) ((x) == 5 ? 24 : 10 + (x)) +#define GPIO3_PIN_IN_SEL(x, y) ((x) >> GPIO3_PIN_IN_SHIFT(y)) +#define GPIO3_PIN5_IN_SEL(x) (((x) >> 24) & 1) +#define GPI3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1) + +struct gpio_regs { + void __iomem *inp_state; + void __iomem *outp_set; + void __iomem *outp_clr; + void __iomem *dir_set; + void __iomem *dir_clr; +}; + +/* + * GPIO names + */ +static const char *gpio_p0_names[LPC32XX_GPIO_P0_MAX] = { + "p0.0", "p0.1", "p0.2", "p0.3", + "p0.4", "p0.5", "p0.6", "p0.7" +}; + +static const char *gpio_p1_names[LPC32XX_GPIO_P1_MAX] = { + "p1.0", "p1.1", "p1.2", "p1.3", + "p1.4", "p1.5", "p1.6", "p1.7", + "p1.8", "p1.9", "p1.10", "p1.11", + "p1.12", "p1.13", "p1.14", "p1.15", + "p1.16", "p1.17", "p1.18", "p1.19", + "p1.20", "p1.21", "p1.22", "p1.23", +}; + +static const char *gpio_p2_names[LPC32XX_GPIO_P2_MAX] = { + "p2.0", "p2.1", "p2.2", "p2.3", + "p2.4", "p2.5", "p2.6", "p2.7", + "p2.8", "p2.9", "p2.10", "p2.11", + "p2.12" +}; + +static const char *gpio_p3_names[LPC32XX_GPIO_P3_MAX] = { + "gpi000", "gpio01", "gpio02", "gpio03", + "gpio04", "gpio05" +}; + +static const char *gpi_p3_names[LPC32XX_GPI_P3_MAX] = { + "gpi00", "gpi01", "gpi02", "gpi03", + "gpi04", "gpi05", "gpi06", "gpi07", + "gpi08", "gpi09", NULL, NULL, + NULL, NULL, NULL, "gpi15", + "gpi16", "gpi17", "gpi18", "gpi19", + "gpi20", "gpi21", "gpi22", "gpi23", + "gpi24", "gpi25", "gpi26", "gpi27" +}; + +static const char *gpo_p3_names[LPC32XX_GPO_P3_MAX] = { + "gpo00", "gpo01", "gpo02", "gpo03", + "gpo04", "gpo05", "gpo06", "gpo07", + "gpo08", "gpo09", "gpo10", "gpo11", + "gpo12", "gpo13", "gpo14", "gpo15", + "gpo16", "gpo17", "gpo18", "gpo19", + "gpo20", "gpo21", "gpo22", "gpo23" +}; + +static struct gpio_regs gpio_grp_regs_p0 = { + .inp_state = LPC32XX_GPIO_P0_INP_STATE, + .outp_set = LPC32XX_GPIO_P0_OUTP_SET, + .outp_clr = LPC32XX_GPIO_P0_OUTP_CLR, + .dir_set = LPC32XX_GPIO_P0_DIR_SET, + .dir_clr = LPC32XX_GPIO_P0_DIR_CLR, +}; + +static struct gpio_regs gpio_grp_regs_p1 = { + .inp_state = LPC32XX_GPIO_P1_INP_STATE, + .outp_set = LPC32XX_GPIO_P1_OUTP_SET, + .outp_clr = LPC32XX_GPIO_P1_OUTP_CLR, + .dir_set = LPC32XX_GPIO_P1_DIR_SET, + .dir_clr = LPC32XX_GPIO_P1_DIR_CLR, +}; + +static struct gpio_regs gpio_grp_regs_p2 = { + .inp_state = LPC32XX_GPIO_P2_INP_STATE, + .outp_set = LPC32XX_GPIO_P2_OUTP_SET, + .outp_clr = LPC32XX_GPIO_P2_OUTP_CLR, + .dir_set = LPC32XX_GPIO_P2_DIR_SET, + .dir_clr = LPC32XX_GPIO_P2_DIR_CLR, +}; + +static struct gpio_regs gpio_grp_regs_p3 = { + .inp_state = LPC32XX_GPIO_P3_INP_STATE, + .outp_set = LPC32XX_GPIO_P3_OUTP_SET, + .outp_clr = LPC32XX_GPIO_P3_OUTP_CLR, + .dir_set = LPC32XX_GPIO_P2_DIR_SET, + .dir_clr = LPC32XX_GPIO_P2_DIR_CLR, +}; + +struct lpc32xx_gpio_chip { + struct gpio_chip chip; + struct gpio_regs *gpio_grp; +}; + +static inline struct lpc32xx_gpio_chip *to_lpc32xx_gpio( + struct gpio_chip *gpc) +{ + return container_of(gpc, struct lpc32xx_gpio_chip, chip); +} + +static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group, + unsigned pin, int input) +{ + if (input) + __raw_writel(GPIO012_PIN_TO_BIT(pin), + group->gpio_grp->dir_clr); + else + __raw_writel(GPIO012_PIN_TO_BIT(pin), + group->gpio_grp->dir_set); +} + +static void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group, + unsigned pin, int input) +{ + u32 u = GPIO3_PIN_TO_BIT(pin); + + if (input) + __raw_writel(u, group->gpio_grp->dir_clr); + else + __raw_writel(u, group->gpio_grp->dir_set); +} + +static void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group, + unsigned pin, int high) +{ + if (high) + __raw_writel(GPIO012_PIN_TO_BIT(pin), + group->gpio_grp->outp_set); + else + __raw_writel(GPIO012_PIN_TO_BIT(pin), + group->gpio_grp->outp_clr); +} + +static void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group, + unsigned pin, int high) +{ + u32 u = GPIO3_PIN_TO_BIT(pin); + + if (high) + __raw_writel(u, group->gpio_grp->outp_set); + else + __raw_writel(u, group->gpio_grp->outp_clr); +} + +static void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group, + unsigned pin, int high) +{ + if (high) + __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set); + else + __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr); +} + +static int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group, + unsigned pin) +{ + return GPIO012_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), + pin); +} + +static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group, + unsigned pin) +{ + int state = __raw_readl(group->gpio_grp->inp_state); + + /* + * P3 GPIO pin input mapping is not contiguous, GPIOP3-0..4 is mapped + * to bits 10..14, while GPIOP3-5 is mapped to bit 24. + */ + return GPIO3_PIN_IN_SEL(state, pin); +} + +static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group, + unsigned pin) +{ + return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin); +} + +/* + * GENERIC_GPIO primitives. + */ +static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip, + unsigned pin) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + __set_gpio_dir_p012(group, pin, 1); + + return 0; +} + +static int lpc32xx_gpio_dir_input_p3(struct gpio_chip *chip, + unsigned pin) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + __set_gpio_dir_p3(group, pin, 1); + + return 0; +} + +static int lpc32xx_gpio_dir_in_always(struct gpio_chip *chip, + unsigned pin) +{ + return 0; +} + +static int lpc32xx_gpio_get_value_p012(struct gpio_chip *chip, unsigned pin) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + return __get_gpio_state_p012(group, pin); +} + +static int lpc32xx_gpio_get_value_p3(struct gpio_chip *chip, unsigned pin) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + return __get_gpio_state_p3(group, pin); +} + +static int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + return __get_gpi_state_p3(group, pin); +} + +static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin, + int value) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + __set_gpio_dir_p012(group, pin, 0); + + return 0; +} + +static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin, + int value) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + __set_gpio_dir_p3(group, pin, 0); + + return 0; +} + +static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin, + int value) +{ + return 0; +} + +static void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin, + int value) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + __set_gpio_level_p012(group, pin, value); +} + +static void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin, + int value) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + __set_gpio_level_p3(group, pin, value); +} + +static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin, + int value) +{ + struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip); + + __set_gpo_level_p3(group, pin, value); +} + +static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin) +{ + if (pin < chip->ngpio) + return 0; + + return -EINVAL; +} + +static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { + { + .chip = { + .label = "gpio_p0", + .direction_input = lpc32xx_gpio_dir_input_p012, + .get = lpc32xx_gpio_get_value_p012, + .direction_output = lpc32xx_gpio_dir_output_p012, + .set = lpc32xx_gpio_set_value_p012, + .request = lpc32xx_gpio_request, + .base = LPC32XX_GPIO_P0_GRP, + .ngpio = LPC32XX_GPIO_P0_MAX, + .names = gpio_p0_names, + .can_sleep = 0, + }, + .gpio_grp = &gpio_grp_regs_p0, + }, + { + .chip = { + .label = "gpio_p1", + .direction_input = lpc32xx_gpio_dir_input_p012, + .get = lpc32xx_gpio_get_value_p012, + .direction_output = lpc32xx_gpio_dir_output_p012, + .set = lpc32xx_gpio_set_value_p012, + .request = lpc32xx_gpio_request, + .base = LPC32XX_GPIO_P1_GRP, + .ngpio = LPC32XX_GPIO_P1_MAX, + .names = gpio_p1_names, + .can_sleep = 0, + }, + .gpio_grp = &gpio_grp_regs_p1, + }, + { + .chip = { + .label = "gpio_p2", + .direction_input = lpc32xx_gpio_dir_input_p012, + .get = lpc32xx_gpio_get_value_p012, + .direction_output = lpc32xx_gpio_dir_output_p012, + .set = lpc32xx_gpio_set_value_p012, + .request = lpc32xx_gpio_request, + .base = LPC32XX_GPIO_P2_GRP, + .ngpio = LPC32XX_GPIO_P2_MAX, + .names = gpio_p2_names, + .can_sleep = 0, + }, + .gpio_grp = &gpio_grp_regs_p2, + }, + { + .chip = { + .label = "gpio_p3", + .direction_input = lpc32xx_gpio_dir_input_p3, + .get = lpc32xx_gpio_get_value_p3, + .direction_output = lpc32xx_gpio_dir_output_p3, + .set = lpc32xx_gpio_set_value_p3, + .request = lpc32xx_gpio_request, + .base = LPC32XX_GPIO_P3_GRP, + .ngpio = LPC32XX_GPIO_P3_MAX, + .names = gpio_p3_names, + .can_sleep = 0, + }, + .gpio_grp = &gpio_grp_regs_p3, + }, + { + .chip = { + .label = "gpi_p3", + .direction_input = lpc32xx_gpio_dir_in_always, + .get = lpc32xx_gpi_get_value, + .request = lpc32xx_gpio_request, + .base = LPC32XX_GPI_P3_GRP, + .ngpio = LPC32XX_GPI_P3_MAX, + .names = gpi_p3_names, + .can_sleep = 0, + }, + .gpio_grp = &gpio_grp_regs_p3, + }, + { + .chip = { + .label = "gpo_p3", + .direction_output = lpc32xx_gpio_dir_out_always, + .set = lpc32xx_gpo_set_value, + .request = lpc32xx_gpio_request, + .base = LPC32XX_GPO_P3_GRP, + .ngpio = LPC32XX_GPO_P3_MAX, + .names = gpo_p3_names, + .can_sleep = 0, + }, + .gpio_grp = &gpio_grp_regs_p3, + }, +}; + +void __init lpc32xx_gpio_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) + gpiochip_add(&lpc32xx_gpiochip[i].chip); +} diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index a9016f5..3aa6bee 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -18,6 +18,17 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + +#define IOH_EDGE_FALLING 0 +#define IOH_EDGE_RISING BIT(0) +#define IOH_LEVEL_L BIT(1) +#define IOH_LEVEL_H (BIT(0) | BIT(1)) +#define IOH_EDGE_BOTH BIT(2) +#define IOH_IM_MASK (BIT(0) | BIT(1) | BIT(2)) + +#define IOH_IRQ_BASE 0 #define PCI_VENDOR_ID_ROHM 0x10DB @@ -46,12 +57,22 @@ struct ioh_regs { /** * struct ioh_gpio_reg_data - The register store data. + * @ien_reg To store contents of interrupt enable register. + * @imask_reg: To store contents of interrupt mask regist * @po_reg: To store contents of PO register. * @pm_reg: To store contents of PM register. + * @im0_reg: To store contents of interrupt mode regist0 + * @im1_reg: To store contents of interrupt mode regist1 + * @use_sel_reg: To store contents of GPIO_USE_SEL0~3 */ struct ioh_gpio_reg_data { + u32 ien_reg; + u32 imask_reg; u32 po_reg; u32 pm_reg; + u32 im0_reg; + u32 im1_reg; + u32 use_sel_reg; }; /** @@ -62,7 +83,11 @@ struct ioh_gpio_reg_data { * @gpio: Data for GPIO infrastructure. * @ioh_gpio_reg: Memory mapped Register data is saved here * when suspend. + * @gpio_use_sel: Save GPIO_USE_SEL1~4 register for PM * @ch: Indicate GPIO channel + * @irq_base: Save base of IRQ number for interrupt + * @spinlock: Used for register access protection in + * interrupt context ioh_irq_type and PM; */ struct ioh_gpio { void __iomem *base; @@ -70,8 +95,11 @@ struct ioh_gpio { struct device *dev; struct gpio_chip gpio; struct ioh_gpio_reg_data ioh_gpio_reg; + u32 gpio_use_sel; struct mutex lock; int ch; + int irq_base; + spinlock_t spinlock; }; static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12}; @@ -145,8 +173,25 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) */ static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip) { - chip->ioh_gpio_reg.po_reg = ioread32(&chip->reg->regs[chip->ch].po); - chip->ioh_gpio_reg.pm_reg = ioread32(&chip->reg->regs[chip->ch].pm); + int i; + + for (i = 0; i < 8; i ++, chip++) { + chip->ioh_gpio_reg.po_reg = + ioread32(&chip->reg->regs[chip->ch].po); + chip->ioh_gpio_reg.pm_reg = + ioread32(&chip->reg->regs[chip->ch].pm); + chip->ioh_gpio_reg.ien_reg = + ioread32(&chip->reg->regs[chip->ch].ien); + chip->ioh_gpio_reg.imask_reg = + ioread32(&chip->reg->regs[chip->ch].imask); + chip->ioh_gpio_reg.im0_reg = + ioread32(&chip->reg->regs[chip->ch].im_0); + chip->ioh_gpio_reg.im1_reg = + ioread32(&chip->reg->regs[chip->ch].im_1); + if (i < 4) + chip->ioh_gpio_reg.use_sel_reg = + ioread32(&chip->reg->ioh_sel_reg[i]); + } } /* @@ -154,13 +199,34 @@ static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip) */ static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip) { - /* to store contents of PO register */ - iowrite32(chip->ioh_gpio_reg.po_reg, &chip->reg->regs[chip->ch].po); - /* to store contents of PM register */ - iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm); + int i; + + for (i = 0; i < 8; i ++, chip++) { + iowrite32(chip->ioh_gpio_reg.po_reg, + &chip->reg->regs[chip->ch].po); + iowrite32(chip->ioh_gpio_reg.pm_reg, + &chip->reg->regs[chip->ch].pm); + iowrite32(chip->ioh_gpio_reg.ien_reg, + &chip->reg->regs[chip->ch].ien); + iowrite32(chip->ioh_gpio_reg.imask_reg, + &chip->reg->regs[chip->ch].imask); + iowrite32(chip->ioh_gpio_reg.im0_reg, + &chip->reg->regs[chip->ch].im_0); + iowrite32(chip->ioh_gpio_reg.im1_reg, + &chip->reg->regs[chip->ch].im_1); + if (i < 4) + iowrite32(chip->ioh_gpio_reg.use_sel_reg, + &chip->reg->ioh_sel_reg[i]); + } } #endif +static int ioh_gpio_to_irq(struct gpio_chip *gpio, unsigned offset) +{ + struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio); + return chip->irq_base + offset; +} + static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port) { struct gpio_chip *gpio = &chip->gpio; @@ -175,16 +241,148 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port) gpio->base = -1; gpio->ngpio = num_port; gpio->can_sleep = 0; + gpio->to_irq = ioh_gpio_to_irq; +} + +static int ioh_irq_type(struct irq_data *d, unsigned int type) +{ + u32 im; + u32 *im_reg; + u32 ien; + u32 im_pos; + int ch; + unsigned long flags; + u32 val; + int irq = d->irq; + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct ioh_gpio *chip = gc->private; + + ch = irq - chip->irq_base; + if (irq <= chip->irq_base + 7) { + im_reg = &chip->reg->regs[chip->ch].im_0; + im_pos = ch; + } else { + im_reg = &chip->reg->regs[chip->ch].im_1; + im_pos = ch - 8; + } + dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d type=%d\n", + __func__, irq, type, ch, im_pos, type); + + spin_lock_irqsave(&chip->spinlock, flags); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + val = IOH_EDGE_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + val = IOH_EDGE_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + val = IOH_EDGE_BOTH; + break; + case IRQ_TYPE_LEVEL_HIGH: + val = IOH_LEVEL_H; + break; + case IRQ_TYPE_LEVEL_LOW: + val = IOH_LEVEL_L; + break; + case IRQ_TYPE_PROBE: + goto end; + default: + dev_warn(chip->dev, "%s: unknown type(%dd)", + __func__, type); + goto end; + } + + /* Set interrupt mode */ + im = ioread32(im_reg) & ~(IOH_IM_MASK << (im_pos * 4)); + iowrite32(im | (val << (im_pos * 4)), im_reg); + + /* iclr */ + iowrite32(BIT(ch), &chip->reg->regs[chip->ch].iclr); + + /* IMASKCLR */ + iowrite32(BIT(ch), &chip->reg->regs[chip->ch].imaskclr); + + /* Enable interrupt */ + ien = ioread32(&chip->reg->regs[chip->ch].ien); + iowrite32(ien | BIT(ch), &chip->reg->regs[chip->ch].ien); +end: + spin_unlock_irqrestore(&chip->spinlock, flags); + + return 0; +} + +static void ioh_irq_unmask(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct ioh_gpio *chip = gc->private; + + iowrite32(1 << (d->irq - chip->irq_base), + &chip->reg->regs[chip->ch].imaskclr); +} + +static void ioh_irq_mask(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct ioh_gpio *chip = gc->private; + + iowrite32(1 << (d->irq - chip->irq_base), + &chip->reg->regs[chip->ch].imask); +} + +static irqreturn_t ioh_gpio_handler(int irq, void *dev_id) +{ + struct ioh_gpio *chip = dev_id; + u32 reg_val; + int i, j; + int ret = IRQ_NONE; + + for (i = 0; i < 8; i++) { + reg_val = ioread32(&chip->reg->regs[i].istatus); + for (j = 0; j < num_ports[i]; j++) { + if (reg_val & BIT(j)) { + dev_dbg(chip->dev, + "%s:[%d]:irq=%d status=0x%x\n", + __func__, j, irq, reg_val); + iowrite32(BIT(j), + &chip->reg->regs[chip->ch].iclr); + generic_handle_irq(chip->irq_base + j); + ret = IRQ_HANDLED; + } + } + } + return ret; +} + +static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, + unsigned int irq_start, unsigned int num) +{ + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + + gc = irq_alloc_generic_chip("ioh_gpio", 1, irq_start, chip->base, + handle_simple_irq); + gc->private = chip; + ct = gc->chip_types; + + ct->chip.irq_mask = ioh_irq_mask; + ct->chip.irq_unmask = ioh_irq_unmask; + ct->chip.irq_set_type = ioh_irq_type; + + irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, + IRQ_NOREQUEST | IRQ_NOPROBE, 0); } static int __devinit ioh_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int ret; - int i; + int i, j; struct ioh_gpio *chip; void __iomem *base; void __iomem *chip_save; + int irq_base; ret = pci_enable_device(pdev); if (ret) { @@ -228,10 +426,41 @@ static int __devinit 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); + if (irq_base < 0) { + dev_warn(&pdev->dev, + "ml_ioh_gpio: Failed to get IRQ base num\n"); + chip->irq_base = -1; + goto err_irq_alloc_descs; + } + 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); + if (ret != 0) { + dev_err(&pdev->dev, + "%s request_irq failed\n", __func__); + goto err_request_irq; + } + 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--; @@ -264,7 +493,11 @@ static void __devexit ioh_gpio_remove(struct pci_dev *pdev) void __iomem *chip_save; chip_save = chip; + + free_irq(pdev->irq, chip); + for (i = 0; i < 8; i++, chip++) { + irq_free_descs(chip->irq_base, num_ports[i]); err = gpiochip_remove(&chip->gpio); if (err) dev_err(&pdev->dev, "Failed gpiochip_remove\n"); @@ -282,9 +515,11 @@ static int ioh_gpio_suspend(struct pci_dev *pdev, pm_message_t state) { s32 ret; struct ioh_gpio *chip = pci_get_drvdata(pdev); + unsigned long flags; + spin_lock_irqsave(&chip->spinlock, flags); ioh_gpio_save_reg_conf(chip); - ioh_gpio_restore_reg_conf(chip); + spin_unlock_irqrestore(&chip->spinlock, flags); ret = pci_save_state(pdev); if (ret) { @@ -304,6 +539,7 @@ static int ioh_gpio_resume(struct pci_dev *pdev) { s32 ret; struct ioh_gpio *chip = pci_get_drvdata(pdev); + unsigned long flags; ret = pci_enable_wake(pdev, PCI_D0, 0); @@ -315,9 +551,11 @@ static int ioh_gpio_resume(struct pci_dev *pdev) } pci_restore_state(pdev); + spin_lock_irqsave(&chip->spinlock, flags); iowrite32(0x01, &chip->reg->srst); iowrite32(0x00, &chip->reg->srst); ioh_gpio_restore_reg_conf(chip); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 4340aca..b81c989 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -30,6 +30,9 @@ #include <linux/of.h> #include <linux/of_device.h> #include <asm-generic/bug.h> +#include <asm/mach/irq.h> + +#define irq_to_gpio(irq) ((irq) - MXC_GPIO_IRQ_START) enum mxc_gpio_hwtype { IMX1_GPIO, /* runs on i.mx1 */ @@ -232,10 +235,15 @@ static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_stat; struct mxc_gpio_port *port = irq_get_handler_data(irq); + struct irq_chip *chip = irq_get_chip(irq); + + chained_irq_enter(chip, desc); irq_stat = readl(port->base + GPIO_ISR) & readl(port->base + GPIO_IMR); mxc_gpio_irq_handler(port, irq_stat); + + chained_irq_exit(chip, desc); } /* MX2 has one interrupt *for all* gpio ports */ @@ -337,6 +345,15 @@ static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) mxc_gpio_hwtype = hwtype; } +static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + struct mxc_gpio_port *port = + container_of(bgc, struct mxc_gpio_port, bgc); + + return port->virtual_irq_start + offset; +} + static int __devinit mxc_gpio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -403,6 +420,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) if (err) goto out_iounmap; + port->bgc.gc.to_irq = mxc_gpio_to_irq; port->bgc.gc.base = pdev->id * 32; port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir); port->bgc.data = port->bgc.read_reg(port->bgc.reg_set); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index af55a85..292b504 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -49,6 +49,8 @@ #define GPIO_INT_LEV_MASK (1 << 0) #define GPIO_INT_POL_MASK (1 << 1) +#define irq_to_gpio(irq) ((irq) - MXS_GPIO_IRQ_START) + struct mxs_gpio_port { void __iomem *base; int id; diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/gpio/gpio-nomadik.c index 2c212c7..1ebedfb 100644 --- a/drivers/gpio/gpio-nomadik.c +++ b/drivers/gpio/gpio-nomadik.c @@ -27,8 +27,9 @@ #include <asm/mach/irq.h> #include <plat/pincfg.h> +#include <plat/gpio-nomadik.h> #include <mach/hardware.h> -#include <mach/gpio.h> +#include <asm/gpio.h> /* * The GPIO module in the Nomadik family of Systems-on-Chip is an @@ -58,7 +59,6 @@ struct nmk_gpio_chip { u32 rwimsc; u32 fwimsc; u32 slpm; - u32 enabled; u32 pull_up; }; @@ -276,6 +276,8 @@ static void nmk_gpio_glitch_slpm_init(unsigned int *slpm) if (!chip) break; + clk_enable(chip->clk); + slpm[i] = readl(chip->addr + NMK_GPIO_SLPC); writel(temp, chip->addr + NMK_GPIO_SLPC); } @@ -292,6 +294,8 @@ static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm) break; writel(slpm[i], chip->addr + NMK_GPIO_SLPC); + + clk_disable(chip->clk); } } @@ -336,10 +340,12 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep) break; } + clk_enable(nmk_chip->clk); spin_lock(&nmk_chip->lock); __nmk_config_pin(nmk_chip, pin - nmk_chip->chip.base, cfgs[i], sleep, glitch ? slpm : NULL); spin_unlock(&nmk_chip->lock); + clk_disable(nmk_chip->clk); } if (glitch) @@ -424,6 +430,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode) if (!nmk_chip) return -EINVAL; + clk_enable(nmk_chip->clk); spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); spin_lock(&nmk_chip->lock); @@ -431,6 +438,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode) spin_unlock(&nmk_chip->lock); spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + clk_disable(nmk_chip->clk); return 0; } @@ -457,9 +465,11 @@ int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull) if (!nmk_chip) return -EINVAL; + clk_enable(nmk_chip->clk); spin_lock_irqsave(&nmk_chip->lock, flags); __nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull); spin_unlock_irqrestore(&nmk_chip->lock, flags); + clk_disable(nmk_chip->clk); return 0; } @@ -483,9 +493,11 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode) if (!nmk_chip) return -EINVAL; + clk_enable(nmk_chip->clk); spin_lock_irqsave(&nmk_chip->lock, flags); __nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode); spin_unlock_irqrestore(&nmk_chip->lock, flags); + clk_disable(nmk_chip->clk); return 0; } @@ -502,9 +514,13 @@ int nmk_gpio_get_mode(int gpio) bit = 1 << (gpio - nmk_chip->chip.base); + clk_enable(nmk_chip->clk); + afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit; bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit; + clk_disable(nmk_chip->clk); + return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0); } EXPORT_SYMBOL(nmk_gpio_get_mode); @@ -525,7 +541,10 @@ static void nmk_gpio_irq_ack(struct irq_data *d) nmk_chip = irq_data_get_irq_chip_data(d); if (!nmk_chip) return; + + clk_enable(nmk_chip->clk); writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC); + clk_disable(nmk_chip->clk); } enum nmk_gpio_irq_type { @@ -586,11 +605,7 @@ static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable) if (!nmk_chip) return -EINVAL; - if (enable) - nmk_chip->enabled |= bitmask; - else - nmk_chip->enabled &= ~bitmask; - + clk_enable(nmk_chip->clk); spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); spin_lock(&nmk_chip->lock); @@ -601,6 +616,7 @@ static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable) spin_unlock(&nmk_chip->lock); spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + clk_disable(nmk_chip->clk); return 0; } @@ -628,10 +644,11 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on) return -EINVAL; bitmask = nmk_gpio_get_bitmask(gpio); + clk_enable(nmk_chip->clk); spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); spin_lock(&nmk_chip->lock); - if (!(nmk_chip->enabled & bitmask)) + if (irqd_irq_disabled(d)) __nmk_gpio_set_wake(nmk_chip, gpio, on); if (on) @@ -641,13 +658,15 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on) spin_unlock(&nmk_chip->lock); spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); + clk_disable(nmk_chip->clk); return 0; } static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - bool enabled, wake = irqd_is_wakeup_set(d); + bool enabled = !irqd_irq_disabled(d); + bool wake = irqd_is_wakeup_set(d); int gpio; struct nmk_gpio_chip *nmk_chip; unsigned long flags; @@ -664,8 +683,7 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type) if (type & IRQ_TYPE_LEVEL_LOW) return -EINVAL; - enabled = nmk_chip->enabled & bitmask; - + clk_enable(nmk_chip->clk); spin_lock_irqsave(&nmk_chip->lock, flags); if (enabled) @@ -689,10 +707,28 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type) __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true); spin_unlock_irqrestore(&nmk_chip->lock, flags); + clk_disable(nmk_chip->clk); return 0; } +static unsigned int nmk_gpio_irq_startup(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + + clk_enable(nmk_chip->clk); + nmk_gpio_irq_unmask(d); + return 0; +} + +static void nmk_gpio_irq_shutdown(struct irq_data *d) +{ + struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d); + + nmk_gpio_irq_mask(d); + clk_disable(nmk_chip->clk); +} + static struct irq_chip nmk_gpio_irq_chip = { .name = "Nomadik-GPIO", .irq_ack = nmk_gpio_irq_ack, @@ -700,6 +736,8 @@ static struct irq_chip nmk_gpio_irq_chip = { .irq_unmask = nmk_gpio_irq_unmask, .irq_set_type = nmk_gpio_irq_set_type, .irq_set_wake = nmk_gpio_irq_set_wake, + .irq_startup = nmk_gpio_irq_startup, + .irq_shutdown = nmk_gpio_irq_shutdown, }; static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, @@ -726,7 +764,11 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); - u32 status = readl(nmk_chip->addr + NMK_GPIO_IS); + u32 status; + + clk_enable(nmk_chip->clk); + status = readl(nmk_chip->addr + NMK_GPIO_IS); + clk_disable(nmk_chip->clk); __nmk_gpio_irq_handler(irq, desc, status); } @@ -772,7 +814,12 @@ static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset) struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); + clk_enable(nmk_chip->clk); + writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC); + + clk_disable(nmk_chip->clk); + return 0; } @@ -781,8 +828,15 @@ static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset) struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); u32 bit = 1 << offset; + int value; + + clk_enable(nmk_chip->clk); - return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0; + value = (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0; + + clk_disable(nmk_chip->clk); + + return value; } static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset, @@ -791,7 +845,11 @@ static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset, struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); + clk_enable(nmk_chip->clk); + __nmk_gpio_set_output(nmk_chip, offset, val); + + clk_disable(nmk_chip->clk); } static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, @@ -800,8 +858,12 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); + clk_enable(nmk_chip->clk); + __nmk_gpio_make_output(nmk_chip, offset, val); + clk_disable(nmk_chip->clk); + return 0; } @@ -832,6 +894,8 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) [NMK_GPIO_ALT_C] = "altC", }; + clk_enable(nmk_chip->clk); + for (i = 0; i < chip->ngpio; i++, gpio++) { const char *label = gpiochip_is_requested(chip, i); bool pull; @@ -876,6 +940,8 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_printf(s, "\n"); } + + clk_disable(nmk_chip->clk); } #else @@ -893,6 +959,34 @@ static struct gpio_chip nmk_gpio_template = { .can_sleep = 0, }; +void nmk_gpio_clocks_enable(void) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + + if (!chip) + continue; + + clk_enable(chip->clk); + } +} + +void nmk_gpio_clocks_disable(void) +{ + int i; + + for (i = 0; i < NUM_BANKS; i++) { + struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; + + if (!chip) + continue; + + clk_disable(chip->clk); + } +} + /* * Called from the suspend/resume path to only keep the real wakeup interrupts * (those that have had set_irq_wake() called on them) as wakeup interrupts, @@ -912,6 +1006,8 @@ void nmk_gpio_wakeups_suspend(void) if (!chip) break; + clk_enable(chip->clk); + chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC); chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC); @@ -926,6 +1022,8 @@ void nmk_gpio_wakeups_suspend(void) /* 0 -> wakeup enable */ writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC); } + + clk_disable(chip->clk); } } @@ -939,11 +1037,15 @@ void nmk_gpio_wakeups_resume(void) if (!chip) break; + clk_enable(chip->clk); + writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC); writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC); if (chip->sleepmode) writel(chip->slpm, chip->addr + NMK_GPIO_SLPC); + + clk_disable(chip->clk); } } @@ -1010,8 +1112,6 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) goto out_release; } - clk_enable(clk); - nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL); if (!nmk_chip) { ret = -ENOMEM; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 118ec12..0e49d87 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -25,7 +25,7 @@ #include <mach/hardware.h> #include <asm/irq.h> #include <mach/irqs.h> -#include <mach/gpio.h> +#include <asm/gpio.h> #include <asm/mach/irq.h> struct gpio_bank { diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 36919e7..1e8a4a5 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -17,9 +17,17 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/irq.h> -#define PCH_GPIO_ALL_PINS 0xfff /* Mask for GPIO pins 0 to 11 */ -#define GPIO_NUM_PINS 12 /* Specifies number of GPIO PINS GPIO0-GPIO11 */ +#define PCH_EDGE_FALLING 0 +#define PCH_EDGE_RISING BIT(0) +#define PCH_LEVEL_L BIT(1) +#define PCH_LEVEL_H (BIT(0) | BIT(1)) +#define PCH_EDGE_BOTH BIT(2) +#define PCH_IM_MASK (BIT(0) | BIT(1) | BIT(2)) + +#define PCH_IRQ_BASE 24 struct pch_regs { u32 ien; @@ -33,18 +41,43 @@ struct pch_regs { u32 pm; u32 im0; u32 im1; - u32 reserved[4]; + u32 reserved[3]; + u32 gpio_use_sel; u32 reset; }; +enum pch_type_t { + INTEL_EG20T_PCH, + OKISEMI_ML7223m_IOH, /* OKISEMI ML7223 IOH PCIe Bus-m */ + OKISEMI_ML7223n_IOH /* OKISEMI ML7223 IOH PCIe Bus-n */ +}; + +/* Specifies number of GPIO PINS */ +static int gpio_pins[] = { + [INTEL_EG20T_PCH] = 12, + [OKISEMI_ML7223m_IOH] = 8, + [OKISEMI_ML7223n_IOH] = 8, +}; + /** * struct pch_gpio_reg_data - The register store data. + * @ien_reg: To store contents of IEN register. + * @imask_reg: To store contents of IMASK register. * @po_reg: To store contents of PO register. * @pm_reg: To store contents of PM register. + * @im0_reg: To store contents of IM0 register. + * @im1_reg: To store contents of IM1 register. + * @gpio_use_sel_reg : To store contents of GPIO_USE_SEL register. + * (Only ML7223 Bus-n) */ struct pch_gpio_reg_data { + u32 ien_reg; + u32 imask_reg; u32 po_reg; u32 pm_reg; + u32 im0_reg; + u32 im1_reg; + u32 gpio_use_sel_reg; }; /** @@ -55,6 +88,12 @@ struct pch_gpio_reg_data { * @gpio: Data for GPIO infrastructure. * @pch_gpio_reg: Memory mapped Register data is saved here * when suspend. + * @lock: Used for register access protection + * @irq_base: Save base of IRQ number for interrupt + * @ioh: IOH ID + * @spinlock: Used for register access protection in + * interrupt context pch_irq_mask, + * pch_irq_unmask and pch_irq_type; */ struct pch_gpio { void __iomem *base; @@ -63,6 +102,9 @@ struct pch_gpio { struct gpio_chip gpio; struct pch_gpio_reg_data pch_gpio_reg; struct mutex lock; + int irq_base; + enum pch_type_t ioh; + spinlock_t spinlock; }; static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val) @@ -96,7 +138,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, u32 reg_val; mutex_lock(&chip->lock); - pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS; + pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); pm |= (1 << nr); iowrite32(pm, &chip->reg->pm); @@ -118,7 +160,7 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) u32 pm; mutex_lock(&chip->lock); - pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS; /*bits 0-11*/ + pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1); pm &= ~(1 << nr); iowrite32(pm, &chip->reg->pm); mutex_unlock(&chip->lock); @@ -131,8 +173,16 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) */ static void pch_gpio_save_reg_conf(struct pch_gpio *chip) { + chip->pch_gpio_reg.ien_reg = ioread32(&chip->reg->ien); + chip->pch_gpio_reg.imask_reg = ioread32(&chip->reg->imask); chip->pch_gpio_reg.po_reg = ioread32(&chip->reg->po); chip->pch_gpio_reg.pm_reg = ioread32(&chip->reg->pm); + chip->pch_gpio_reg.im0_reg = ioread32(&chip->reg->im0); + if (chip->ioh == INTEL_EG20T_PCH) + chip->pch_gpio_reg.im1_reg = ioread32(&chip->reg->im1); + if (chip->ioh == OKISEMI_ML7223n_IOH) + chip->pch_gpio_reg.gpio_use_sel_reg =\ + ioread32(&chip->reg->gpio_use_sel); } /* @@ -140,10 +190,24 @@ static void pch_gpio_save_reg_conf(struct pch_gpio *chip) */ static void pch_gpio_restore_reg_conf(struct pch_gpio *chip) { + iowrite32(chip->pch_gpio_reg.ien_reg, &chip->reg->ien); + iowrite32(chip->pch_gpio_reg.imask_reg, &chip->reg->imask); /* to store contents of PO register */ iowrite32(chip->pch_gpio_reg.po_reg, &chip->reg->po); /* to store contents of PM register */ iowrite32(chip->pch_gpio_reg.pm_reg, &chip->reg->pm); + iowrite32(chip->pch_gpio_reg.im0_reg, &chip->reg->im0); + if (chip->ioh == INTEL_EG20T_PCH) + iowrite32(chip->pch_gpio_reg.im1_reg, &chip->reg->im1); + if (chip->ioh == OKISEMI_ML7223n_IOH) + iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg, + &chip->reg->gpio_use_sel); +} + +static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset) +{ + struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio); + return chip->irq_base + offset; } static void pch_gpio_setup(struct pch_gpio *chip) @@ -158,8 +222,132 @@ static void pch_gpio_setup(struct pch_gpio *chip) gpio->set = pch_gpio_set; gpio->dbg_show = NULL; gpio->base = -1; - gpio->ngpio = GPIO_NUM_PINS; + gpio->ngpio = gpio_pins[chip->ioh]; gpio->can_sleep = 0; + gpio->to_irq = pch_gpio_to_irq; +} + +static int pch_irq_type(struct irq_data *d, unsigned int type) +{ + u32 im; + u32 *im_reg; + u32 ien; + u32 im_pos; + int ch; + unsigned long flags; + u32 val; + int irq = d->irq; + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct pch_gpio *chip = gc->private; + + ch = irq - chip->irq_base; + if (irq <= chip->irq_base + 7) { + im_reg = &chip->reg->im0; + im_pos = ch; + } else { + im_reg = &chip->reg->im1; + im_pos = ch - 8; + } + dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d\n", + __func__, irq, type, ch, im_pos); + + spin_lock_irqsave(&chip->spinlock, flags); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + val = PCH_EDGE_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + val = PCH_EDGE_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + val = PCH_EDGE_BOTH; + break; + case IRQ_TYPE_LEVEL_HIGH: + val = PCH_LEVEL_H; + break; + case IRQ_TYPE_LEVEL_LOW: + val = PCH_LEVEL_L; + break; + case IRQ_TYPE_PROBE: + goto end; + default: + dev_warn(chip->dev, "%s: unknown type(%dd)", + __func__, type); + goto end; + } + + /* Set interrupt mode */ + im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4)); + iowrite32(im | (val << (im_pos * 4)), im_reg); + + /* iclr */ + iowrite32(BIT(ch), &chip->reg->iclr); + + /* IMASKCLR */ + iowrite32(BIT(ch), &chip->reg->imaskclr); + + /* Enable interrupt */ + ien = ioread32(&chip->reg->ien); + iowrite32(ien | BIT(ch), &chip->reg->ien); +end: + spin_unlock_irqrestore(&chip->spinlock, flags); + + return 0; +} + +static void pch_irq_unmask(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct pch_gpio *chip = gc->private; + + iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imaskclr); +} + +static void pch_irq_mask(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct pch_gpio *chip = gc->private; + + iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imask); +} + +static irqreturn_t pch_gpio_handler(int irq, void *dev_id) +{ + struct pch_gpio *chip = dev_id; + u32 reg_val = ioread32(&chip->reg->istatus); + int i; + int ret = IRQ_NONE; + + for (i = 0; i < gpio_pins[chip->ioh]; i++) { + if (reg_val & BIT(i)) { + dev_dbg(chip->dev, "%s:[%d]:irq=%d status=0x%x\n", + __func__, i, irq, reg_val); + iowrite32(BIT(i), &chip->reg->iclr); + generic_handle_irq(chip->irq_base + i); + ret = IRQ_HANDLED; + } + } + return ret; +} + +static __devinit void pch_gpio_alloc_generic_chip(struct pch_gpio *chip, + unsigned int irq_start, unsigned int num) +{ + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + + gc = irq_alloc_generic_chip("pch_gpio", 1, irq_start, chip->base, + handle_simple_irq); + gc->private = chip; + ct = gc->chip_types; + + ct->chip.irq_mask = pch_irq_mask; + ct->chip.irq_unmask = pch_irq_unmask; + ct->chip.irq_set_type = pch_irq_type; + + irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, + IRQ_NOREQUEST | IRQ_NOPROBE, 0); } static int __devinit pch_gpio_probe(struct pci_dev *pdev, @@ -167,6 +355,7 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev, { s32 ret; struct pch_gpio *chip; + int irq_base; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) @@ -192,6 +381,13 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev, goto err_iomap; } + if (pdev->device == 0x8803) + chip->ioh = INTEL_EG20T_PCH; + else if (pdev->device == 0x8014) + chip->ioh = OKISEMI_ML7223m_IOH; + else if (pdev->device == 0x8043) + chip->ioh = OKISEMI_ML7223n_IOH; + chip->reg = chip->base; pci_set_drvdata(pdev, chip); mutex_init(&chip->lock); @@ -202,8 +398,36 @@ static int __devinit 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); + if (irq_base < 0) { + dev_warn(&pdev->dev, "PCH gpio: Failed to get IRQ base num\n"); + chip->irq_base = -1; + goto end; + } + chip->irq_base = irq_base; + + ret = request_irq(pdev->irq, pch_gpio_handler, + IRQF_SHARED, KBUILD_MODNAME, chip); + if (ret != 0) { + dev_err(&pdev->dev, + "%s request_irq failed\n", __func__); + goto err_request_irq; + } + + pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]); + + /* Initialize interrupt ien register */ + iowrite32(0, &chip->reg->ien); +end: return 0; +err_request_irq: + irq_free_descs(irq_base, gpio_pins[chip->ioh]); + + ret = gpiochip_remove(&chip->gpio); + if (ret) + dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__); + err_gpiochip_add: pci_iounmap(pdev, chip->base); @@ -224,6 +448,12 @@ static void __devexit pch_gpio_remove(struct pci_dev *pdev) int err; 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]); + } + err = gpiochip_remove(&chip->gpio); if (err) dev_err(&pdev->dev, "Failed gpiochip_remove\n"); @@ -239,9 +469,11 @@ static int pch_gpio_suspend(struct pci_dev *pdev, pm_message_t state) { s32 ret; struct pch_gpio *chip = pci_get_drvdata(pdev); + unsigned long flags; + spin_lock_irqsave(&chip->spinlock, flags); pch_gpio_save_reg_conf(chip); - pch_gpio_restore_reg_conf(chip); + spin_unlock_irqrestore(&chip->spinlock, flags); ret = pci_save_state(pdev); if (ret) { @@ -261,6 +493,7 @@ static int pch_gpio_resume(struct pci_dev *pdev) { s32 ret; struct pch_gpio *chip = pci_get_drvdata(pdev); + unsigned long flags; ret = pci_enable_wake(pdev, PCI_D0, 0); @@ -272,9 +505,11 @@ static int pch_gpio_resume(struct pci_dev *pdev) } pci_restore_state(pdev); + spin_lock_irqsave(&chip->spinlock, flags); iowrite32(0x01, &chip->reg->reset); iowrite32(0x00, &chip->reg->reset); pch_gpio_restore_reg_conf(chip); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -287,6 +522,7 @@ static int pch_gpio_resume(struct pci_dev *pdev) static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) }, { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) }, + { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) }, { 0, } }; MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id); diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 2c5a18f..093c90b 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -118,7 +118,7 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset) { struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc); - if (chip->irq_base == (unsigned) -1) + if (chip->irq_base == NO_IRQ) return -EINVAL; return chip->irq_base + offset; @@ -246,6 +246,18 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) if (chip == NULL) return -ENOMEM; + pdata = dev->dev.platform_data; + if (pdata) { + chip->gc.base = pdata->gpio_base; + chip->irq_base = pdata->irq_base; + } else if (dev->dev.of_node) { + chip->gc.base = -1; + chip->irq_base = NO_IRQ; + } else { + ret = -ENODEV; + goto free_mem; + } + if (!request_mem_region(dev->res.start, resource_size(&dev->res), "pl061")) { ret = -EBUSY; @@ -267,14 +279,11 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) chip->gc.get = pl061_get_value; chip->gc.set = pl061_set_value; chip->gc.to_irq = pl061_to_irq; - chip->gc.base = pdata->gpio_base; chip->gc.ngpio = PL061_GPIO_NR; chip->gc.label = dev_name(&dev->dev); chip->gc.dev = &dev->dev; chip->gc.owner = THIS_MODULE; - chip->irq_base = pdata->irq_base; - ret = gpiochip_add(&chip->gc); if (ret) goto iounmap; @@ -283,7 +292,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) * irq_chip support */ - if (chip->irq_base == (unsigned) -1) + if (chip->irq_base == NO_IRQ) return 0; writeb(0, chip->base + GPIOIE); /* disable irqs */ @@ -307,11 +316,13 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) list_add(&chip->list, chip_list); for (i = 0; i < PL061_GPIO_NR; i++) { - if (pdata->directions & (1 << i)) - pl061_direction_output(&chip->gc, i, - pdata->values & (1 << i)); - else - pl061_direction_input(&chip->gc, i); + if (pdata) { + if (pdata->directions & (1 << i)) + pl061_direction_output(&chip->gc, i, + pdata->values & (1 << i)); + else + pl061_direction_input(&chip->gc, i); + } irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip, handle_simple_irq); diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c new file mode 100644 index 0000000..ee137712 --- /dev/null +++ b/drivers/gpio/gpio-pxa.c @@ -0,0 +1,338 @@ +/* + * linux/arch/arm/plat-pxa/gpio.c + * + * Generic PXA GPIO handling + * + * Author: Nicolas Pitre + * Created: Jun 15, 2001 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/syscore_ops.h> +#include <linux/slab.h> + +#include <mach/gpio-pxa.h> + +int pxa_last_gpio; + +struct pxa_gpio_chip { + struct gpio_chip chip; + void __iomem *regbase; + char label[10]; + + unsigned long irq_mask; + unsigned long irq_edge_rise; + unsigned long irq_edge_fall; + +#ifdef CONFIG_PM + unsigned long saved_gplr; + unsigned long saved_gpdr; + unsigned long saved_grer; + unsigned long saved_gfer; +#endif +}; + +static DEFINE_SPINLOCK(gpio_lock); +static struct pxa_gpio_chip *pxa_gpio_chips; + +#define for_each_gpio_chip(i, c) \ + for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++) + +static inline void __iomem *gpio_chip_base(struct gpio_chip *c) +{ + return container_of(c, struct pxa_gpio_chip, chip)->regbase; +} + +static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio) +{ + return &pxa_gpio_chips[gpio_to_bank(gpio)]; +} + +static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + void __iomem *base = gpio_chip_base(chip); + uint32_t value, mask = 1 << offset; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + + value = __raw_readl(base + GPDR_OFFSET); + if (__gpio_is_inverted(chip->base + offset)) + value |= mask; + else + value &= ~mask; + __raw_writel(value, base + GPDR_OFFSET); + + spin_unlock_irqrestore(&gpio_lock, flags); + return 0; +} + +static int pxa_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + void __iomem *base = gpio_chip_base(chip); + uint32_t tmp, mask = 1 << offset; + unsigned long flags; + + __raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET)); + + spin_lock_irqsave(&gpio_lock, flags); + + tmp = __raw_readl(base + GPDR_OFFSET); + if (__gpio_is_inverted(chip->base + offset)) + tmp &= ~mask; + else + tmp |= mask; + __raw_writel(tmp, base + GPDR_OFFSET); + + spin_unlock_irqrestore(&gpio_lock, flags); + return 0; +} + +static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset); +} + +static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + __raw_writel(1 << offset, gpio_chip_base(chip) + + (value ? GPSR_OFFSET : GPCR_OFFSET)); +} + +static int __init pxa_init_gpio_chip(int gpio_end) +{ + int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1; + struct pxa_gpio_chip *chips; + + chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL); + if (chips == NULL) { + pr_err("%s: failed to allocate GPIO chips\n", __func__); + return -ENOMEM; + } + + for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) { + struct gpio_chip *c = &chips[i].chip; + + sprintf(chips[i].label, "gpio-%d", i); + chips[i].regbase = GPIO_BANK(i); + + c->base = gpio; + c->label = chips[i].label; + + c->direction_input = pxa_gpio_direction_input; + c->direction_output = pxa_gpio_direction_output; + c->get = pxa_gpio_get; + c->set = pxa_gpio_set; + + /* number of GPIOs on last bank may be less than 32 */ + c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32; + gpiochip_add(c); + } + pxa_gpio_chips = chips; + return 0; +} + +/* Update only those GRERx and GFERx edge detection register bits if those + * bits are set in c->irq_mask + */ +static inline void update_edge_detect(struct pxa_gpio_chip *c) +{ + uint32_t grer, gfer; + + grer = __raw_readl(c->regbase + GRER_OFFSET) & ~c->irq_mask; + gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~c->irq_mask; + grer |= c->irq_edge_rise & c->irq_mask; + gfer |= c->irq_edge_fall & c->irq_mask; + __raw_writel(grer, c->regbase + GRER_OFFSET); + __raw_writel(gfer, c->regbase + GFER_OFFSET); +} + +static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type) +{ + struct pxa_gpio_chip *c; + int gpio = irq_to_gpio(d->irq); + unsigned long gpdr, mask = GPIO_bit(gpio); + + c = gpio_to_pxachip(gpio); + + if (type == IRQ_TYPE_PROBE) { + /* Don't mess with enabled GPIOs using preconfigured edges or + * GPIOs set to alternate function or to output during probe + */ + if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio)) + return 0; + + if (__gpio_is_occupied(gpio)) + return 0; + + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + + gpdr = __raw_readl(c->regbase + GPDR_OFFSET); + + if (__gpio_is_inverted(gpio)) + __raw_writel(gpdr | mask, c->regbase + GPDR_OFFSET); + else + __raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET); + + if (type & IRQ_TYPE_EDGE_RISING) + c->irq_edge_rise |= mask; + else + c->irq_edge_rise &= ~mask; + + if (type & IRQ_TYPE_EDGE_FALLING) + c->irq_edge_fall |= mask; + else + c->irq_edge_fall &= ~mask; + + update_edge_detect(c); + + pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio, + ((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""), + ((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : "")); + return 0; +} + +static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc) +{ + struct pxa_gpio_chip *c; + int loop, gpio, gpio_base, n; + unsigned long gedr; + + do { + loop = 0; + for_each_gpio_chip(gpio, c) { + gpio_base = c->chip.base; + + gedr = __raw_readl(c->regbase + GEDR_OFFSET); + gedr = gedr & c->irq_mask; + __raw_writel(gedr, c->regbase + GEDR_OFFSET); + + n = find_first_bit(&gedr, BITS_PER_LONG); + while (n < BITS_PER_LONG) { + loop = 1; + + generic_handle_irq(gpio_to_irq(gpio_base + n)); + n = find_next_bit(&gedr, BITS_PER_LONG, n + 1); + } + } + } while (loop); +} + +static void pxa_ack_muxed_gpio(struct irq_data *d) +{ + int gpio = irq_to_gpio(d->irq); + struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); + + __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET); +} + +static void pxa_mask_muxed_gpio(struct irq_data *d) +{ + int gpio = irq_to_gpio(d->irq); + struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); + uint32_t grer, gfer; + + c->irq_mask &= ~GPIO_bit(gpio); + + grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio); + gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio); + __raw_writel(grer, c->regbase + GRER_OFFSET); + __raw_writel(gfer, c->regbase + GFER_OFFSET); +} + +static void pxa_unmask_muxed_gpio(struct irq_data *d) +{ + int gpio = irq_to_gpio(d->irq); + struct pxa_gpio_chip *c = gpio_to_pxachip(gpio); + + c->irq_mask |= GPIO_bit(gpio); + update_edge_detect(c); +} + +static struct irq_chip pxa_muxed_gpio_chip = { + .name = "GPIO", + .irq_ack = pxa_ack_muxed_gpio, + .irq_mask = pxa_mask_muxed_gpio, + .irq_unmask = pxa_unmask_muxed_gpio, + .irq_set_type = pxa_gpio_irq_type, +}; + +void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn) +{ + struct pxa_gpio_chip *c; + int gpio, irq; + + pxa_last_gpio = end; + + /* Initialize GPIO chips */ + pxa_init_gpio_chip(end); + + /* clear all GPIO edge detects */ + for_each_gpio_chip(gpio, c) { + __raw_writel(0, c->regbase + GFER_OFFSET); + __raw_writel(0, c->regbase + GRER_OFFSET); + __raw_writel(~0,c->regbase + GEDR_OFFSET); + } + + for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) { + irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, + handle_edge_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + + /* Install handler for GPIO>=2 edge detect interrupts */ + irq_set_chained_handler(mux_irq, pxa_gpio_demux_handler); + pxa_muxed_gpio_chip.irq_set_wake = fn; +} + +#ifdef CONFIG_PM +static int pxa_gpio_suspend(void) +{ + struct pxa_gpio_chip *c; + int gpio; + + for_each_gpio_chip(gpio, c) { + c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET); + c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET); + c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET); + c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET); + + /* Clear GPIO transition detect bits */ + __raw_writel(0xffffffff, c->regbase + GEDR_OFFSET); + } + return 0; +} + +static void pxa_gpio_resume(void) +{ + struct pxa_gpio_chip *c; + int gpio; + + for_each_gpio_chip(gpio, c) { + /* restore level with set/clear */ + __raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET); + __raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET); + + __raw_writel(c->saved_grer, c->regbase + GRER_OFFSET); + __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET); + __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET); + } +} +#else +#define pxa_gpio_suspend NULL +#define pxa_gpio_resume NULL +#endif + +struct syscore_ops pxa_gpio_syscore_ops = { + .suspend = pxa_gpio_suspend, + .resume = pxa_gpio_resume, +}; diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c new file mode 100644 index 0000000..b6c1f6d --- /dev/null +++ b/drivers/gpio/gpio-sa1100.c @@ -0,0 +1,63 @@ +/* + * linux/arch/arm/mach-sa1100/gpio.c + * + * Generic SA-1100 GPIO handling + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/module.h> + +#include <mach/hardware.h> + +static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + return GPLR & GPIO_GPIO(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); +} + +static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset) +{ + unsigned long flags; + + local_irq_save(flags); + GPDR &= ~GPIO_GPIO(offset); + local_irq_restore(flags); + return 0; +} + +static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int value) +{ + unsigned long flags; + + local_irq_save(flags); + sa1100_gpio_set(chip, offset, value); + GPDR |= GPIO_GPIO(offset); + local_irq_restore(flags); + return 0; +} + +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, + .base = 0, + .ngpio = GPIO_MAX + 1, +}; + +void __init sa1100_init_gpio(void) +{ + gpiochip_add(&sa1100_gpio_chip); +} diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 747eb40..61044c8 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -20,13 +20,15 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/interrupt.h> - #include <linux/io.h> #include <linux/gpio.h> #include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/module.h> #include <asm/mach/irq.h> +#include <mach/gpio-tegra.h> #include <mach/iomap.h> #include <mach/suspend.h> @@ -34,9 +36,7 @@ #define GPIO_PORT(x) (((x) >> 3) & 0x3) #define GPIO_BIT(x) ((x) & 0x7) -#define GPIO_REG(x) (IO_TO_VIRT(TEGRA_GPIO_BASE) + \ - GPIO_BANK(x) * 0x80 + \ - GPIO_PORT(x) * 4) +#define GPIO_REG(x) (GPIO_BANK(x) * 0x80 + GPIO_PORT(x) * 4) #define GPIO_CNF(x) (GPIO_REG(x) + 0x00) #define GPIO_OE(x) (GPIO_REG(x) + 0x10) @@ -75,15 +75,18 @@ struct tegra_gpio_bank { }; -static struct tegra_gpio_bank tegra_gpio_banks[] = { - {.bank = 0, .irq = INT_GPIO1}, - {.bank = 1, .irq = INT_GPIO2}, - {.bank = 2, .irq = INT_GPIO3}, - {.bank = 3, .irq = INT_GPIO4}, - {.bank = 4, .irq = INT_GPIO5}, - {.bank = 5, .irq = INT_GPIO6}, - {.bank = 6, .irq = INT_GPIO7}, -}; +static void __iomem *regs; +static struct tegra_gpio_bank tegra_gpio_banks[7]; + +static inline void tegra_gpio_writel(u32 val, u32 reg) +{ + __raw_writel(val, regs + reg); +} + +static inline u32 tegra_gpio_readl(u32 reg) +{ + return __raw_readl(regs + reg); +} static int tegra_gpio_compose(int bank, int port, int bit) { @@ -97,7 +100,7 @@ static void tegra_gpio_mask_write(u32 reg, int gpio, int value) val = 0x100 << GPIO_BIT(gpio); if (value) val |= 1 << GPIO_BIT(gpio); - __raw_writel(val, reg); + tegra_gpio_writel(val, reg); } void tegra_gpio_enable(int gpio) @@ -117,7 +120,7 @@ static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) { - return (__raw_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; + return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; } static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -134,7 +137,10 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, return 0; } - +static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + return TEGRA_GPIO_TO_IRQ(offset); +} static struct gpio_chip tegra_gpio_chip = { .label = "tegra-gpio", @@ -142,6 +148,7 @@ static struct gpio_chip tegra_gpio_chip = { .get = tegra_gpio_get, .direction_output = tegra_gpio_direction_output, .set = tegra_gpio_set, + .to_irq = tegra_gpio_to_irq, .base = 0, .ngpio = TEGRA_NR_GPIOS, }; @@ -150,7 +157,7 @@ static void tegra_gpio_irq_ack(struct irq_data *d) { int gpio = d->irq - INT_GPIO_BASE; - __raw_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); + tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); } static void tegra_gpio_irq_mask(struct irq_data *d) @@ -203,10 +210,10 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) spin_lock_irqsave(&bank->lvl_lock[port], flags); - val = __raw_readl(GPIO_INT_LVL(gpio)); + val = tegra_gpio_readl(GPIO_INT_LVL(gpio)); val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio)); val |= lvl_type << GPIO_BIT(gpio); - __raw_writel(val, GPIO_INT_LVL(gpio)); + tegra_gpio_writel(val, GPIO_INT_LVL(gpio)); spin_unlock_irqrestore(&bank->lvl_lock[port], flags); @@ -232,12 +239,12 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) for (port = 0; port < 4; port++) { int gpio = tegra_gpio_compose(bank->bank, port, 0); - unsigned long sta = __raw_readl(GPIO_INT_STA(gpio)) & - __raw_readl(GPIO_INT_ENB(gpio)); - u32 lvl = __raw_readl(GPIO_INT_LVL(gpio)); + unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) & + tegra_gpio_readl(GPIO_INT_ENB(gpio)); + u32 lvl = tegra_gpio_readl(GPIO_INT_LVL(gpio)); for_each_set_bit(pin, &sta, 8) { - __raw_writel(1 << pin, GPIO_INT_CLR(gpio)); + tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio)); /* if gpio is edge triggered, clear condition * before executing the hander so that we don't @@ -271,11 +278,11 @@ void tegra_gpio_resume(void) for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { unsigned int gpio = (b<<5) | (p<<3); - __raw_writel(bank->cnf[p], GPIO_CNF(gpio)); - __raw_writel(bank->out[p], GPIO_OUT(gpio)); - __raw_writel(bank->oe[p], GPIO_OE(gpio)); - __raw_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio)); - __raw_writel(bank->int_enb[p], GPIO_INT_ENB(gpio)); + tegra_gpio_writel(bank->cnf[p], GPIO_CNF(gpio)); + tegra_gpio_writel(bank->out[p], GPIO_OUT(gpio)); + tegra_gpio_writel(bank->oe[p], GPIO_OE(gpio)); + tegra_gpio_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio)); + tegra_gpio_writel(bank->int_enb[p], GPIO_INT_ENB(gpio)); } } @@ -294,11 +301,11 @@ void tegra_gpio_suspend(void) for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { unsigned int gpio = (b<<5) | (p<<3); - bank->cnf[p] = __raw_readl(GPIO_CNF(gpio)); - bank->out[p] = __raw_readl(GPIO_OUT(gpio)); - bank->oe[p] = __raw_readl(GPIO_OE(gpio)); - bank->int_enb[p] = __raw_readl(GPIO_INT_ENB(gpio)); - bank->int_lvl[p] = __raw_readl(GPIO_INT_LVL(gpio)); + bank->cnf[p] = tegra_gpio_readl(GPIO_CNF(gpio)); + bank->out[p] = tegra_gpio_readl(GPIO_OUT(gpio)); + bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio)); + bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio)); + bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio)); } } local_irq_restore(flags); @@ -328,38 +335,69 @@ static struct irq_chip tegra_gpio_irq_chip = { */ static struct lock_class_key gpio_lock_class; -static int __init tegra_gpio_init(void) +static int __devinit tegra_gpio_probe(struct platform_device *pdev) { + struct resource *res; struct tegra_gpio_bank *bank; + int gpio; int i; int j; + for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + if (!res) { + dev_err(&pdev->dev, "Missing IRQ resource\n"); + return -ENODEV; + } + + bank = &tegra_gpio_banks[i]; + bank->bank = i; + bank->irq = res->start; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Missing MEM resource\n"); + return -ENODEV; + } + + if (!devm_request_mem_region(&pdev->dev, res->start, + resource_size(res), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "Couldn't request MEM resource\n"); + return -ENODEV; + } + + regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!regs) { + dev_err(&pdev->dev, "Couldn't ioremap regs\n"); + return -ENODEV; + } + for (i = 0; i < 7; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); - __raw_writel(0x00, GPIO_INT_ENB(gpio)); + tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio)); } } #ifdef CONFIG_OF_GPIO - /* - * This isn't ideal, but it gets things hooked up until this - * driver is converted into a platform_device - */ - tegra_gpio_chip.of_node = of_find_compatible_node(NULL, NULL, - "nvidia,tegra20-gpio"); -#endif /* CONFIG_OF_GPIO */ + tegra_gpio_chip.of_node = pdev->dev.of_node; +#endif gpiochip_add(&tegra_gpio_chip); - for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) { - bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))]; + for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) { + int irq = TEGRA_GPIO_TO_IRQ(gpio); + /* No validity check; all Tegra GPIOs are valid IRQs */ - irq_set_lockdep_class(i, &gpio_lock_class); - irq_set_chip_data(i, bank); - irq_set_chip_and_handler(i, &tegra_gpio_irq_chip, + bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; + + irq_set_lockdep_class(irq, &gpio_lock_class); + irq_set_chip_data(irq, bank); + irq_set_chip_and_handler(irq, &tegra_gpio_irq_chip, handle_simple_irq); - set_irq_flags(i, IRQF_VALID); + set_irq_flags(irq, IRQF_VALID); } for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { @@ -375,6 +413,24 @@ static int __init tegra_gpio_init(void) return 0; } +static struct of_device_id tegra_gpio_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra20-gpio", }, + { }, +}; + +static struct platform_driver tegra_gpio_driver = { + .driver = { + .name = "tegra-gpio", + .owner = THIS_MODULE, + .of_match_table = tegra_gpio_of_match, + }, + .probe = tegra_gpio_probe, +}; + +static int __init tegra_gpio_init(void) +{ + return platform_driver_register(&tegra_gpio_driver); +} postcore_initcall(tegra_gpio_init); void __init tegra_gpio_config(struct tegra_gpio_table *table, int num) @@ -407,13 +463,13 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) seq_printf(s, "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", i, j, - __raw_readl(GPIO_CNF(gpio)), - __raw_readl(GPIO_OE(gpio)), - __raw_readl(GPIO_OUT(gpio)), - __raw_readl(GPIO_IN(gpio)), - __raw_readl(GPIO_INT_STA(gpio)), - __raw_readl(GPIO_INT_ENB(gpio)), - __raw_readl(GPIO_INT_LVL(gpio))); + tegra_gpio_readl(GPIO_CNF(gpio)), + tegra_gpio_readl(GPIO_OE(gpio)), + tegra_gpio_readl(GPIO_OUT(gpio)), + tegra_gpio_readl(GPIO_IN(gpio)), + tegra_gpio_readl(GPIO_INT_STA(gpio)), + tegra_gpio_readl(GPIO_INT_ENB(gpio)), + tegra_gpio_readl(GPIO_INT_LVL(gpio))); } } return 0; diff --git a/drivers/gpio/gpio-tnetv107x.c b/drivers/gpio/gpio-tnetv107x.c new file mode 100644 index 0000000..3fa3e28 --- /dev/null +++ b/drivers/gpio/gpio-tnetv107x.c @@ -0,0 +1,205 @@ +/* + * Texas Instruments TNETV107X GPIO Controller + * + * Copyright (C) 2010 Texas Instruments + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/gpio.h> + +#include <mach/common.h> +#include <mach/tnetv107x.h> + +struct tnetv107x_gpio_regs { + u32 idver; + u32 data_in[3]; + u32 data_out[3]; + u32 direction[3]; + u32 enable[3]; +}; + +#define gpio_reg_index(gpio) ((gpio) >> 5) +#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f) + +#define gpio_reg_rmw(reg, mask, val) \ + __raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg)) + +#define gpio_reg_set_bit(reg, gpio) \ + gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio)) + +#define gpio_reg_clear_bit(reg, gpio) \ + gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0) + +#define gpio_reg_get_bit(reg, gpio) \ + (__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio)) + +#define chip2controller(chip) \ + container_of(chip, struct davinci_gpio_controller, chip) + +#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32) + +static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS]; + +static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_gpio_controller *ctlr = chip2controller(chip); + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; + unsigned gpio = chip->base + offset; + unsigned long flags; + + spin_lock_irqsave(&ctlr->lock, flags); + + gpio_reg_set_bit(regs->enable, gpio); + + spin_unlock_irqrestore(&ctlr->lock, flags); + + return 0; +} + +static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_gpio_controller *ctlr = chip2controller(chip); + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; + unsigned gpio = chip->base + offset; + unsigned long flags; + + spin_lock_irqsave(&ctlr->lock, flags); + + gpio_reg_clear_bit(regs->enable, gpio); + + spin_unlock_irqrestore(&ctlr->lock, flags); +} + +static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_gpio_controller *ctlr = chip2controller(chip); + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; + unsigned gpio = chip->base + offset; + unsigned long flags; + + spin_lock_irqsave(&ctlr->lock, flags); + + gpio_reg_set_bit(regs->direction, gpio); + + spin_unlock_irqrestore(&ctlr->lock, flags); + + return 0; +} + +static int tnetv107x_gpio_dir_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct davinci_gpio_controller *ctlr = chip2controller(chip); + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; + unsigned gpio = chip->base + offset; + unsigned long flags; + + spin_lock_irqsave(&ctlr->lock, flags); + + if (value) + gpio_reg_set_bit(regs->data_out, gpio); + else + gpio_reg_clear_bit(regs->data_out, gpio); + + gpio_reg_clear_bit(regs->direction, gpio); + + spin_unlock_irqrestore(&ctlr->lock, flags); + + return 0; +} + +static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_gpio_controller *ctlr = chip2controller(chip); + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; + unsigned gpio = chip->base + offset; + int ret; + + ret = gpio_reg_get_bit(regs->data_in, gpio); + + return ret ? 1 : 0; +} + +static void tnetv107x_gpio_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct davinci_gpio_controller *ctlr = chip2controller(chip); + struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs; + unsigned gpio = chip->base + offset; + unsigned long flags; + + spin_lock_irqsave(&ctlr->lock, flags); + + if (value) + gpio_reg_set_bit(regs->data_out, gpio); + else + gpio_reg_clear_bit(regs->data_out, gpio); + + spin_unlock_irqrestore(&ctlr->lock, flags); +} + +static int __init tnetv107x_gpio_setup(void) +{ + int i, base; + unsigned ngpio; + struct davinci_soc_info *soc_info = &davinci_soc_info; + struct tnetv107x_gpio_regs *regs; + struct davinci_gpio_controller *ctlr; + + if (soc_info->gpio_type != GPIO_TYPE_TNETV107X) + return 0; + + ngpio = soc_info->gpio_num; + if (ngpio == 0) { + pr_err("GPIO setup: how many GPIOs?\n"); + return -EINVAL; + } + + if (WARN_ON(TNETV107X_N_GPIO < ngpio)) + ngpio = TNETV107X_N_GPIO; + + regs = ioremap(soc_info->gpio_base, SZ_4K); + if (WARN_ON(!regs)) + return -EINVAL; + + for (i = 0, base = 0; base < ngpio; i++, base += 32) { + ctlr = &chips[i]; + + ctlr->chip.label = "tnetv107x"; + ctlr->chip.can_sleep = 0; + ctlr->chip.base = base; + ctlr->chip.ngpio = ngpio - base; + if (ctlr->chip.ngpio > 32) + ctlr->chip.ngpio = 32; + + ctlr->chip.request = tnetv107x_gpio_request; + ctlr->chip.free = tnetv107x_gpio_free; + ctlr->chip.direction_input = tnetv107x_gpio_dir_in; + ctlr->chip.get = tnetv107x_gpio_get; + ctlr->chip.direction_output = tnetv107x_gpio_dir_out; + ctlr->chip.set = tnetv107x_gpio_set; + + spin_lock_init(&ctlr->lock); + + ctlr->regs = regs; + ctlr->set_data = ®s->data_out[i]; + ctlr->clr_data = ®s->data_out[i]; + ctlr->in_data = ®s->data_in[i]; + + gpiochip_add(&ctlr->chip); + } + + soc_info->gpio_ctlrs = chips; + soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32); + return 0; +} +pure_initcall(tnetv107x_gpio_setup); diff --git a/drivers/gpio/gpio-u300.c b/drivers/gpio/gpio-u300.c index 53e8255..4035778 100644 --- a/drivers/gpio/gpio-u300.c +++ b/drivers/gpio/gpio-u300.c @@ -1,18 +1,17 @@ /* * U300 GPIO module. * - * Copyright (C) 2007-2009 ST-Ericsson AB + * Copyright (C) 2007-2011 ST-Ericsson AB * License terms: GNU General Public License (GPL) version 2 * This can driver either of the two basic GPIO cores * available in the U300 platforms: * COH 901 335 - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0) * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0) - * Notice that you also have inline macros in <asm-arch/gpio.h> - * Author: Linus Walleij <linus.walleij@stericsson.com> + * Author: Linus Walleij <linus.walleij@linaro.org> * Author: Jonas Aaberg <jonas.aberg@stericsson.com> - * */ #include <linux/module.h> +#include <linux/irq.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/errno.h> @@ -21,677 +20,898 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/gpio.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <mach/gpio-u300.h> -/* Reference to GPIO block clock */ -static struct clk *clk; +/* + * Bias modes for U300 GPIOs + * + * GPIO_U300_CONFIG_BIAS_UNKNOWN: this bias mode is not known to us + * GPIO_U300_CONFIG_BIAS_FLOAT: no specific bias, the GPIO will float or state + * is not controlled by software + * GPIO_U300_CONFIG_BIAS_PULL_UP: the GPIO will be pulled up (usually with high + * impedance to VDD) + */ +#define GPIO_U300_CONFIG_BIAS_UNKNOWN 0x1000 +#define GPIO_U300_CONFIG_BIAS_FLOAT 0x1001 +#define GPIO_U300_CONFIG_BIAS_PULL_UP 0x1002 -/* Memory resource */ -static struct resource *memres; -static void __iomem *virtbase; -static struct device *gpiodev; +/* + * Drive modes for U300 GPIOs (output) + * + * GPIO_U300_CONFIG_DRIVE_PUSH_PULL: the GPIO will be driven actively high and + * low, this is the most typical case and is typically achieved with two + * active transistors on the output + * GPIO_U300_CONFIG_DRIVE_OPEN_DRAIN: the GPIO will be driven with open drain + * (open collector) which means it is usually wired with other output + * ports which are then pulled up with an external resistor + * GPIO_U300_CONFIG_DRIVE_OPEN_SOURCE: the GPIO will be driven with open drain + * (open emitter) which is the same as open drain mutatis mutandis but + * pulled to ground + */ +#define GPIO_U300_CONFIG_DRIVE_PUSH_PULL 0x2000 +#define GPIO_U300_CONFIG_DRIVE_OPEN_DRAIN 0x2001 +#define GPIO_U300_CONFIG_DRIVE_OPEN_SOURCE 0x2002 + +/* + * Register definitions for COH 901 335 variant + */ +#define U300_335_PORT_STRIDE (0x1C) +/* Port X Pin Data Register 32bit, this is both input and output (R/W) */ +#define U300_335_PXPDIR (0x00) +#define U300_335_PXPDOR (0x00) +/* Port X Pin Config Register 32bit (R/W) */ +#define U300_335_PXPCR (0x04) +/* This register layout is the same in both blocks */ +#define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK (0x0000FFFFUL) +#define U300_GPIO_PXPCR_PIN_MODE_MASK (0x00000003UL) +#define U300_GPIO_PXPCR_PIN_MODE_SHIFT (0x00000002UL) +#define U300_GPIO_PXPCR_PIN_MODE_INPUT (0x00000000UL) +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL (0x00000001UL) +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN (0x00000002UL) +#define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE (0x00000003UL) +/* Port X Interrupt Event Register 32bit (R/W) */ +#define U300_335_PXIEV (0x08) +/* Port X Interrupt Enable Register 32bit (R/W) */ +#define U300_335_PXIEN (0x0C) +/* Port X Interrupt Force Register 32bit (R/W) */ +#define U300_335_PXIFR (0x10) +/* Port X Interrupt Config Register 32bit (R/W) */ +#define U300_335_PXICR (0x14) +/* This register layout is the same in both blocks */ +#define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK (0x000000FFUL) +#define U300_GPIO_PXICR_IRQ_CONFIG_MASK (0x00000001UL) +#define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE (0x00000000UL) +#define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE (0x00000001UL) +/* Port X Pull-up Enable Register 32bit (R/W) */ +#define U300_335_PXPER (0x18) +/* This register layout is the same in both blocks */ +#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK (0x000000FFUL) +#define U300_GPIO_PXPER_PULL_UP_DISABLE (0x00000001UL) +/* Control Register 32bit (R/W) */ +#define U300_335_CR (0x54) +#define U300_335_CR_BLOCK_CLOCK_ENABLE (0x00000001UL) + +/* + * Register definitions for COH 901 571 / 3 variant + */ +#define U300_571_PORT_STRIDE (0x30) +/* + * Control Register 32bit (R/W) + * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores + * gives the number of GPIO pins. + * bit 8-2 (mask 0x000001FC) contains the core version ID. + */ +#define U300_571_CR (0x00) +#define U300_571_CR_SYNC_SEL_ENABLE (0x00000002UL) +#define U300_571_CR_BLOCK_CLKRQ_ENABLE (0x00000001UL) +/* + * These registers have the same layout and function as the corresponding + * COH 901 335 registers, just at different offset. + */ +#define U300_571_PXPDIR (0x04) +#define U300_571_PXPDOR (0x08) +#define U300_571_PXPCR (0x0C) +#define U300_571_PXPER (0x10) +#define U300_571_PXIEV (0x14) +#define U300_571_PXIEN (0x18) +#define U300_571_PXIFR (0x1C) +#define U300_571_PXICR (0x20) + +/* 8 bits per port, no version has more than 7 ports */ +#define U300_GPIO_PINS_PER_PORT 8 +#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * 7) + +struct u300_gpio { + struct gpio_chip chip; + struct list_head port_list; + struct clk *clk; + struct resource *memres; + void __iomem *base; + struct device *dev; + int irq_base; + u32 stride; + /* Register offsets */ + u32 pcr; + u32 dor; + u32 dir; + u32 per; + u32 icr; + u32 ien; + u32 iev; +}; struct u300_gpio_port { - const char *name; + struct list_head node; + struct u300_gpio *gpio; + char name[8]; int irq; int number; + u8 toggle_edge_mode; }; +/* + * Macro to expand to read a specific register found in the "gpio" + * struct. It requires the struct u300_gpio *gpio variable to exist in + * its context. It calculates the port offset from the given pin + * offset, muliplies by the port stride and adds the register offset + * so it provides a pointer to the desired register. + */ +#define U300_PIN_REG(pin, reg) \ + (gpio->base + (pin >> 3) * gpio->stride + gpio->reg) -static struct u300_gpio_port gpio_ports[] = { - { - .name = "gpio0", - .number = 0, - }, - { - .name = "gpio1", - .number = 1, - }, - { - .name = "gpio2", - .number = 2, - }, -#ifdef U300_COH901571_3 - { - .name = "gpio3", - .number = 3, - }, - { - .name = "gpio4", - .number = 4, - }, -#ifdef CONFIG_MACH_U300_BS335 - { - .name = "gpio5", - .number = 5, - }, - { - .name = "gpio6", - .number = 6, - }, -#endif -#endif +/* + * Provides a bitmask for a specific gpio pin inside an 8-bit GPIO + * register. + */ +#define U300_PIN_BIT(pin) \ + (1 << (pin & 0x07)) +struct u300_gpio_confdata { + u16 bias_mode; + bool output; + int outval; }; +/* BS335 has seven ports of 8 bits each = GPIO pins 0..55 */ +#define BS335_GPIO_NUM_PORTS 7 +/* BS365 has five ports of 8 bits each = GPIO pins 0..39 */ +#define BS365_GPIO_NUM_PORTS 5 -#ifdef U300_COH901571_3 +#define U300_FLOATING_INPUT { \ + .bias_mode = GPIO_U300_CONFIG_BIAS_FLOAT, \ + .output = false, \ +} -/* Default input value */ -#define DEFAULT_OUTPUT_LOW 0 -#define DEFAULT_OUTPUT_HIGH 1 +#define U300_PULL_UP_INPUT { \ + .bias_mode = GPIO_U300_CONFIG_BIAS_PULL_UP, \ + .output = false, \ +} -/* GPIO Pull-Up status */ -#define DISABLE_PULL_UP 0 -#define ENABLE_PULL_UP 1 +#define U300_OUTPUT_LOW { \ + .output = true, \ + .outval = 0, \ +} -#define GPIO_NOT_USED 0 -#define GPIO_IN 1 -#define GPIO_OUT 2 +#define U300_OUTPUT_HIGH { \ + .output = true, \ + .outval = 1, \ +} -struct u300_gpio_configuration_data { - unsigned char pin_usage; - unsigned char default_output_value; - unsigned char pull_up; -}; /* Initial configuration */ -const struct u300_gpio_configuration_data -u300_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { -#ifdef CONFIG_MACH_U300_BS335 +static const struct __initdata u300_gpio_confdata +bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { /* Port 0, pins 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} + U300_FLOATING_INPUT, + U300_OUTPUT_HIGH, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, }, /* Port 1, pins 0-7 */ { - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_FLOATING_INPUT, + U300_OUTPUT_HIGH, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, }, /* Port 2, pins 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, }, /* Port 3, pins 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} + U300_PULL_UP_INPUT, + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, }, /* Port 4, pins 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, }, /* Port 5, pins 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, }, /* Port 6, pind 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, } -#endif +}; -#ifdef CONFIG_MACH_U300_BS365 +static const struct __initdata u300_gpio_confdata +bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { /* Port 0, pins 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_FLOATING_INPUT, }, /* Port 1, pins 0-7 */ { - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_OUTPUT_LOW, + U300_FLOATING_INPUT, + U300_FLOATING_INPUT, + U300_OUTPUT_HIGH, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, }, /* Port 2, pins 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} + U300_FLOATING_INPUT, + U300_PULL_UP_INPUT, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, }, /* Port 3, pins 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, }, /* Port 4, pins 0-7 */ { - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, + U300_PULL_UP_INPUT, /* These 4 pins doesn't exist on DB3210 */ - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, + U300_OUTPUT_LOW, } -#endif }; -#endif - -/* No users == we can power down GPIO */ -static int gpio_users; - -struct gpio_struct { - int (*callback)(void *); - void *data; - int users; -}; - -static struct gpio_struct gpio_pin[U300_GPIO_MAX]; - -/* - * Let drivers register callback in order to get notified when there is - * an interrupt on the gpio pin +/** + * to_u300_gpio() - get the pointer to u300_gpio + * @chip: the gpio chip member of the structure u300_gpio */ -int gpio_register_callback(unsigned gpio, int (*func)(void *arg), void *data) +static inline struct u300_gpio *to_u300_gpio(struct gpio_chip *chip) { - if (gpio_pin[gpio].callback) - dev_warn(gpiodev, "%s: WARNING: callback already " - "registered for gpio pin#%d\n", __func__, gpio); - gpio_pin[gpio].callback = func; - gpio_pin[gpio].data = data; - - return 0; + return container_of(chip, struct u300_gpio, chip); } -EXPORT_SYMBOL(gpio_register_callback); -int gpio_unregister_callback(unsigned gpio) +static int u300_gpio_get(struct gpio_chip *chip, unsigned offset) { - if (!gpio_pin[gpio].callback) - dev_warn(gpiodev, "%s: WARNING: callback already " - "unregistered for gpio pin#%d\n", __func__, gpio); - gpio_pin[gpio].callback = NULL; - gpio_pin[gpio].data = NULL; + struct u300_gpio *gpio = to_u300_gpio(chip); - return 0; + return readl(U300_PIN_REG(offset, dir)) & U300_PIN_BIT(offset); } -EXPORT_SYMBOL(gpio_unregister_callback); -/* Non-zero means valid */ -int gpio_is_valid(int number) +static void u300_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - if (number >= 0 && - number < (U300_GPIO_NUM_PORTS * U300_GPIO_PINS_PER_PORT)) - return 1; - return 0; -} -EXPORT_SYMBOL(gpio_is_valid); + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 val; -int gpio_request(unsigned gpio, const char *label) -{ - if (gpio_pin[gpio].users) - return -EINVAL; - else - gpio_pin[gpio].users++; + local_irq_save(flags); - gpio_users++; + val = readl(U300_PIN_REG(offset, dor)); + if (value) + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, dor)); + else + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, dor)); - return 0; + local_irq_restore(flags); } -EXPORT_SYMBOL(gpio_request); -void gpio_free(unsigned gpio) +static int u300_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - gpio_users--; - gpio_pin[gpio].users--; - if (unlikely(gpio_pin[gpio].users < 0)) { - dev_warn(gpiodev, "warning: gpio#%d release mismatch\n", - gpio); - gpio_pin[gpio].users = 0; - } - - return; -} -EXPORT_SYMBOL(gpio_free); + struct u300_gpio *gpio = to_u300_gpio(chip); + unsigned long flags; + u32 val; -/* This returns zero or nonzero */ -int gpio_get_value(unsigned gpio) -{ - return readl(virtbase + U300_GPIO_PXPDIR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) & (1 << (gpio & 0x07)); + local_irq_save(flags); + val = readl(U300_PIN_REG(offset, pcr)); + /* Mask out this pin, note 2 bits per setting */ + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + local_irq_restore(flags); + return 0; } -EXPORT_SYMBOL(gpio_get_value); -/* - * We hope that the compiler will optimize away the unused branch - * in case "value" is a constant - */ -void gpio_set_value(unsigned gpio, int value) +static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) { - u32 val; + struct u300_gpio *gpio = to_u300_gpio(chip); unsigned long flags; + u32 oldmode; + u32 val; local_irq_save(flags); - if (value) { - /* set */ - val = readl(virtbase + U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) - & (1 << (gpio & 0x07)); - writel(val | (1 << (gpio & 0x07)), virtbase + - U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } else { - /* clear */ - val = readl(virtbase + U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) - & (1 << (gpio & 0x07)); - writel(val & ~(1 << (gpio & 0x07)), virtbase + - U300_GPIO_PXPDOR + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); + val = readl(U300_PIN_REG(offset, pcr)); + /* + * Drive mode must be set by the special mode set function, set + * push/pull mode by default if no mode has been selected. + */ + oldmode = val & (U300_GPIO_PXPCR_PIN_MODE_MASK << + ((offset & 0x07) << 1)); + /* mode = 0 means input, else some mode is already set */ + if (oldmode == 0) { + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << + ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); } + u300_gpio_set(chip, offset, value); local_irq_restore(flags); + return 0; } -EXPORT_SYMBOL(gpio_set_value); -int gpio_direction_input(unsigned gpio) +static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { + struct u300_gpio *gpio = to_u300_gpio(chip); + int retirq = gpio->irq_base + offset; + + dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset, + retirq); + return retirq; +} + +static int u300_gpio_config(struct gpio_chip *chip, unsigned offset, + u16 param, unsigned long *data) +{ + struct u300_gpio *gpio = to_u300_gpio(chip); unsigned long flags; u32 val; - if (gpio > U300_GPIO_MAX) - return -EINVAL; - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - /* Mask out this pin*/ - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); - /* This is not needed since it sets the bits to zero.*/ - /* val |= (U300_GPIO_PXPCR_PIN_MODE_INPUT << (gpio*2)); */ - writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); + switch (param) { + case GPIO_U300_CONFIG_BIAS_UNKNOWN: + case GPIO_U300_CONFIG_BIAS_FLOAT: + val = readl(U300_PIN_REG(offset, per)); + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, per)); + break; + case GPIO_U300_CONFIG_BIAS_PULL_UP: + val = readl(U300_PIN_REG(offset, per)); + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, per)); + break; + case GPIO_U300_CONFIG_DRIVE_PUSH_PULL: + val = readl(U300_PIN_REG(offset, pcr)); + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK + << ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + break; + case GPIO_U300_CONFIG_DRIVE_OPEN_DRAIN: + val = readl(U300_PIN_REG(offset, pcr)); + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK + << ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + break; + case GPIO_U300_CONFIG_DRIVE_OPEN_SOURCE: + val = readl(U300_PIN_REG(offset, pcr)); + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK + << ((offset & 0x07) << 1)); + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE + << ((offset & 0x07) << 1)); + writel(val, U300_PIN_REG(offset, pcr)); + break; + default: + local_irq_restore(flags); + dev_err(gpio->dev, "illegal configuration requested\n"); + return -EINVAL; + } local_irq_restore(flags); return 0; } -EXPORT_SYMBOL(gpio_direction_input); -int gpio_direction_output(unsigned gpio, int value) +static struct gpio_chip u300_gpio_chip = { + .label = "u300-gpio-chip", + .owner = THIS_MODULE, + .get = u300_gpio_get, + .set = u300_gpio_set, + .direction_input = u300_gpio_direction_input, + .direction_output = u300_gpio_direction_output, + .to_irq = u300_gpio_to_irq, +}; + +static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset) { - unsigned long flags; u32 val; - if (gpio > U300_GPIO_MAX) - return -EINVAL; - - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - /* Mask out this pin */ - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); - /* - * FIXME: configure for push/pull, open drain or open source per pin - * in setup. The current driver will only support push/pull. - */ - val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL - << ((gpio & 0x07) << 1)); - writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - gpio_set_value(gpio, value); - local_irq_restore(flags); - return 0; + val = readl(U300_PIN_REG(offset, icr)); + /* Set mode depending on state */ + if (u300_gpio_get(&gpio->chip, offset)) { + /* High now, let's trigger on falling edge next then */ + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); + dev_dbg(gpio->dev, "next IRQ on falling edge on pin %d\n", + offset); + } else { + /* Low now, let's trigger on rising edge next then */ + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); + dev_dbg(gpio->dev, "next IRQ on rising edge on pin %d\n", + offset); + } } -EXPORT_SYMBOL(gpio_direction_output); -/* - * Enable an IRQ, edge is rising edge (!= 0) or falling edge (==0). - */ -void enable_irq_on_gpio_pin(unsigned gpio, int edge) +static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) { + struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = port->gpio; + int offset = d->irq - gpio->irq_base; u32 val; - unsigned long flags; - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - val |= (1 << (gpio & 0x07)); - writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - val = readl(virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - if (edge) - val |= (1 << (gpio & 0x07)); - else - val &= ~(1 << (gpio & 0x07)); - writel(val, virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); + if ((trigger & IRQF_TRIGGER_RISING) && + (trigger & IRQF_TRIGGER_FALLING)) { + /* + * The GPIO block can only trigger on falling OR rising edges, + * not both. So we need to toggle the mode whenever the pin + * goes from one state to the other with a special state flag + */ + dev_dbg(gpio->dev, + "trigger on both rising and falling edge on pin %d\n", + offset); + port->toggle_edge_mode |= U300_PIN_BIT(offset); + u300_toggle_trigger(gpio, offset); + } else if (trigger & IRQF_TRIGGER_RISING) { + dev_dbg(gpio->dev, "trigger on rising edge on pin %d\n", + offset); + val = readl(U300_PIN_REG(offset, icr)); + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); + port->toggle_edge_mode &= ~U300_PIN_BIT(offset); + } else if (trigger & IRQF_TRIGGER_FALLING) { + dev_dbg(gpio->dev, "trigger on falling edge on pin %d\n", + offset); + val = readl(U300_PIN_REG(offset, icr)); + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, icr)); + port->toggle_edge_mode &= ~U300_PIN_BIT(offset); + } + + return 0; } -EXPORT_SYMBOL(enable_irq_on_gpio_pin); -void disable_irq_on_gpio_pin(unsigned gpio) +static void u300_gpio_irq_enable(struct irq_data *d) { + struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = port->gpio; + int offset = d->irq - gpio->irq_base; u32 val; unsigned long flags; local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - val &= ~(1 << (gpio & 0x07)); - writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); + val = readl(U300_PIN_REG(offset, ien)); + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); local_irq_restore(flags); } -EXPORT_SYMBOL(disable_irq_on_gpio_pin); -/* Enable (value == 0) or disable (value == 1) internal pullup */ -void gpio_pullup(unsigned gpio, int value) +static void u300_gpio_irq_disable(struct irq_data *d) { + struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); + struct u300_gpio *gpio = port->gpio; + int offset = d->irq - gpio->irq_base; u32 val; unsigned long flags; local_irq_save(flags); - if (value) { - val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - writel(val | (1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } else { - val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * - U300_GPIO_PORTX_SPACING); - writel(val & ~(1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + - PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); - } + val = readl(U300_PIN_REG(offset, ien)); + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); local_irq_restore(flags); } -EXPORT_SYMBOL(gpio_pullup); -static irqreturn_t gpio_irq_handler(int irq, void *dev_id) +static struct irq_chip u300_gpio_irqchip = { + .name = "u300-gpio-irqchip", + .irq_enable = u300_gpio_irq_enable, + .irq_disable = u300_gpio_irq_disable, + .irq_set_type = u300_gpio_irq_type, + +}; + +static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - struct u300_gpio_port *port = dev_id; - u32 val; - int pin; + struct u300_gpio_port *port = irq_get_handler_data(irq); + struct u300_gpio *gpio = port->gpio; + int pinoffset = port->number << 3; /* get the right stride */ + unsigned long val; + desc->irq_data.chip->irq_ack(&desc->irq_data); /* Read event register */ - val = readl(virtbase + U300_GPIO_PXIEV + port->number * - U300_GPIO_PORTX_SPACING); - /* Mask with enable register */ - val &= readl(virtbase + U300_GPIO_PXIEV + port->number * - U300_GPIO_PORTX_SPACING); + val = readl(U300_PIN_REG(pinoffset, iev)); /* Mask relevant bits */ - val &= U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK; + val &= 0xFFU; /* 8 bits per port */ /* ACK IRQ (clear event) */ - writel(val, virtbase + U300_GPIO_PXIEV + port->number * - U300_GPIO_PORTX_SPACING); - /* Print message */ - while (val != 0) { - unsigned gpio; - - pin = __ffs(val); - /* mask off this pin */ - val &= ~(1 << pin); - gpio = (port->number << 3) + pin; - - if (gpio_pin[gpio].callback) - (void)gpio_pin[gpio].callback(gpio_pin[gpio].data); - else - dev_dbg(gpiodev, "stray GPIO IRQ on line %d\n", - gpio); + writel(val, U300_PIN_REG(pinoffset, iev)); + + /* Call IRQ handler */ + if (val != 0) { + int irqoffset; + + for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { + int pin_irq = gpio->irq_base + (port->number << 3) + + irqoffset; + int offset = pinoffset + irqoffset; + + dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n", + pin_irq, offset); + generic_handle_irq(pin_irq); + /* + * Triggering IRQ on both rising and falling edge + * needs mockery + */ + if (port->toggle_edge_mode & U300_PIN_BIT(offset)) + u300_toggle_trigger(gpio, offset); + } } - return IRQ_HANDLED; + + desc->irq_data.chip->irq_unmask(&desc->irq_data); } -static void gpio_set_initial_values(void) +static void __init u300_gpio_init_pin(struct u300_gpio *gpio, + int offset, + const struct u300_gpio_confdata *conf) { -#ifdef U300_COH901571_3 - int i, j; - unsigned long flags; - u32 val; + /* Set mode: input or output */ + if (conf->output) { + u300_gpio_direction_output(&gpio->chip, offset, conf->outval); - /* Write default values to all pins */ - for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { - val = 0; - for (j = 0; j < 8; j++) - val |= (u32) (u300_gpio_config[i][j].default_output_value != DEFAULT_OUTPUT_LOW) << j; - local_irq_save(flags); - writel(val, virtbase + U300_GPIO_PXPDOR + i * U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); + /* Deactivate bias mode for output */ + u300_gpio_config(&gpio->chip, offset, + GPIO_U300_CONFIG_BIAS_FLOAT, + NULL); + + /* Set drive mode for output */ + u300_gpio_config(&gpio->chip, offset, + GPIO_U300_CONFIG_DRIVE_PUSH_PULL, NULL); + + dev_dbg(gpio->dev, "set up pin %d as output, value: %d\n", + offset, conf->outval); + } else { + u300_gpio_direction_input(&gpio->chip, offset); + + /* Always set output low on input pins */ + u300_gpio_set(&gpio->chip, offset, 0); + + /* Set bias mode for input */ + u300_gpio_config(&gpio->chip, offset, conf->bias_mode, NULL); + + dev_dbg(gpio->dev, "set up pin %d as input, bias: %04x\n", + offset, conf->bias_mode); } +} - /* - * Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED' - * to output and 'GPIO_IN' to input for each port. And initialize - * default value on outputs. - */ - for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { - for (j = 0; j < U300_GPIO_PINS_PER_PORT; j++) { - local_irq_save(flags); - val = readl(virtbase + U300_GPIO_PXPCR + - i * U300_GPIO_PORTX_SPACING); - /* Mask out this pin */ - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << (j << 1)); - - if (u300_gpio_config[i][j].pin_usage != GPIO_IN) - val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL << (j << 1)); - writel(val, virtbase + U300_GPIO_PXPCR + - i * U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); +static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio, + struct u300_gpio_platform *plat) +{ + int i, j; + + /* Write default config and values to all pins */ + for (i = 0; i < plat->ports; i++) { + for (j = 0; j < 8; j++) { + const struct u300_gpio_confdata *conf; + int offset = (i*8) + j; + + if (plat->variant == U300_GPIO_COH901571_3_BS335) + conf = &bs335_gpio_config[i][j]; + else if (plat->variant == U300_GPIO_COH901571_3_BS365) + conf = &bs365_gpio_config[i][j]; + else + break; + + u300_gpio_init_pin(gpio, offset, conf); } } +} - /* Enable or disable the internal pull-ups in the GPIO ASIC block */ - for (i = 0; i < U300_GPIO_MAX; i++) { - val = 0; - for (j = 0; j < 8; j++) - val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP) << j); - local_irq_save(flags); - writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING); - local_irq_restore(flags); +static inline void u300_gpio_free_ports(struct u300_gpio *gpio) +{ + struct u300_gpio_port *port; + struct list_head *p, *n; + + list_for_each_safe(p, n, &gpio->port_list) { + port = list_entry(p, struct u300_gpio_port, node); + list_del(&port->node); + free_irq(port->irq, port); + kfree(port); } -#endif } -static int __init gpio_probe(struct platform_device *pdev) +static int __init u300_gpio_probe(struct platform_device *pdev) { - u32 val; + struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); + struct u300_gpio *gpio; int err = 0; + int portno; + u32 val; + u32 ifr; int i; - int num_irqs; - gpiodev = &pdev->dev; - memset(gpio_pin, 0, sizeof(gpio_pin)); + gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL); + if (gpio == NULL) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + gpio->chip = u300_gpio_chip; + gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; + gpio->irq_base = plat->gpio_irq_base; + gpio->chip.dev = &pdev->dev; + gpio->chip.base = plat->gpio_base; + gpio->dev = &pdev->dev; /* Get GPIO clock */ - clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - err = PTR_ERR(clk); - dev_err(gpiodev, "could not get GPIO clock\n"); + gpio->clk = clk_get(gpio->dev, NULL); + if (IS_ERR(gpio->clk)) { + err = PTR_ERR(gpio->clk); + dev_err(gpio->dev, "could not get GPIO clock\n"); goto err_no_clk; } - err = clk_enable(clk); + err = clk_enable(gpio->clk); if (err) { - dev_err(gpiodev, "could not enable GPIO clock\n"); + dev_err(gpio->dev, "could not enable GPIO clock\n"); goto err_no_clk_enable; } - memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!memres) + gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!gpio->memres) { + dev_err(gpio->dev, "could not get GPIO memory resource\n"); + err = -ENODEV; goto err_no_resource; + } - if (!request_mem_region(memres->start, resource_size(memres), + if (!request_mem_region(gpio->memres->start, + resource_size(gpio->memres), "GPIO Controller")) { err = -ENODEV; goto err_no_ioregion; } - virtbase = ioremap(memres->start, resource_size(memres)); - if (!virtbase) { + gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres)); + if (!gpio->base) { err = -ENOMEM; goto err_no_ioremap; } - dev_info(gpiodev, "remapped 0x%08x to %p\n", - memres->start, virtbase); - -#ifdef U300_COH901335 - dev_info(gpiodev, "initializing GPIO Controller COH 901 335\n"); - /* Turn on the GPIO block */ - writel(U300_GPIO_CR_BLOCK_CLOCK_ENABLE, virtbase + U300_GPIO_CR); -#endif - -#ifdef U300_COH901571_3 - dev_info(gpiodev, "initializing GPIO Controller COH 901 571/3\n"); - val = readl(virtbase + U300_GPIO_CR); - dev_info(gpiodev, "COH901571/3 block version: %d, " \ - "number of cores: %d\n", - ((val & 0x0000FE00) >> 9), - ((val & 0x000001FC) >> 2)); - writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE, virtbase + U300_GPIO_CR); -#endif - - gpio_set_initial_values(); - - for (num_irqs = 0 ; num_irqs < U300_GPIO_NUM_PORTS; num_irqs++) { - - gpio_ports[num_irqs].irq = - platform_get_irq_byname(pdev, - gpio_ports[num_irqs].name); - - err = request_irq(gpio_ports[num_irqs].irq, - gpio_irq_handler, IRQF_DISABLED, - gpio_ports[num_irqs].name, - &gpio_ports[num_irqs]); - if (err) { - dev_err(gpiodev, "cannot allocate IRQ for %s!\n", - gpio_ports[num_irqs].name); - goto err_no_irq; + + if (plat->variant == U300_GPIO_COH901335) { + dev_info(gpio->dev, + "initializing GPIO Controller COH 901 335\n"); + gpio->stride = U300_335_PORT_STRIDE; + gpio->pcr = U300_335_PXPCR; + gpio->dor = U300_335_PXPDOR; + gpio->dir = U300_335_PXPDIR; + gpio->per = U300_335_PXPER; + gpio->icr = U300_335_PXICR; + gpio->ien = U300_335_PXIEN; + gpio->iev = U300_335_PXIEV; + ifr = U300_335_PXIFR; + + /* Turn on the GPIO block */ + writel(U300_335_CR_BLOCK_CLOCK_ENABLE, + gpio->base + U300_335_CR); + } else if (plat->variant == U300_GPIO_COH901571_3_BS335 || + plat->variant == U300_GPIO_COH901571_3_BS365) { + dev_info(gpio->dev, + "initializing GPIO Controller COH 901 571/3\n"); + gpio->stride = U300_571_PORT_STRIDE; + gpio->pcr = U300_571_PXPCR; + gpio->dor = U300_571_PXPDOR; + gpio->dir = U300_571_PXPDIR; + gpio->per = U300_571_PXPER; + gpio->icr = U300_571_PXICR; + gpio->ien = U300_571_PXIEN; + gpio->iev = U300_571_PXIEV; + ifr = U300_571_PXIFR; + + val = readl(gpio->base + U300_571_CR); + dev_info(gpio->dev, "COH901571/3 block version: %d, " \ + "number of cores: %d totalling %d pins\n", + ((val & 0x000001FC) >> 2), + ((val & 0x0000FE00) >> 9), + ((val & 0x0000FE00) >> 9) * 8); + writel(U300_571_CR_BLOCK_CLKRQ_ENABLE, + gpio->base + U300_571_CR); + u300_gpio_init_coh901571(gpio, plat); + } else { + dev_err(gpio->dev, "unknown block variant\n"); + err = -ENODEV; + goto err_unknown_variant; + } + + /* Add each port with its IRQ separately */ + INIT_LIST_HEAD(&gpio->port_list); + for (portno = 0 ; portno < plat->ports; portno++) { + struct u300_gpio_port *port = + kmalloc(sizeof(struct u300_gpio_port), GFP_KERNEL); + + if (!port) { + dev_err(gpio->dev, "out of memory\n"); + err = -ENOMEM; + goto err_no_port; } - /* Turns off PortX_irq_force */ - writel(0x0, virtbase + U300_GPIO_PXIFR + - num_irqs * U300_GPIO_PORTX_SPACING); + + snprintf(port->name, 8, "gpio%d", portno); + port->number = portno; + port->gpio = gpio; + + port->irq = platform_get_irq_byname(pdev, + port->name); + + dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq, + port->name); + + irq_set_chained_handler(port->irq, u300_gpio_irq_handler); + irq_set_handler_data(port->irq, port); + + /* For each GPIO pin set the unique IRQ handler */ + for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { + int irqno = gpio->irq_base + (portno << 3) + i; + + dev_dbg(gpio->dev, "handler for IRQ %d on %s\n", + irqno, port->name); + irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, + handle_simple_irq); + set_irq_flags(irqno, IRQF_VALID); + irq_set_chip_data(irqno, port); + } + + /* Turns off irq force (test register) for this port */ + writel(0x0, gpio->base + portno * gpio->stride + ifr); + + list_add_tail(&port->node, &gpio->port_list); } + dev_dbg(gpio->dev, "initialized %d GPIO ports\n", portno); + + err = gpiochip_add(&gpio->chip); + if (err) { + dev_err(gpio->dev, "unable to add gpiochip: %d\n", err); + goto err_no_chip; + } + + platform_set_drvdata(pdev, gpio); return 0; - err_no_irq: - for (i = 0; i < num_irqs; i++) - free_irq(gpio_ports[i].irq, &gpio_ports[i]); - iounmap(virtbase); - err_no_ioremap: - release_mem_region(memres->start, resource_size(memres)); - err_no_ioregion: - err_no_resource: - clk_disable(clk); - err_no_clk_enable: - clk_put(clk); - err_no_clk: - dev_info(gpiodev, "module ERROR:%d\n", err); +err_no_chip: +err_no_port: + u300_gpio_free_ports(gpio); +err_unknown_variant: + iounmap(gpio->base); +err_no_ioremap: + release_mem_region(gpio->memres->start, resource_size(gpio->memres)); +err_no_ioregion: +err_no_resource: + clk_disable(gpio->clk); +err_no_clk_enable: + clk_put(gpio->clk); +err_no_clk: + kfree(gpio); + dev_info(&pdev->dev, "module ERROR:%d\n", err); return err; } -static int __exit gpio_remove(struct platform_device *pdev) +static int __exit u300_gpio_remove(struct platform_device *pdev) { - int i; + struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); + struct u300_gpio *gpio = platform_get_drvdata(pdev); + int err; /* Turn off the GPIO block */ - writel(0x00000000U, virtbase + U300_GPIO_CR); - for (i = 0 ; i < U300_GPIO_NUM_PORTS; i++) - free_irq(gpio_ports[i].irq, &gpio_ports[i]); - iounmap(virtbase); - release_mem_region(memres->start, resource_size(memres)); - clk_disable(clk); - clk_put(clk); + if (plat->variant == U300_GPIO_COH901335) + writel(0x00000000U, gpio->base + U300_335_CR); + if (plat->variant == U300_GPIO_COH901571_3_BS335 || + plat->variant == U300_GPIO_COH901571_3_BS365) + writel(0x00000000U, gpio->base + U300_571_CR); + + err = gpiochip_remove(&gpio->chip); + if (err < 0) { + dev_err(gpio->dev, "unable to remove gpiochip: %d\n", err); + return err; + } + u300_gpio_free_ports(gpio); + iounmap(gpio->base); + release_mem_region(gpio->memres->start, + resource_size(gpio->memres)); + clk_disable(gpio->clk); + clk_put(gpio->clk); + platform_set_drvdata(pdev, NULL); + kfree(gpio); return 0; } -static struct platform_driver gpio_driver = { +static struct platform_driver u300_gpio_driver = { .driver = { .name = "u300-gpio", }, - .remove = __exit_p(gpio_remove), + .remove = __exit_p(u300_gpio_remove), }; static int __init u300_gpio_init(void) { - return platform_driver_probe(&gpio_driver, gpio_probe); + return platform_driver_probe(&u300_gpio_driver, u300_gpio_probe); } static void __exit u300_gpio_exit(void) { - platform_driver_unregister(&gpio_driver); + platform_driver_unregister(&u300_gpio_driver); } arch_initcall(u300_gpio_init); module_exit(u300_gpio_exit); MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); - -#ifdef U300_COH901571_3 -MODULE_DESCRIPTION("ST-Ericsson AB COH 901 571/3 GPIO driver"); -#endif - -#ifdef U300_COH901335 -MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335 GPIO driver"); -#endif - +MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335/COH 901 571/3 GPIO driver"); MODULE_LICENSE("GPL"); |