diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 11 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-ep93xx.c | 7 | ||||
-rw-r--r-- | drivers/gpio/gpio-ge.c | 199 | ||||
-rw-r--r-- | drivers/gpio/gpio-sa1100.c | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-samsung.c | 487 | ||||
-rw-r--r-- | drivers/gpio/gpio-stmpe.c | 41 | ||||
-rw-r--r-- | drivers/gpio/gpio-tegra.c | 59 | ||||
-rw-r--r-- | drivers/gpio/gpio-twl4030.c | 111 |
9 files changed, 795 insertions, 122 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index dfea1d84655d..edadbdad31d0 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -190,6 +190,17 @@ config GPIO_VX855 additional drivers must be enabled in order to use the functionality of the device. +config GPIO_GE_FPGA + bool "GE FPGA based GPIO" + depends on GE_FPGA + help + Support for common GPIO functionality provided on some GE Single Board + Computers. + + This driver provides basic support (configure as input or output, read + and write pin state) for GPIO implemented in a number of GE single + board computers. + comment "I2C GPIO expanders:" config GPIO_MAX7300 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 593bdcd1976e..007f54bd0081 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ 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_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 6a89683fdc91..776b772523e5 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -370,13 +370,6 @@ static int __devinit ep93xx_gpio_probe(struct platform_device *pdev) } ep93xx_gpio->mmio_base = mmio; - /* Default all ports to GPIO */ - ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_KEYS | - EP93XX_SYSCON_DEVCFG_GONK | - EP93XX_SYSCON_DEVCFG_EONIDE | - EP93XX_SYSCON_DEVCFG_GONIDE | - EP93XX_SYSCON_DEVCFG_HONIDE); - for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) { struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i]; struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i]; diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c new file mode 100644 index 000000000000..7b95a4a8318c --- /dev/null +++ b/drivers/gpio/gpio-ge.c @@ -0,0 +1,199 @@ +/* + * Driver for GE FPGA based GPIO + * + * Author: Martyn Welch <martyn.welch@ge.com> + * + * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/* TODO + * + * Configuration of output modes (totem-pole/open-drain) + * Interrupt configuration - interrupts are always generated the FPGA relies on + * the I/O interrupt controllers mask to stop them propergating + */ + +#include <linux/kernel.h> +#include <linux/compiler.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/module.h> + +#define GEF_GPIO_DIRECT 0x00 +#define GEF_GPIO_IN 0x04 +#define GEF_GPIO_OUT 0x08 +#define GEF_GPIO_TRIG 0x0C +#define GEF_GPIO_POLAR_A 0x10 +#define GEF_GPIO_POLAR_B 0x14 +#define GEF_GPIO_INT_STAT 0x18 +#define GEF_GPIO_OVERRUN 0x1C +#define GEF_GPIO_MODE 0x20 + +static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value) +{ + unsigned int data; + + data = ioread32be(reg); + /* value: 0=low; 1=high */ + if (value & 0x1) + data = data | (0x1 << offset); + else + data = data & ~(0x1 << offset); + + iowrite32be(data, reg); +} + + +static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset) +{ + unsigned int data; + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); + data = data | (0x1 << offset); + iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); + + return 0; +} + +static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value) +{ + unsigned int data; + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + /* Set direction before switching to input */ + _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); + + data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT); + data = data & ~(0x1 << offset); + iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT); + + return 0; +} + +static int gef_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + unsigned int data; + int state = 0; + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + data = ioread32be(mmchip->regs + GEF_GPIO_IN); + state = (int)((data >> offset) & 0x1); + + return state; +} + +static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip); + + _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value); +} + +static int __init gef_gpio_init(void) +{ + struct device_node *np; + int retval; + struct of_mm_gpio_chip *gef_gpio_chip; + + for_each_compatible_node(np, NULL, "gef,sbc610-gpio") { + + pr_debug("%s: Initialising GEF GPIO\n", np->full_name); + + /* Allocate chip structure */ + gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); + if (!gef_gpio_chip) { + pr_err("%s: Unable to allocate structure\n", + np->full_name); + continue; + } + + /* Setup pointers to chip functions */ + gef_gpio_chip->gc.of_gpio_n_cells = 2; + gef_gpio_chip->gc.ngpio = 19; + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; + gef_gpio_chip->gc.get = gef_gpio_get; + gef_gpio_chip->gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + retval = of_mm_gpiochip_add(np, gef_gpio_chip); + if (retval) { + kfree(gef_gpio_chip); + pr_err("%s: Unable to add GPIO\n", np->full_name); + } + } + + for_each_compatible_node(np, NULL, "gef,sbc310-gpio") { + + pr_debug("%s: Initialising GEF GPIO\n", np->full_name); + + /* Allocate chip structure */ + gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); + if (!gef_gpio_chip) { + pr_err("%s: Unable to allocate structure\n", + np->full_name); + continue; + } + + /* Setup pointers to chip functions */ + gef_gpio_chip->gc.of_gpio_n_cells = 2; + gef_gpio_chip->gc.ngpio = 6; + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; + gef_gpio_chip->gc.get = gef_gpio_get; + gef_gpio_chip->gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + retval = of_mm_gpiochip_add(np, gef_gpio_chip); + if (retval) { + kfree(gef_gpio_chip); + pr_err("%s: Unable to add GPIO\n", np->full_name); + } + } + + for_each_compatible_node(np, NULL, "ge,imp3a-gpio") { + + pr_debug("%s: Initialising GE GPIO\n", np->full_name); + + /* Allocate chip structure */ + gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); + if (!gef_gpio_chip) { + pr_err("%s: Unable to allocate structure\n", + np->full_name); + continue; + } + + /* Setup pointers to chip functions */ + gef_gpio_chip->gc.of_gpio_n_cells = 2; + gef_gpio_chip->gc.ngpio = 16; + gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; + gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; + gef_gpio_chip->gc.get = gef_gpio_get; + gef_gpio_chip->gc.set = gef_gpio_set; + + /* This function adds a memory mapped GPIO chip */ + retval = of_mm_gpiochip_add(np, gef_gpio_chip); + if (retval) { + kfree(gef_gpio_chip); + pr_err("%s: Unable to add GPIO\n", np->full_name); + } + } + + return 0; +}; +arch_initcall(gef_gpio_init); + +MODULE_DESCRIPTION("GE I/O FPGA GPIO driver"); +MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 7eecf69362ee..8ea3b33d4b40 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <mach/hardware.h> +#include <mach/irqs.h> static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset) { diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 0a79a1167a25..46277877b7ec 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -169,7 +169,7 @@ int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN); } -static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip, +static int exynos_gpio_setpull(struct samsung_gpio_chip *chip, unsigned int off, samsung_gpio_pull_t pull) { if (pull == S3C_GPIO_PULL_UP) @@ -178,7 +178,7 @@ static int exynos4_gpio_setpull(struct samsung_gpio_chip *chip, return samsung_gpio_setpull_updown(chip, off, pull); } -static samsung_gpio_pull_t exynos4_gpio_getpull(struct samsung_gpio_chip *chip, +static samsung_gpio_pull_t exynos_gpio_getpull(struct samsung_gpio_chip *chip, unsigned int off) { samsung_gpio_pull_t pull; @@ -452,9 +452,9 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = { }; #endif -static struct samsung_gpio_cfg exynos4_gpio_cfg = { - .set_pull = exynos4_gpio_setpull, - .get_pull = exynos4_gpio_getpull, +static struct samsung_gpio_cfg exynos_gpio_cfg = { + .set_pull = exynos_gpio_setpull, + .get_pull = exynos_gpio_getpull, .set_config = samsung_gpio_setcfg_4bit, .get_config = samsung_gpio_getcfg_4bit, }; @@ -502,13 +502,13 @@ static struct samsung_gpio_cfg samsung_gpio_cfgs[] = { .get_config = samsung_gpio_getcfg_2bit, }, [8] = { - .set_pull = exynos4_gpio_setpull, - .get_pull = exynos4_gpio_getpull, + .set_pull = exynos_gpio_setpull, + .get_pull = exynos_gpio_getpull, }, [9] = { .cfg_eint = 0x3, - .set_pull = exynos4_gpio_setpull, - .get_pull = exynos4_gpio_getpull, + .set_pull = exynos_gpio_setpull, + .get_pull = exynos_gpio_getpull, } }; @@ -2113,10 +2113,10 @@ static struct samsung_gpio_chip s5pv210_gpios_4bit[] = { }; /* - * Followings are the gpio banks in EXYNOS4210 + * Followings are the gpio banks in EXYNOS SoCs * * The 'config' member when left to NULL, is initialized to the default - * structure samsung_gpio_cfgs[3] in the init function below. + * structure exynos_gpio_cfg in the init function below. * * The 'base' member is also initialized in the init function below. * Note: The initialization of 'base' member of samsung_gpio_chip structure @@ -2331,7 +2331,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = { .label = "GPY6", }, }, { - .base = (S5P_VA_GPIO2 + 0xC00), .config = &samsung_gpio_cfgs[9], .irq_base = IRQ_EINT(0), .chip = { @@ -2341,7 +2340,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = { .to_irq = samsung_gpiolib_to_irq, }, }, { - .base = (S5P_VA_GPIO2 + 0xC20), .config = &samsung_gpio_cfgs[9], .irq_base = IRQ_EINT(8), .chip = { @@ -2351,7 +2349,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = { .to_irq = samsung_gpiolib_to_irq, }, }, { - .base = (S5P_VA_GPIO2 + 0xC40), .config = &samsung_gpio_cfgs[9], .irq_base = IRQ_EINT(16), .chip = { @@ -2361,7 +2358,6 @@ static struct samsung_gpio_chip exynos4_gpios_2[] = { .to_irq = samsung_gpiolib_to_irq, }, }, { - .base = (S5P_VA_GPIO2 + 0xC60), .config = &samsung_gpio_cfgs[9], .irq_base = IRQ_EINT(24), .chip = { @@ -2386,8 +2382,280 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = { #endif }; -#if defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) -static int exynos4_gpio_xlate(struct gpio_chip *gc, +static struct samsung_gpio_chip exynos5_gpios_1[] = { +#ifdef CONFIG_ARCH_EXYNOS5 + { + .chip = { + .base = EXYNOS5_GPA0(0), + .ngpio = EXYNOS5_GPIO_A0_NR, + .label = "GPA0", + }, + }, { + .chip = { + .base = EXYNOS5_GPA1(0), + .ngpio = EXYNOS5_GPIO_A1_NR, + .label = "GPA1", + }, + }, { + .chip = { + .base = EXYNOS5_GPA2(0), + .ngpio = EXYNOS5_GPIO_A2_NR, + .label = "GPA2", + }, + }, { + .chip = { + .base = EXYNOS5_GPB0(0), + .ngpio = EXYNOS5_GPIO_B0_NR, + .label = "GPB0", + }, + }, { + .chip = { + .base = EXYNOS5_GPB1(0), + .ngpio = EXYNOS5_GPIO_B1_NR, + .label = "GPB1", + }, + }, { + .chip = { + .base = EXYNOS5_GPB2(0), + .ngpio = EXYNOS5_GPIO_B2_NR, + .label = "GPB2", + }, + }, { + .chip = { + .base = EXYNOS5_GPB3(0), + .ngpio = EXYNOS5_GPIO_B3_NR, + .label = "GPB3", + }, + }, { + .chip = { + .base = EXYNOS5_GPC0(0), + .ngpio = EXYNOS5_GPIO_C0_NR, + .label = "GPC0", + }, + }, { + .chip = { + .base = EXYNOS5_GPC1(0), + .ngpio = EXYNOS5_GPIO_C1_NR, + .label = "GPC1", + }, + }, { + .chip = { + .base = EXYNOS5_GPC2(0), + .ngpio = EXYNOS5_GPIO_C2_NR, + .label = "GPC2", + }, + }, { + .chip = { + .base = EXYNOS5_GPC3(0), + .ngpio = EXYNOS5_GPIO_C3_NR, + .label = "GPC3", + }, + }, { + .chip = { + .base = EXYNOS5_GPD0(0), + .ngpio = EXYNOS5_GPIO_D0_NR, + .label = "GPD0", + }, + }, { + .chip = { + .base = EXYNOS5_GPD1(0), + .ngpio = EXYNOS5_GPIO_D1_NR, + .label = "GPD1", + }, + }, { + .chip = { + .base = EXYNOS5_GPY0(0), + .ngpio = EXYNOS5_GPIO_Y0_NR, + .label = "GPY0", + }, + }, { + .chip = { + .base = EXYNOS5_GPY1(0), + .ngpio = EXYNOS5_GPIO_Y1_NR, + .label = "GPY1", + }, + }, { + .chip = { + .base = EXYNOS5_GPY2(0), + .ngpio = EXYNOS5_GPIO_Y2_NR, + .label = "GPY2", + }, + }, { + .chip = { + .base = EXYNOS5_GPY3(0), + .ngpio = EXYNOS5_GPIO_Y3_NR, + .label = "GPY3", + }, + }, { + .chip = { + .base = EXYNOS5_GPY4(0), + .ngpio = EXYNOS5_GPIO_Y4_NR, + .label = "GPY4", + }, + }, { + .chip = { + .base = EXYNOS5_GPY5(0), + .ngpio = EXYNOS5_GPIO_Y5_NR, + .label = "GPY5", + }, + }, { + .chip = { + .base = EXYNOS5_GPY6(0), + .ngpio = EXYNOS5_GPIO_Y6_NR, + .label = "GPY6", + }, + }, { + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(0), + .chip = { + .base = EXYNOS5_GPX0(0), + .ngpio = EXYNOS5_GPIO_X0_NR, + .label = "GPX0", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(8), + .chip = { + .base = EXYNOS5_GPX1(0), + .ngpio = EXYNOS5_GPIO_X1_NR, + .label = "GPX1", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(16), + .chip = { + .base = EXYNOS5_GPX2(0), + .ngpio = EXYNOS5_GPIO_X2_NR, + .label = "GPX2", + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .config = &samsung_gpio_cfgs[9], + .irq_base = IRQ_EINT(24), + .chip = { + .base = EXYNOS5_GPX3(0), + .ngpio = EXYNOS5_GPIO_X3_NR, + .label = "GPX3", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos5_gpios_2[] = { +#ifdef CONFIG_ARCH_EXYNOS5 + { + .chip = { + .base = EXYNOS5_GPE0(0), + .ngpio = EXYNOS5_GPIO_E0_NR, + .label = "GPE0", + }, + }, { + .chip = { + .base = EXYNOS5_GPE1(0), + .ngpio = EXYNOS5_GPIO_E1_NR, + .label = "GPE1", + }, + }, { + .chip = { + .base = EXYNOS5_GPF0(0), + .ngpio = EXYNOS5_GPIO_F0_NR, + .label = "GPF0", + }, + }, { + .chip = { + .base = EXYNOS5_GPF1(0), + .ngpio = EXYNOS5_GPIO_F1_NR, + .label = "GPF1", + }, + }, { + .chip = { + .base = EXYNOS5_GPG0(0), + .ngpio = EXYNOS5_GPIO_G0_NR, + .label = "GPG0", + }, + }, { + .chip = { + .base = EXYNOS5_GPG1(0), + .ngpio = EXYNOS5_GPIO_G1_NR, + .label = "GPG1", + }, + }, { + .chip = { + .base = EXYNOS5_GPG2(0), + .ngpio = EXYNOS5_GPIO_G2_NR, + .label = "GPG2", + }, + }, { + .chip = { + .base = EXYNOS5_GPH0(0), + .ngpio = EXYNOS5_GPIO_H0_NR, + .label = "GPH0", + }, + }, { + .chip = { + .base = EXYNOS5_GPH1(0), + .ngpio = EXYNOS5_GPIO_H1_NR, + .label = "GPH1", + + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos5_gpios_3[] = { +#ifdef CONFIG_ARCH_EXYNOS5 + { + .chip = { + .base = EXYNOS5_GPV0(0), + .ngpio = EXYNOS5_GPIO_V0_NR, + .label = "GPV0", + }, + }, { + .chip = { + .base = EXYNOS5_GPV1(0), + .ngpio = EXYNOS5_GPIO_V1_NR, + .label = "GPV1", + }, + }, { + .chip = { + .base = EXYNOS5_GPV2(0), + .ngpio = EXYNOS5_GPIO_V2_NR, + .label = "GPV2", + }, + }, { + .chip = { + .base = EXYNOS5_GPV3(0), + .ngpio = EXYNOS5_GPIO_V3_NR, + .label = "GPV3", + }, + }, { + .chip = { + .base = EXYNOS5_GPV4(0), + .ngpio = EXYNOS5_GPIO_V4_NR, + .label = "GPV4", + }, + }, +#endif +}; + +static struct samsung_gpio_chip exynos5_gpios_4[] = { +#ifdef CONFIG_ARCH_EXYNOS5 + { + .chip = { + .base = EXYNOS5_GPZ(0), + .ngpio = EXYNOS5_GPIO_Z_NR, + .label = "GPZ", + }, + }, +#endif +}; + + +#if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) +static int exynos_gpio_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags) { unsigned int pin; @@ -2413,13 +2681,13 @@ static int exynos4_gpio_xlate(struct gpio_chip *gc, return gpiospec->args[0]; } -static const struct of_device_id exynos4_gpio_dt_match[] __initdata = { +static const struct of_device_id exynos_gpio_dt_match[] __initdata = { { .compatible = "samsung,exynos4-gpio", }, {} }; -static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, - u64 base, u64 offset) +static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) { struct gpio_chip *gc = &chip->chip; u64 address; @@ -2429,28 +2697,29 @@ static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; gc->of_node = of_find_matching_node_by_address(NULL, - exynos4_gpio_dt_match, address); + exynos_gpio_dt_match, address); if (!gc->of_node) { pr_info("gpio: device tree node not found for gpio controller" " with base address %08llx\n", address); return; } gc->of_gpio_n_cells = 4; - gc->of_xlate = exynos4_gpio_xlate; + gc->of_xlate = exynos_gpio_xlate; } -#elif defined(CONFIG_ARCH_EXYNOS4) -static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, - u64 base, u64 offset) +#elif defined(CONFIG_ARCH_EXYNOS) +static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, + u64 base, u64 offset) { return; } -#endif /* defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) */ +#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */ /* TODO: cleanup soc_is_* */ static __init int samsung_gpiolib_init(void) { struct samsung_gpio_chip *chip; int i, nr_chips; + void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4; int group = 0; samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs)); @@ -2516,66 +2785,200 @@ static __init int samsung_gpiolib_init(void) s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); #endif } else if (soc_is_exynos4210()) { - group = 0; +#ifdef CONFIG_CPU_EXYNOS4210 + void __iomem *gpx_base; /* gpio part1 */ + gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K); + if (gpio_base1 == NULL) { + pr_err("unable to ioremap for gpio_base1\n"); + goto err_ioremap1; + } + chip = exynos4_gpios_1; nr_chips = ARRAY_SIZE(exynos4_gpios_1); for (i = 0; i < nr_chips; i++, chip++) { if (!chip->config) { - chip->config = &exynos4_gpio_cfg; + chip->config = &exynos_gpio_cfg; chip->group = group++; } -#ifdef CONFIG_CPU_EXYNOS4210 - exynos4_gpiolib_attach_ofnode(chip, + exynos_gpiolib_attach_ofnode(chip, EXYNOS4_PA_GPIO1, i * 0x20); -#endif } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1); + samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, + nr_chips, gpio_base1); /* gpio part2 */ + gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K); + if (gpio_base2 == NULL) { + pr_err("unable to ioremap for gpio_base2\n"); + goto err_ioremap2; + } + + /* need to set base address for gpx */ + chip = &exynos4_gpios_2[16]; + gpx_base = gpio_base2 + 0xC00; + for (i = 0; i < 4; i++, chip++, gpx_base += 0x20) + chip->base = gpx_base; + chip = exynos4_gpios_2; nr_chips = ARRAY_SIZE(exynos4_gpios_2); for (i = 0; i < nr_chips; i++, chip++) { if (!chip->config) { - chip->config = &exynos4_gpio_cfg; + chip->config = &exynos_gpio_cfg; chip->group = group++; } -#ifdef CONFIG_CPU_EXYNOS4210 - exynos4_gpiolib_attach_ofnode(chip, + exynos_gpiolib_attach_ofnode(chip, EXYNOS4_PA_GPIO2, i * 0x20); -#endif } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2); + samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, + nr_chips, gpio_base2); /* gpio part3 */ + gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256); + if (gpio_base3 == NULL) { + pr_err("unable to ioremap for gpio_base3\n"); + goto err_ioremap3; + } + chip = exynos4_gpios_3; nr_chips = ARRAY_SIZE(exynos4_gpios_3); for (i = 0; i < nr_chips; i++, chip++) { if (!chip->config) { - chip->config = &exynos4_gpio_cfg; + chip->config = &exynos_gpio_cfg; chip->group = group++; } -#ifdef CONFIG_CPU_EXYNOS4210 - exynos4_gpiolib_attach_ofnode(chip, + exynos_gpiolib_attach_ofnode(chip, EXYNOS4_PA_GPIO3, i * 0x20); -#endif } - samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3); + samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, + nr_chips, gpio_base3); #if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT) s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS); s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS); #endif + +#endif /* CONFIG_CPU_EXYNOS4210 */ + } else if (soc_is_exynos5250()) { +#ifdef CONFIG_SOC_EXYNOS5250 + void __iomem *gpx_base; + + /* gpio part1 */ + gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K); + if (gpio_base1 == NULL) { + pr_err("unable to ioremap for gpio_base1\n"); + goto err_ioremap1; + } + + /* need to set base address for gpx */ + chip = &exynos5_gpios_1[20]; + gpx_base = gpio_base1 + 0xC00; + for (i = 0; i < 4; i++, chip++, gpx_base += 0x20) + chip->base = gpx_base; + + chip = exynos5_gpios_1; + nr_chips = ARRAY_SIZE(exynos5_gpios_1); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS5_PA_GPIO1, i * 0x20); + } + samsung_gpiolib_add_4bit_chips(exynos5_gpios_1, + nr_chips, gpio_base1); + + /* gpio part2 */ + gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K); + if (gpio_base2 == NULL) { + pr_err("unable to ioremap for gpio_base2\n"); + goto err_ioremap2; + } + + chip = exynos5_gpios_2; + nr_chips = ARRAY_SIZE(exynos5_gpios_2); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS5_PA_GPIO2, i * 0x20); + } + samsung_gpiolib_add_4bit_chips(exynos5_gpios_2, + nr_chips, gpio_base2); + + /* gpio part3 */ + gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K); + if (gpio_base3 == NULL) { + pr_err("unable to ioremap for gpio_base3\n"); + goto err_ioremap3; + } + + /* need to set base address for gpv */ + exynos5_gpios_3[0].base = gpio_base3; + exynos5_gpios_3[1].base = gpio_base3 + 0x20; + exynos5_gpios_3[2].base = gpio_base3 + 0x60; + exynos5_gpios_3[3].base = gpio_base3 + 0x80; + exynos5_gpios_3[4].base = gpio_base3 + 0xC0; + + chip = exynos5_gpios_3; + nr_chips = ARRAY_SIZE(exynos5_gpios_3); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS5_PA_GPIO3, i * 0x20); + } + samsung_gpiolib_add_4bit_chips(exynos5_gpios_3, + nr_chips, gpio_base3); + + /* gpio part4 */ + gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K); + if (gpio_base4 == NULL) { + pr_err("unable to ioremap for gpio_base4\n"); + goto err_ioremap4; + } + + chip = exynos5_gpios_4; + nr_chips = ARRAY_SIZE(exynos5_gpios_4); + + for (i = 0; i < nr_chips; i++, chip++) { + if (!chip->config) { + chip->config = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS5_PA_GPIO4, i * 0x20); + } + samsung_gpiolib_add_4bit_chips(exynos5_gpios_4, + nr_chips, gpio_base4); +#endif /* CONFIG_SOC_EXYNOS5250 */ } else { WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n"); return -ENODEV; } return 0; + +err_ioremap4: + iounmap(gpio_base3); +err_ioremap3: + iounmap(gpio_base2); +err_ioremap2: + iounmap(gpio_base1); +err_ioremap1: + return -ENOMEM; } core_initcall(samsung_gpiolib_init); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 8abf4e9e2300..dce34727bbf8 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -307,13 +307,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) struct stmpe_gpio_platform_data *pdata; struct stmpe_gpio *stmpe_gpio; int ret; - int irq; + int irq = 0; pdata = stmpe->pdata->gpio; irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL); if (!stmpe_gpio) @@ -330,21 +328,28 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->chip.dev = &pdev->dev; stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1; - stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0); + if (irq >= 0) + stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0); + else + dev_info(&pdev->dev, + "device configured in no-irq mode; " + "irqs are not available\n"); ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO); if (ret) goto out_free; - ret = stmpe_gpio_irq_init(stmpe_gpio); - if (ret) - goto out_disable; + if (irq >= 0) { + ret = stmpe_gpio_irq_init(stmpe_gpio); + if (ret) + goto out_disable; - ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT, - "stmpe-gpio", stmpe_gpio); - if (ret) { - dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_removeirq; + ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, + IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio); + if (ret) { + dev_err(&pdev->dev, "unable to get irq: %d\n", ret); + goto out_removeirq; + } } ret = gpiochip_add(&stmpe_gpio->chip); @@ -361,9 +366,11 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) return 0; out_freeirq: - free_irq(irq, stmpe_gpio); + if (irq >= 0) + free_irq(irq, stmpe_gpio); out_removeirq: - stmpe_gpio_irq_remove(stmpe_gpio); + if (irq >= 0) + stmpe_gpio_irq_remove(stmpe_gpio); out_disable: stmpe_disable(stmpe, STMPE_BLOCK_GPIO); out_free: @@ -391,8 +398,10 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev) stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - free_irq(irq, stmpe_gpio); - stmpe_gpio_irq_remove(stmpe_gpio); + if (irq >= 0) { + free_irq(irq, stmpe_gpio); + stmpe_gpio_irq_remove(stmpe_gpio); + } platform_set_drvdata(pdev, NULL); kfree(stmpe_gpio); diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index ceb1fd081b85..32de6707e3c4 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -25,6 +25,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/irqdomain.h> #include <asm/mach/irq.h> @@ -74,9 +75,10 @@ struct tegra_gpio_bank { #endif }; - +static struct irq_domain *irq_domain; static void __iomem *regs; -static struct tegra_gpio_bank tegra_gpio_banks[7]; +static u32 tegra_gpio_bank_count; +static struct tegra_gpio_bank *tegra_gpio_banks; static inline void tegra_gpio_writel(u32 val, u32 reg) { @@ -141,7 +143,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - return TEGRA_GPIO_TO_IRQ(offset); + return irq_find_mapping(irq_domain, offset); } static struct gpio_chip tegra_gpio_chip = { @@ -157,28 +159,28 @@ static struct gpio_chip tegra_gpio_chip = { static void tegra_gpio_irq_ack(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); } static void tegra_gpio_irq_mask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); } static void tegra_gpio_irq_unmask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); } static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); int port = GPIO_PORT(gpio); int lvl_type; @@ -275,7 +277,7 @@ void tegra_gpio_resume(void) local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -298,7 +300,7 @@ void tegra_gpio_suspend(void) int p; local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -339,13 +341,44 @@ static struct lock_class_key gpio_lock_class; static int __devinit tegra_gpio_probe(struct platform_device *pdev) { + int irq_base; struct resource *res; struct tegra_gpio_bank *bank; int gpio; int i; int j; - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + for (;;) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count); + if (!res) + break; + tegra_gpio_bank_count++; + } + if (!tegra_gpio_bank_count) { + dev_err(&pdev->dev, "Missing IRQ resource\n"); + return -ENODEV; + } + + tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32; + + tegra_gpio_banks = devm_kzalloc(&pdev->dev, + tegra_gpio_bank_count * sizeof(*tegra_gpio_banks), + GFP_KERNEL); + if (!tegra_gpio_banks) { + dev_err(&pdev->dev, "Couldn't allocate bank structure\n"); + return -ENODEV; + } + + irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0); + if (irq_base < 0) { + dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } + irq_domain = irq_domain_add_legacy(pdev->dev.of_node, + tegra_gpio_chip.ngpio, irq_base, 0, + &irq_domain_simple_ops, NULL); + + for (i = 0; i < tegra_gpio_bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { dev_err(&pdev->dev, "Missing IRQ resource\n"); @@ -382,8 +415,8 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); - for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) { - int irq = TEGRA_GPIO_TO_IRQ(gpio); + for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { + int irq = irq_find_mapping(irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; @@ -395,7 +428,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) set_irq_flags(irq, IRQF_VALID); } - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { bank = &tegra_gpio_banks[i]; irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index b8b4f228757c..94256fe7bf36 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -32,6 +32,8 @@ #include <linux/irq.h> #include <linux/gpio.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/irqdomain.h> #include <linux/i2c/twl.h> @@ -256,7 +258,8 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) * and vMMC2 power supplies based on card presence. */ pdata = chip->dev->platform_data; - value |= pdata->mmc_cd & 0x03; + if (pdata) + value |= pdata->mmc_cd & 0x03; status = gpio_twl4030_write(REG_GPIO_CTRL, value); } @@ -395,59 +398,70 @@ static int gpio_twl4030_remove(struct platform_device *pdev); static int __devinit gpio_twl4030_probe(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; - int ret; + struct device_node *node = pdev->dev.of_node; + int ret, irq_base; /* maybe setup IRQs */ - if (pdata->irq_base) { - if (is_module()) { - dev_err(&pdev->dev, - "can't dispatch IRQs from modules\n"); - goto no_irqs; - } - ret = twl4030_sih_setup(TWL4030_MODULE_GPIO); - if (ret < 0) - return ret; - WARN_ON(ret != pdata->irq_base); - twl4030_gpio_irq_base = ret; + if (is_module()) { + dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); + goto no_irqs; + } + + irq_base = irq_alloc_descs(-1, 0, TWL4030_GPIO_MAX, 0); + if (irq_base < 0) { + dev_err(&pdev->dev, "Failed to alloc irq_descs\n"); + return irq_base; } + irq_domain_add_legacy(node, TWL4030_GPIO_MAX, irq_base, 0, + &irq_domain_simple_ops, NULL); + + ret = twl4030_sih_setup(&pdev->dev, TWL4030_MODULE_GPIO, irq_base); + if (ret < 0) + return ret; + + twl4030_gpio_irq_base = irq_base; + no_irqs: - /* - * NOTE: boards may waste power if they don't set pullups - * and pulldowns correctly ... default for non-ULPI pins is - * pulldown, and some other pins may have external pullups - * or pulldowns. Careful! - */ - ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); - if (ret) - dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", - pdata->pullups, pdata->pulldowns, - ret); - - ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); - if (ret) - dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", - pdata->debounce, pdata->mmc_cd, - ret); - - twl_gpiochip.base = pdata->gpio_base; + twl_gpiochip.base = -1; twl_gpiochip.ngpio = TWL4030_GPIO_MAX; twl_gpiochip.dev = &pdev->dev; - /* NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, - * is (still) clear if use_leds is set. - */ - if (pdata->use_leds) - twl_gpiochip.ngpio += 2; + if (pdata) { + twl_gpiochip.base = pdata->gpio_base; + + /* + * NOTE: boards may waste power if they don't set pullups + * and pulldowns correctly ... default for non-ULPI pins is + * pulldown, and some other pins may have external pullups + * or pulldowns. Careful! + */ + ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns); + if (ret) + dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n", + pdata->pullups, pdata->pulldowns, + ret); + + ret = gpio_twl4030_debounce(pdata->debounce, pdata->mmc_cd); + if (ret) + dev_dbg(&pdev->dev, "debounce %.03x %.01x --> %d\n", + pdata->debounce, pdata->mmc_cd, + ret); + + /* + * NOTE: we assume VIBRA_CTL.VIBRA_EN, in MODULE_AUDIO_VOICE, + * is (still) clear if use_leds is set. + */ + if (pdata->use_leds) + twl_gpiochip.ngpio += 2; + } ret = gpiochip_add(&twl_gpiochip); if (ret < 0) { - dev_err(&pdev->dev, - "could not register gpiochip, %d\n", - ret); + dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); twl_gpiochip.ngpio = 0; gpio_twl4030_remove(pdev); - } else if (pdata->setup) { + } else if (pdata && pdata->setup) { int status; status = pdata->setup(&pdev->dev, @@ -465,7 +479,7 @@ static int gpio_twl4030_remove(struct platform_device *pdev) struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; int status; - if (pdata->teardown) { + if (pdata && pdata->teardown) { status = pdata->teardown(&pdev->dev, pdata->gpio_base, TWL4030_GPIO_MAX); if (status) { @@ -486,12 +500,21 @@ static int gpio_twl4030_remove(struct platform_device *pdev) return -EIO; } +static const struct of_device_id twl_gpio_match[] = { + { .compatible = "ti,twl4030-gpio", }, + { }, +}; +MODULE_DEVICE_TABLE(of, twl_gpio_match); + /* Note: this hardware lives inside an I2C-based multi-function device. */ MODULE_ALIAS("platform:twl4030_gpio"); static struct platform_driver gpio_twl4030_driver = { - .driver.name = "twl4030_gpio", - .driver.owner = THIS_MODULE, + .driver = { + .name = "twl4030_gpio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl_gpio_match), + }, .probe = gpio_twl4030_probe, .remove = gpio_twl4030_remove, }; |