diff options
53 files changed, 1210 insertions, 878 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio_lpc32xx.txt b/Documentation/devicetree/bindings/gpio/gpio_lpc32xx.txt new file mode 100644 index 00000000000..49819367a01 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio_lpc32xx.txt @@ -0,0 +1,43 @@ +NXP LPC32xx SoC GPIO controller + +Required properties: +- compatible: must be "nxp,lpc3220-gpio" +- reg: Physical base address and length of the controller's registers. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be 3: + 1) bank: + 0: GPIO P0 + 1: GPIO P1 + 2: GPIO P2 + 3: GPIO P3 + 4: GPI P3 + 5: GPO P3 + 2) pin number + 3) optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) +- reg: Index of the GPIO group + +Example: + + gpio: gpio@40028000 { + compatible = "nxp,lpc3220-gpio"; + reg = <0x40028000 0x1000>; + gpio-controller; + #gpio-cells = <3>; /* bank, pin, flags */ + }; + + leds { + compatible = "gpio-leds"; + + led0 { + gpios = <&gpio 5 1 1>; /* GPO_P3 1, active low */ + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led1 { + gpios = <&gpio 5 14 1>; /* GPO_P3 14, active low */ + linux,default-trigger = "timer"; + default-state = "off"; + }; + }; diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index 620a07844e8..e08a883de36 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt @@ -322,6 +322,9 @@ where 'flags' is currently defined to specify the following properties: * GPIOF_OPEN_DRAIN - gpio pin is open drain type. * GPIOF_OPEN_SOURCE - gpio pin is open source type. + * GPIOF_EXPORT_DIR_FIXED - export gpio to sysfs, keep direction + * GPIOF_EXPORT_DIR_CHANGEABLE - also export, allow changing direction + since GPIOF_INIT_* are only valid when configured as output, so group valid combinations as: diff --git a/arch/alpha/include/asm/gpio.h b/arch/alpha/include/asm/gpio.h index 7dc6a6343c0..b3799d88ffc 100644 --- a/arch/alpha/include/asm/gpio.h +++ b/arch/alpha/include/asm/gpio.h @@ -1,55 +1,4 @@ -/* - * Generic GPIO API implementation for Alpha. - * - * A stright copy of that for PowerPC which was: - * - * Copyright (c) 2007-2008 MontaVista Software, Inc. - * - * Author: Anton Vorontsov <avorontsov@ru.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. - */ - -#ifndef _ASM_ALPHA_GPIO_H -#define _ASM_ALPHA_GPIO_H - -#include <linux/errno.h> -#include <asm-generic/gpio.h> - -#ifdef CONFIG_GPIOLIB - -/* - * We don't (yet) implement inlined/rapid versions for on-chip gpios. - * Just call gpiolib. - */ -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(unsigned int gpio) -{ - return __gpio_to_irq(gpio); -} - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* _ASM_ALPHA_GPIO_H */ +#ifndef __LINUX_GPIO_H +#warning Include linux/gpio.h instead of asm/gpio.h +#include <linux/gpio.h> +#endif diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 312450941a1..5458aa9db06 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1,6 +1,7 @@ config ARM bool default y + select ARCH_HAVE_CUSTOM_GPIO_H select HAVE_AOUT select HAVE_DMA_API_DEBUG select HAVE_IDE if PCI || ISA || PCMCIA diff --git a/arch/arm/mach-imx/mach-mx35_3ds.c b/arch/arm/mach-imx/mach-mx35_3ds.c index 86284bba46d..28aa19476de 100644 --- a/arch/arm/mach-imx/mach-mx35_3ds.c +++ b/arch/arm/mach-imx/mach-mx35_3ds.c @@ -98,8 +98,7 @@ static struct i2c_board_info __initdata i2c_devices_3ds[] = { static int lcd_power_gpio = -ENXIO; -static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip, - const void *data) +static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip, void *data) { return !strcmp(chip->label, data); } diff --git a/arch/arm/mach-lpc32xx/include/mach/gpio.h b/arch/arm/mach-lpc32xx/include/mach/gpio.h index 40a8c178f10..2ba6ca412be 100644 --- a/arch/arm/mach-lpc32xx/include/mach/gpio.h +++ b/arch/arm/mach-lpc32xx/include/mach/gpio.h @@ -1 +1,8 @@ -/* empty */ +#ifndef __MACH_GPIO_H +#define __MACH_GPIO_H + +#include "gpio-lpc32xx.h" + +#define ARCH_NR_GPIOS (LPC32XX_GPO_P3_GRP + LPC32XX_GPO_P3_MAX) + +#endif /* __MACH_GPIO_H */ diff --git a/arch/arm/mach-omap1/gpio15xx.c b/arch/arm/mach-omap1/gpio15xx.c index 634903ef829..ebef15e5e7b 100644 --- a/arch/arm/mach-omap1/gpio15xx.c +++ b/arch/arm/mach-omap1/gpio15xx.c @@ -46,7 +46,6 @@ static struct omap_gpio_reg_offs omap15xx_mpuio_regs = { }; static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = { - .virtual_irq_start = IH_MPUIO_BASE, .is_mpuio = true, .bank_width = 16, .bank_stride = 1, @@ -89,7 +88,6 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = { }; static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = { - .virtual_irq_start = IH_GPIO_BASE, .bank_width = 16, .regs = &omap15xx_gpio_regs, }; diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c index 1fb3b9ad496..2a48cd2e175 100644 --- a/arch/arm/mach-omap1/gpio16xx.c +++ b/arch/arm/mach-omap1/gpio16xx.c @@ -52,7 +52,6 @@ static struct omap_gpio_reg_offs omap16xx_mpuio_regs = { }; static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = { - .virtual_irq_start = IH_MPUIO_BASE, .is_mpuio = true, .bank_width = 16, .bank_stride = 1, @@ -99,7 +98,6 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = { }; static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = { - .virtual_irq_start = IH_GPIO_BASE, .bank_width = 16, .regs = &omap16xx_gpio_regs, }; @@ -128,7 +126,6 @@ static struct __initdata resource omap16xx_gpio2_resources[] = { }; static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = { - .virtual_irq_start = IH_GPIO_BASE + 16, .bank_width = 16, .regs = &omap16xx_gpio_regs, }; @@ -157,7 +154,6 @@ static struct __initdata resource omap16xx_gpio3_resources[] = { }; static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = { - .virtual_irq_start = IH_GPIO_BASE + 32, .bank_width = 16, .regs = &omap16xx_gpio_regs, }; @@ -186,7 +182,6 @@ static struct __initdata resource omap16xx_gpio4_resources[] = { }; static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = { - .virtual_irq_start = IH_GPIO_BASE + 48, .bank_width = 16, .regs = &omap16xx_gpio_regs, }; diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c index 4771d6b68b9..acf12b73eac 100644 --- a/arch/arm/mach-omap1/gpio7xx.c +++ b/arch/arm/mach-omap1/gpio7xx.c @@ -51,7 +51,6 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = { }; static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = { - .virtual_irq_start = IH_MPUIO_BASE, .is_mpuio = true, .bank_width = 16, .bank_stride = 2, @@ -93,7 +92,6 @@ static struct omap_gpio_reg_offs omap7xx_gpio_regs = { }; static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = { - .virtual_irq_start = IH_GPIO_BASE, .bank_width = 32, .regs = &omap7xx_gpio_regs, }; @@ -122,7 +120,6 @@ static struct __initdata resource omap7xx_gpio2_resources[] = { }; static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = { - .virtual_irq_start = IH_GPIO_BASE + 32, .bank_width = 32, .regs = &omap7xx_gpio_regs, }; @@ -151,7 +148,6 @@ static struct __initdata resource omap7xx_gpio3_resources[] = { }; static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = { - .virtual_irq_start = IH_GPIO_BASE + 64, .bank_width = 32, .regs = &omap7xx_gpio_regs, }; @@ -180,7 +176,6 @@ static struct __initdata resource omap7xx_gpio4_resources[] = { }; static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = { - .virtual_irq_start = IH_GPIO_BASE + 96, .bank_width = 32, .regs = &omap7xx_gpio_regs, }; @@ -209,7 +204,6 @@ static struct __initdata resource omap7xx_gpio5_resources[] = { }; static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = { - .virtual_irq_start = IH_GPIO_BASE + 128, .bank_width = 32, .regs = &omap7xx_gpio_regs, }; @@ -238,7 +232,6 @@ static struct __initdata resource omap7xx_gpio6_resources[] = { }; static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = { - .virtual_irq_start = IH_GPIO_BASE + 160, .bank_width = 32, .regs = &omap7xx_gpio_regs, }; diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c index a80e093b039..9ad7d489b0d 100644 --- a/arch/arm/mach-omap2/gpio.c +++ b/arch/arm/mach-omap2/gpio.c @@ -56,7 +56,6 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) dev_attr = (struct omap_gpio_dev_attr *)oh->dev_attr; pdata->bank_width = dev_attr->bank_width; pdata->dbck_flag = dev_attr->dbck_flag; - pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1); pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL); if (!pdata->regs) { @@ -103,6 +102,8 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused) pdata->regs->dataout = OMAP4_GPIO_DATAOUT; pdata->regs->set_dataout = OMAP4_GPIO_SETDATAOUT; pdata->regs->clr_dataout = OMAP4_GPIO_CLEARDATAOUT; + pdata->regs->irqstatus_raw0 = OMAP4_GPIO_IRQSTATUSRAW0; + pdata->regs->irqstatus_raw1 = OMAP4_GPIO_IRQSTATUSRAW1; pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0; pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1; pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0; diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h index 2f6e9924a81..50fb7cc000e 100644 --- a/arch/arm/plat-omap/include/plat/gpio.h +++ b/arch/arm/plat-omap/include/plat/gpio.h @@ -172,6 +172,8 @@ struct omap_gpio_reg_offs { u16 clr_dataout; u16 irqstatus; u16 irqstatus2; + u16 irqstatus_raw0; + u16 irqstatus_raw1; u16 irqenable; u16 irqenable2; u16 set_irqenable; @@ -193,7 +195,6 @@ struct omap_gpio_reg_offs { }; struct omap_gpio_platform_data { - u16 virtual_irq_start; int bank_type; int bank_width; /* GPIO bank width */ int bank_stride; /* Only needed for omap1 MPUIO */ diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index f8bc2d27d14..71d38c76726 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -11,6 +11,7 @@ config AVR32 select GENERIC_ATOMIC64 select HARDIRQS_SW_RESEND select GENERIC_IRQ_SHOW + select ARCH_HAVE_CUSTOM_GPIO_H select ARCH_HAVE_NMI_SAFE_CMPXCHG select GENERIC_CLOCKEVENTS help diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 04ec0d8fbbb..fef96f47876 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -31,6 +31,7 @@ config BLACKFIN select HAVE_KERNEL_LZO if RAMKERNEL select HAVE_OPROFILE select HAVE_PERF_EVENTS + select ARCH_HAVE_CUSTOM_GPIO_H select ARCH_WANT_OPTIONAL_GPIOLIB select HAVE_GENERIC_HARDIRQS select GENERIC_ATOMIC64 diff --git a/arch/ia64/include/asm/gpio.h b/arch/ia64/include/asm/gpio.h index 590a20debc4..b3799d88ffc 100644 --- a/arch/ia64/include/asm/gpio.h +++ b/arch/ia64/include/asm/gpio.h @@ -1,55 +1,4 @@ -/* - * Generic GPIO API implementation for IA-64. - * - * A stright copy of that for PowerPC which was: - * - * Copyright (c) 2007-2008 MontaVista Software, Inc. - * - * Author: Anton Vorontsov <avorontsov@ru.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. - */ - -#ifndef _ASM_IA64_GPIO_H -#define _ASM_IA64_GPIO_H - -#include <linux/errno.h> -#include <asm-generic/gpio.h> - -#ifdef CONFIG_GPIOLIB - -/* - * We don't (yet) implement inlined/rapid versions for on-chip gpios. - * Just call gpiolib. - */ -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(unsigned int gpio) -{ - return __gpio_to_irq(gpio); -} - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* _ASM_IA64_GPIO_H */ +#ifndef __LINUX_GPIO_H +#warning Include linux/gpio.h instead of asm/gpio.h +#include <linux/gpio.h> +#endif diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu index 51b3274cbe7..2b53254ad99 100644 --- a/arch/m68k/Kconfig.cpu +++ b/arch/m68k/Kconfig.cpu @@ -24,6 +24,7 @@ config COLDFIRE bool "Coldfire CPU family support" select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB + select ARCH_HAVE_CUSTOM_GPIO_H select CPU_HAS_NO_BITFIELDS select CPU_HAS_NO_MULDIV64 select GENERIC_CSUM diff --git a/arch/microblaze/include/asm/gpio.h b/arch/microblaze/include/asm/gpio.h index 2b2c18be71c..b3799d88ffc 100644 --- a/arch/microblaze/include/asm/gpio.h +++ b/arch/microblaze/include/asm/gpio.h @@ -1,53 +1,4 @@ -/* - * Generic GPIO API implementation for PowerPC. - * - * Copyright (c) 2007-2008 MontaVista Software, Inc. - * - * Author: Anton Vorontsov <avorontsov@ru.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. - */ - -#ifndef _ASM_MICROBLAZE_GPIO_H -#define _ASM_MICROBLAZE_GPIO_H - -#include <linux/errno.h> -#include <asm-generic/gpio.h> - -#ifdef CONFIG_GPIOLIB - -/* - * We don't (yet) implement inlined/rapid versions for on-chip gpios. - * Just call gpiolib. - */ -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(unsigned int gpio) -{ - return __gpio_to_irq(gpio); -} - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* _ASM_MICROBLAZE_GPIO_H */ +#ifndef __LINUX_GPIO_H +#warning Include linux/gpio.h instead of asm/gpio.h +#include <linux/gpio.h> +#endif diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 3aa826bcbf9..77050671eee 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -8,6 +8,7 @@ config MIPS select HAVE_PERF_EVENTS select PERF_USE_VMALLOC select HAVE_ARCH_KGDB + select ARCH_HAVE_CUSTOM_GPIO_H select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_DYNAMIC_FTRACE diff --git a/arch/openrisc/include/asm/gpio.h b/arch/openrisc/include/asm/gpio.h index 0b0d174f47c..b3799d88ffc 100644 --- a/arch/openrisc/include/asm/gpio.h +++ b/arch/openrisc/include/asm/gpio.h @@ -1,65 +1,4 @@ -/* - * OpenRISC Linux - * - * Linux architectural port borrowing liberally from similar works of - * others. All original copyrights apply as per the original source - * declaration. - * - * OpenRISC implementation: - * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com> - * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> - * et al. - * - * 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. - */ - -#ifndef __ASM_OPENRISC_GPIO_H -#define __ASM_OPENRISC_GPIO_H - -#include <linux/errno.h> -#include <asm-generic/gpio.h> - -#ifdef CONFIG_GPIOLIB - -/* - * OpenRISC (or1k) does not have on-chip GPIO's so there is not really - * any standardized implementation that makes sense here. If passing - * through gpiolib becomes a bottleneck then it may make sense, on a - * case-by-case basis, to implement these inlined/rapid versions. - * - * Just call gpiolib. - */ -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -/* - * Not implemented, yet. - */ -static inline int gpio_to_irq(unsigned int gpio) -{ - return -ENOSYS; -} - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* __ASM_OPENRISC_GPIO_H */ +#ifndef __LINUX_GPIO_H +#warning Include linux/gpio.h instead of asm/gpio.h +#include <linux/gpio.h> +#endif diff --git a/arch/powerpc/include/asm/gpio.h b/arch/powerpc/include/asm/gpio.h index 38762edb5e5..b3799d88ffc 100644 --- a/arch/powerpc/include/asm/gpio.h +++ b/arch/powerpc/include/asm/gpio.h @@ -1,53 +1,4 @@ -/* - * Generic GPIO API implementation for PowerPC. - * - * Copyright (c) 2007-2008 MontaVista Software, Inc. - * - * Author: Anton Vorontsov <avorontsov@ru.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. - */ - -#ifndef __ASM_POWERPC_GPIO_H -#define __ASM_POWERPC_GPIO_H - -#include <linux/errno.h> -#include <asm-generic/gpio.h> - -#ifdef CONFIG_GPIOLIB - -/* - * We don't (yet) implement inlined/rapid versions for on-chip gpios. - * Just call gpiolib. - */ -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(unsigned int gpio) -{ - return __gpio_to_irq(gpio); -} - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* __ASM_POWERPC_GPIO_H */ +#ifndef __LINUX_GPIO_H +#warning Include linux/gpio.h instead of asm/gpio.h +#include <linux/gpio.h> +#endif diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 5e05c0b445b..99bcd0ee838 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -13,6 +13,7 @@ config SUPERH select HAVE_DMA_ATTRS select HAVE_IRQ_WORK select HAVE_PERF_EVENTS + select ARCH_HAVE_CUSTOM_GPIO_H select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A) select PERF_USE_VMALLOC select HAVE_KERNEL_GZIP diff --git a/arch/sparc/include/asm/gpio.h b/arch/sparc/include/asm/gpio.h index a0e3ac0af59..b3799d88ffc 100644 --- a/arch/sparc/include/asm/gpio.h +++ b/arch/sparc/include/asm/gpio.h @@ -1,36 +1,4 @@ -#ifndef __ASM_SPARC_GPIO_H -#define __ASM_SPARC_GPIO_H - -#include <linux/errno.h> -#include <asm-generic/gpio.h> - -#ifdef CONFIG_GPIOLIB - -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(unsigned int gpio) -{ - return -ENOSYS; -} - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* __ASM_SPARC_GPIO_H */ +#ifndef __LINUX_GPIO_H +#warning Include linux/gpio.h instead of asm/gpio.h +#include <linux/gpio.h> +#endif diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig index 47ad5210606..03c9ff808b5 100644 --- a/arch/unicore32/Kconfig +++ b/arch/unicore32/Kconfig @@ -8,6 +8,7 @@ config UNICORE32 select HAVE_KERNEL_BZIP2 select HAVE_KERNEL_LZO select HAVE_KERNEL_LZMA + select ARCH_HAVE_CUSTOM_GPIO_H select GENERIC_FIND_FIRST_BIT select GENERIC_IRQ_PROBE select GENERIC_IRQ_SHOW diff --git a/arch/x86/include/asm/gpio.h b/arch/x86/include/asm/gpio.h index 91d915a6525..b3799d88ffc 100644 --- a/arch/x86/include/asm/gpio.h +++ b/arch/x86/include/asm/gpio.h @@ -1,53 +1,4 @@ -/* - * Generic GPIO API implementation for x86. - * - * Derived from the generic GPIO API for powerpc: - * - * Copyright (c) 2007-2008 MontaVista Software, Inc. - * - * Author: Anton Vorontsov <avorontsov@ru.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. - */ - -#ifndef _ASM_X86_GPIO_H -#define _ASM_X86_GPIO_H - -#include <asm-generic/gpio.h> - -#ifdef CONFIG_GPIOLIB - -/* - * Just call gpiolib. - */ -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(unsigned int gpio) -{ - return __gpio_to_irq(gpio); -} - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* _ASM_X86_GPIO_H */ +#ifndef __LINUX_GPIO_H +#warning Include linux/gpio.h instead of asm/gpio.h +#include <linux/gpio.h> +#endif diff --git a/arch/xtensa/include/asm/gpio.h b/arch/xtensa/include/asm/gpio.h index a8c9fc46c79..b3799d88ffc 100644 --- a/arch/xtensa/include/asm/gpio.h +++ b/arch/xtensa/include/asm/gpio.h @@ -1,56 +1,4 @@ -/* - * Generic GPIO API implementation for xtensa. - * - * Stolen from x86, which is derived from the generic GPIO API for powerpc: - * - * Copyright (c) 2007-2008 MontaVista Software, Inc. - * - * Author: Anton Vorontsov <avorontsov@ru.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. - */ - -#ifndef _ASM_XTENSA_GPIO_H -#define _ASM_XTENSA_GPIO_H - -#include <asm-generic/gpio.h> - -#ifdef CONFIG_GPIOLIB - -/* - * Just call gpiolib. - */ -static inline int gpio_get_value(unsigned int gpio) -{ - return __gpio_get_value(gpio); -} - -static inline void gpio_set_value(unsigned int gpio, int value) -{ - __gpio_set_value(gpio, value); -} - -static inline int gpio_cansleep(unsigned int gpio) -{ - return __gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(unsigned int gpio) -{ - return __gpio_to_irq(gpio); -} - -/* - * Not implemented, yet. - */ -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif /* CONFIG_GPIOLIB */ - -#endif /* _ASM_XTENSA_GPIO_H */ +#ifndef __LINUX_GPIO_H +#warning Include linux/gpio.h instead of asm/gpio.h +#include <linux/gpio.h> +#endif diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index eb80ba30045..aa3642cb820 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -2,6 +2,14 @@ # GPIO infrastructure and drivers # +config ARCH_HAVE_CUSTOM_GPIO_H + bool + help + Selecting this config option from the architecture Kconfig allows + the architecture to provide a custom asm/gpio.h implementation + overriding the default implementations. New uses of this are + strongly discouraged. + config ARCH_WANT_OPTIONAL_GPIOLIB bool help @@ -37,6 +45,10 @@ menuconfig GPIOLIB if GPIOLIB +config OF_GPIO + def_bool y + depends on OF && !SPARC + config DEBUG_GPIO bool "Debug GPIO calls" depends on DEBUG_KERNEL @@ -249,7 +261,7 @@ config GPIO_MC9S08DZ60 Select this to enable the MC9S08DZ60 GPIO driver config GPIO_PCA953X - tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports" + tristate "PCA953x, PCA955x, PCA957x, TCA64xx, and MAX7310 I/O ports" depends on I2C help Say yes here to provide access to several register-oriented @@ -258,10 +270,11 @@ config GPIO_PCA953X 4 bits: pca9536, pca9537 - 8 bits: max7310, pca9534, pca9538, pca9554, pca9557, - tca6408 + 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554, + pca9556, pca9557, pca9574, tca6408 - 16 bits: pca9535, pca9539, pca9555, tca6416 + 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575, + tca6416 config GPIO_PCA953X_IRQ bool "Interrupt controller support for PCA953x" @@ -294,6 +307,15 @@ config GPIO_PCF857X This driver provides an in-kernel interface to those GPIOs using platform-neutral GPIO calls. +config GPIO_RC5T583 + bool "RICOH RC5T583 GPIO" + depends on MFD_RC5T583 + help + Select this option to enable GPIO driver for the Ricoh RC5T583 + chip family. + This driver provides the support for driving/reading the gpio pins + of RC5T583 device through standard gpio library. + config GPIO_SX150X bool "Semtech SX150x I2C GPIO expander" depends on I2C=y @@ -405,6 +427,7 @@ config GPIO_BT8XX config GPIO_LANGWELL bool "Intel Langwell/Penwell GPIO support" depends on PCI && X86 + select IRQ_DOMAIN help Say Y here to support Intel Langwell/Penwell GPIO. @@ -520,4 +543,12 @@ config GPIO_TPS65910 help Select this option to enable GPIO driver for the TPS65910 chip family. + +config GPIO_MSIC + bool "Intel MSIC mixed signal gpio support" + depends on MFD_INTEL_MSIC + help + Enable support for GPIO on intel MSIC controllers found in + intel MID devices + endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 708ffb2165e..07a79e24540 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -3,6 +3,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o +obj-$(CONFIG_OF_GPIO) += gpiolib-of.o # Device drivers. Generally keep list sorted alphabetically obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o @@ -33,6 +34,7 @@ obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o +obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o @@ -43,6 +45,7 @@ obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o obj-$(CONFIG_GPIO_PCH) += gpio-pch.o obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o +obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 8950f6261bb..9e9947cb86a 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -71,6 +71,35 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label) EXPORT_SYMBOL(devm_gpio_request); /** + * devm_gpio_request_one - request a single GPIO with initial setup + * @dev: device to request for + * @gpio: the GPIO number + * @flags: GPIO configuration as specified by GPIOF_* + * @label: a literal description string of this GPIO + */ +int devm_gpio_request_one(struct device *dev, unsigned gpio, + unsigned long flags, const char *label) +{ + unsigned *dr; + int rc; + + dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + rc = gpio_request_one(gpio, flags, label); + if (rc) { + devres_free(dr); + return rc; + } + + *dr = gpio; + devres_add(dev, dr); + + return 0; +} + +/** * devm_gpio_free - free an interrupt * @dev: device to free gpio for * @gpio: gpio to free diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index 5ca4098ba09..e4cc7eb69bb 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -328,17 +328,7 @@ static struct pci_driver bt8xxgpio_pci_driver = { .resume = bt8xxgpio_resume, }; -static int __init bt8xxgpio_init(void) -{ - return pci_register_driver(&bt8xxgpio_pci_driver); -} -module_init(bt8xxgpio_init) - -static void __exit bt8xxgpio_exit(void) -{ - pci_unregister_driver(&bt8xxgpio_pci_driver); -} -module_exit(bt8xxgpio_exit) +module_pci_driver(bt8xxgpio_pci_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Buesch"); diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 776b772523e..9fe5b8fe9be 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -325,7 +325,7 @@ static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev, void __iomem *dir = mmio_base + bank->dir; int err; - err = bgpio_init(bgc, dev, 1, data, NULL, NULL, dir, NULL, false); + err = bgpio_init(bgc, dev, 1, data, NULL, NULL, dir, NULL, 0); if (err) return err; diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index e38dd0c3197..82e2e4fe599 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -364,7 +364,7 @@ EXPORT_SYMBOL_GPL(bgpio_remove); int bgpio_init(struct bgpio_chip *bgc, struct device *dev, unsigned long sz, void __iomem *dat, void __iomem *set, void __iomem *clr, void __iomem *dirout, void __iomem *dirin, - bool big_endian) + unsigned long flags) { int ret; @@ -385,7 +385,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, if (ret) return ret; - ret = bgpio_setup_accessors(dev, bgc, big_endian); + ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN); if (ret) return ret; @@ -394,6 +394,11 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, return ret; bgc->data = bgc->read_reg(bgc->reg_dat); + if (bgc->gc.set == bgpio_set_set && + !(flags & BGPIOF_UNREADABLE_REG_SET)) + bgc->data = bgc->read_reg(bgc->reg_set); + if (bgc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR)) + bgc->dir = bgc->read_reg(bgc->reg_dir); return ret; } @@ -449,7 +454,7 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev) void __iomem *dirout; void __iomem *dirin; unsigned long sz; - bool be; + unsigned long flags = 0; int err; struct bgpio_chip *bgc; struct bgpio_pdata *pdata = dev_get_platdata(dev); @@ -480,13 +485,14 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev) if (err) return err; - be = !strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be"); + if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be")) + flags |= BGPIOF_BIG_ENDIAN; bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); if (!bgc) return -ENOMEM; - err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, be); + err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, flags); if (err) return err; diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c index 00692e89ef8..a1c8754f52c 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c @@ -36,6 +36,7 @@ #include <linux/gpio.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/irqdomain.h> /* * Langwell chip has 64 pins and thus there are 2 32bit registers to control @@ -66,8 +67,8 @@ struct lnw_gpio { struct gpio_chip chip; void *reg_base; spinlock_t lock; - unsigned irq_base; struct pci_dev *pdev; + struct irq_domain *domain; }; static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, @@ -176,13 +177,13 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip, static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip); - return lnw->irq_base + offset; + return irq_create_mapping(lnw->domain, offset); } static int lnw_irq_type(struct irq_data *d, unsigned type) { struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d); - u32 gpio = d->irq - lnw->irq_base; + u32 gpio = irqd_to_hwirq(d); unsigned long flags; u32 value; void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); @@ -249,20 +250,55 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) /* check GPIO controller to check which pin triggered the interrupt */ for (base = 0; base < lnw->chip.ngpio; base += 32) { gedr = gpio_reg(&lnw->chip, base, GEDR); - pending = readl(gedr); - while (pending) { + while ((pending = readl(gedr))) { gpio = __ffs(pending); mask = BIT(gpio); - pending &= ~mask; /* Clear before handling so we can't lose an edge */ writel(mask, gedr); - generic_handle_irq(lnw->irq_base + base + gpio); + generic_handle_irq(irq_find_mapping(lnw->domain, + base + gpio)); } } chip->irq_eoi(data); } +static void lnw_irq_init_hw(struct lnw_gpio *lnw) +{ + void __iomem *reg; + unsigned base; + + for (base = 0; base < lnw->chip.ngpio; base += 32) { + /* Clear the rising-edge detect register */ + reg = gpio_reg(&lnw->chip, base, GRER); + writel(0, reg); + /* Clear the falling-edge detect register */ + reg = gpio_reg(&lnw->chip, base, GFER); + writel(0, reg); + /* Clear the edge detect status register */ + reg = gpio_reg(&lnw->chip, base, GEDR); + writel(~0, reg); + } +} + +static int lnw_gpio_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + struct lnw_gpio *lnw = d->host_data; + + irq_set_chip_and_handler_name(virq, &lnw_irqchip, handle_simple_irq, + "demux"); + irq_set_chip_data(virq, lnw); + irq_set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static const struct irq_domain_ops lnw_gpio_irq_ops = { + .map = lnw_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + #ifdef CONFIG_PM static int lnw_gpio_runtime_resume(struct device *dev) { @@ -300,23 +336,22 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void *base; - int i; resource_size_t start, len; struct lnw_gpio *lnw; - u32 irq_base; u32 gpio_base; int retval = 0; + int ngpio = id->driver_data; retval = pci_enable_device(pdev); if (retval) - goto done; + return retval; retval = pci_request_regions(pdev, "langwell_gpio"); if (retval) { dev_err(&pdev->dev, "error requesting resources\n"); goto err2; } - /* get the irq_base from bar1 */ + /* get the gpio_base from bar1 */ start = pci_resource_start(pdev, 1); len = pci_resource_len(pdev, 1); base = ioremap_nocache(start, len); @@ -324,28 +359,32 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "error mapping bar1\n"); goto err3; } - irq_base = *(u32 *)base; gpio_base = *((u32 *)base + 1); /* release the IO mapping, since we already get the info from bar1 */ iounmap(base); /* get the register base from bar0 */ start = pci_resource_start(pdev, 0); len = pci_resource_len(pdev, 0); - base = ioremap_nocache(start, len); + base = devm_ioremap_nocache(&pdev->dev, start, len); if (!base) { dev_err(&pdev->dev, "error mapping bar0\n"); retval = -EFAULT; goto err3; } - lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL); + lnw = devm_kzalloc(&pdev->dev, sizeof(struct lnw_gpio), GFP_KERNEL); if (!lnw) { dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n"); retval = -ENOMEM; - goto err4; + goto err3; } + + lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio, + &lnw_gpio_irq_ops, lnw); + if (!lnw->domain) + goto err3; + 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; @@ -354,38 +393,32 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, lnw->chip.set = lnw_gpio_set; lnw->chip.to_irq = lnw_gpio_to_irq; lnw->chip.base = gpio_base; - lnw->chip.ngpio = id->driver_data; + lnw->chip.ngpio = ngpio; lnw->chip.can_sleep = 0; lnw->pdev = pdev; pci_set_drvdata(pdev, lnw); retval = gpiochip_add(&lnw->chip); if (retval) { dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); - goto err5; + goto err3; } + + lnw_irq_init_hw(lnw); + irq_set_handler_data(pdev->irq, lnw); irq_set_chained_handler(pdev->irq, lnw_irq_handler); - for (i = 0; i < lnw->chip.ngpio; i++) { - irq_set_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip, - handle_simple_irq, "demux"); - irq_set_chip_data(i + lnw->irq_base, lnw); - } spin_lock_init(&lnw->lock); pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); - goto done; -err5: - kfree(lnw); -err4: - iounmap(base); + return 0; + err3: pci_release_regions(pdev); err2: pci_disable_device(pdev); -done: return retval; } diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 61c2d08d37b..c2199beca98 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -21,6 +21,9 @@ #include <linux/io.h> #include <linux/errno.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/module.h> #include <mach/hardware.h> #include <mach/platform.h> @@ -454,10 +457,57 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { }, }; +/* Empty now, can be removed later when mach-lpc32xx is finally switched over + * to DT support + */ void __init lpc32xx_gpio_init(void) { +} + +static int lpc32xx_of_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + /* Is this the correct bank? */ + u32 bank = gpiospec->args[0]; + if ((bank > ARRAY_SIZE(lpc32xx_gpiochip) || + (gc != &lpc32xx_gpiochip[bank].chip))) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[2]; + return gpiospec->args[1]; +} + +static int __devinit lpc32xx_gpio_probe(struct platform_device *pdev) +{ int i; - for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) + for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) { + if (pdev->dev.of_node) { + lpc32xx_gpiochip[i].chip.of_xlate = lpc32xx_of_xlate; + lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3; + lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node; + } gpiochip_add(&lpc32xx_gpiochip[i].chip); + } + + return 0; } + +#ifdef CONFIG_OF +static struct of_device_id lpc32xx_gpio_of_match[] __devinitdata = { + { .compatible = "nxp,lpc3220-gpio", }, + { }, +}; +#endif + +static struct platform_driver lpc32xx_gpio_driver = { + .driver = { + .name = "lpc32xx-gpio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lpc32xx_gpio_of_match), + }, + .probe = lpc32xx_gpio_probe, +}; + +module_platform_driver(lpc32xx_gpio_driver); diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index c5d83a8a91c..0f425189de1 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -353,7 +353,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) chip->base + t, bank, t, label, (mcp->cache[MCP_IODIR] & mask) ? "in " : "out", (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo", - (mcp->cache[MCP_GPPU] & mask) ? " " : "up"); + (mcp->cache[MCP_GPPU] & mask) ? "up" : " "); /* NOTE: ignoring the irq-related registers */ seq_printf(s, "\n"); } diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index f0febe5b822..db01f151d41 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -611,17 +611,7 @@ static struct pci_driver ioh_gpio_driver = { .resume = ioh_gpio_resume }; -static int __init ioh_gpio_pci_init(void) -{ - return pci_register_driver(&ioh_gpio_driver); -} -module_init(ioh_gpio_pci_init); - -static void __exit ioh_gpio_pci_exit(void) -{ - pci_unregister_driver(&ioh_gpio_driver); -} -module_exit(ioh_gpio_pci_exit); +module_pci_driver(ioh_gpio_driver); MODULE_DESCRIPTION("OKI SEMICONDUCTOR ML-IOH series GPIO Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index e6568c19c93..5a1817eedd1 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -163,7 +163,8 @@ static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc) if (mask) generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, 32 - ffs(mask))); - chip->irq_eoi(&desc->irq_data); + if (chip->irq_eoi) + chip->irq_eoi(&desc->irq_data); } static void mpc8xxx_irq_unmask(struct irq_data *d) diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c new file mode 100644 index 00000000000..71a838f4450 --- /dev/null +++ b/drivers/gpio/gpio-msic.c @@ -0,0 +1,339 @@ +/* + * Intel Medfield MSIC GPIO driver> + * Copyright (c) 2011, Intel Corporation. + * + * Author: Mathias Nyman <mathias.nyman@linux.intel.com> + * Based on intel_pmic_gpio.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/mfd/intel_msic.h> + +/* the offset for the mapping of global gpio pin to irq */ +#define MSIC_GPIO_IRQ_OFFSET 0x100 + +#define MSIC_GPIO_DIR_IN 0 +#define MSIC_GPIO_DIR_OUT BIT(5) +#define MSIC_GPIO_TRIG_FALL BIT(1) +#define MSIC_GPIO_TRIG_RISE BIT(2) + +/* masks for msic gpio output GPIOxxxxCTLO registers */ +#define MSIC_GPIO_DIR_MASK BIT(5) +#define MSIC_GPIO_DRV_MASK BIT(4) +#define MSIC_GPIO_REN_MASK BIT(3) +#define MSIC_GPIO_RVAL_MASK (BIT(2) | BIT(1)) +#define MSIC_GPIO_DOUT_MASK BIT(0) + +/* masks for msic gpio input GPIOxxxxCTLI registers */ +#define MSIC_GPIO_GLBYP_MASK BIT(5) +#define MSIC_GPIO_DBNC_MASK (BIT(4) | BIT(3)) +#define MSIC_GPIO_INTCNT_MASK (BIT(2) | BIT(1)) +#define MSIC_GPIO_DIN_MASK BIT(0) + +#define MSIC_NUM_GPIO 24 + +struct msic_gpio { + struct platform_device *pdev; + struct mutex buslock; + struct gpio_chip chip; + int irq; + unsigned irq_base; + unsigned long trig_change_mask; + unsigned trig_type; +}; + +/* + * MSIC has 24 gpios, 16 low voltage (1.2-1.8v) and 8 high voltage (3v). + * Both the high and low voltage gpios are divided in two banks. + * GPIOs are numbered with GPIO0LV0 as gpio_base in the following order: + * GPIO0LV0..GPIO0LV7: low voltage, bank 0, gpio_base + * GPIO1LV0..GPIO1LV7: low voltage, bank 1, gpio_base + 8 + * GPIO0HV0..GPIO0HV3: high voltage, bank 0, gpio_base + 16 + * GPIO1HV0..GPIO1HV3: high voltage, bank 1, gpio_base + 20 + */ + +static int msic_gpio_to_ireg(unsigned offset) +{ + if (offset >= MSIC_NUM_GPIO) + return -EINVAL; + + if (offset < 8) + return INTEL_MSIC_GPIO0LV0CTLI - offset; + if (offset < 16) + return INTEL_MSIC_GPIO1LV0CTLI - offset + 8; + if (offset < 20) + return INTEL_MSIC_GPIO0HV0CTLI - offset + 16; + + return INTEL_MSIC_GPIO1HV0CTLI - offset + 20; +} + +static int msic_gpio_to_oreg(unsigned offset) +{ + if (offset >= MSIC_NUM_GPIO) + return -EINVAL; + + if (offset < 8) + return INTEL_MSIC_GPIO0LV0CTLO - offset; + if (offset < 16) + return INTEL_MSIC_GPIO1LV0CTLO - offset + 8; + if (offset < 20) + return INTEL_MSIC_GPIO0HV0CTLO - offset + 16; + + return INTEL_MSIC_GPIO1HV0CTLO + offset + 20; +} + +static int msic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + int reg; + + reg = msic_gpio_to_oreg(offset); + if (reg < 0) + return reg; + + return intel_msic_reg_update(reg, MSIC_GPIO_DIR_IN, MSIC_GPIO_DIR_MASK); +} + +static int msic_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + int reg; + unsigned mask; + + value = (!!value) | MSIC_GPIO_DIR_OUT; + mask = MSIC_GPIO_DIR_MASK | MSIC_GPIO_DOUT_MASK; + + reg = msic_gpio_to_oreg(offset); + if (reg < 0) + return reg; + + return intel_msic_reg_update(reg, value, mask); +} + +static int msic_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + u8 r; + int ret; + int reg; + + reg = msic_gpio_to_ireg(offset); + if (reg < 0) + return reg; + + ret = intel_msic_reg_read(reg, &r); + if (ret < 0) + return ret; + + return r & MSIC_GPIO_DIN_MASK; +} + +static void msic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + int reg; + + reg = msic_gpio_to_oreg(offset); + if (reg < 0) + return; + + intel_msic_reg_update(reg, !!value , MSIC_GPIO_DOUT_MASK); +} + +/* + * This is called from genirq with mg->buslock locked and + * irq_desc->lock held. We can not access the scu bus here, so we + * store the change and update in the bus_sync_unlock() function below + */ +static int msic_irq_type(struct irq_data *data, unsigned type) +{ + struct msic_gpio *mg = irq_data_get_irq_chip_data(data); + u32 gpio = data->irq - mg->irq_base; + + if (gpio >= mg->chip.ngpio) + return -EINVAL; + + /* mark for which gpio the trigger changed, protected by buslock */ + mg->trig_change_mask |= (1 << gpio); + mg->trig_type = type; + + return 0; +} + +static int msic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct msic_gpio *mg = container_of(chip, struct msic_gpio, chip); + return mg->irq_base + offset; +} + +static void msic_bus_lock(struct irq_data *data) +{ + struct msic_gpio *mg = irq_data_get_irq_chip_data(data); + mutex_lock(&mg->buslock); +} + +static void msic_bus_sync_unlock(struct irq_data *data) +{ + struct msic_gpio *mg = irq_data_get_irq_chip_data(data); + int offset; + int reg; + u8 trig = 0; + + /* We can only get one change at a time as the buslock covers the + entire transaction. The irq_desc->lock is dropped before we are + called but that is fine */ + if (mg->trig_change_mask) { + offset = __ffs(mg->trig_change_mask); + + reg = msic_gpio_to_ireg(offset); + if (reg < 0) + goto out; + + if (mg->trig_type & IRQ_TYPE_EDGE_RISING) + trig |= MSIC_GPIO_TRIG_RISE; + if (mg->trig_type & IRQ_TYPE_EDGE_FALLING) + trig |= MSIC_GPIO_TRIG_FALL; + + intel_msic_reg_update(reg, trig, MSIC_GPIO_INTCNT_MASK); + mg->trig_change_mask = 0; + } +out: + mutex_unlock(&mg->buslock); +} + +/* Firmware does all the masking and unmasking for us, no masking here. */ +static void msic_irq_unmask(struct irq_data *data) { } + +static void msic_irq_mask(struct irq_data *data) { } + +static struct irq_chip msic_irqchip = { + .name = "MSIC-GPIO", + .irq_mask = msic_irq_mask, + .irq_unmask = msic_irq_unmask, + .irq_set_type = msic_irq_type, + .irq_bus_lock = msic_bus_lock, + .irq_bus_sync_unlock = msic_bus_sync_unlock, +}; + +static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_data *data = irq_desc_get_irq_data(desc); + struct msic_gpio *mg = irq_data_get_irq_handler_data(data); + struct irq_chip *chip = irq_data_get_irq_chip(data); + struct intel_msic *msic = pdev_to_intel_msic(mg->pdev); + int i; + int bitnr; + u8 pin; + unsigned long pending = 0; + + for (i = 0; i < (mg->chip.ngpio / BITS_PER_BYTE); i++) { + intel_msic_irq_read(msic, INTEL_MSIC_GPIO0LVIRQ + i, &pin); + pending = pin; + + if (pending) { + for_each_set_bit(bitnr, &pending, BITS_PER_BYTE) + generic_handle_irq(mg->irq_base + + (i * BITS_PER_BYTE) + bitnr); + } + } + chip->irq_eoi(data); +} + +static int __devinit platform_msic_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct intel_msic_gpio_pdata *pdata = dev->platform_data; + struct msic_gpio *mg; + int irq = platform_get_irq(pdev, 0); + int retval; + int i; + + if (irq < 0) { + dev_err(dev, "no IRQ line\n"); + return -EINVAL; + } + + if (!pdata || !pdata->gpio_base) { + dev_err(dev, "incorrect or missing platform data\n"); + return -EINVAL; + } + + mg = kzalloc(sizeof(*mg), GFP_KERNEL); + if (!mg) + return -ENOMEM; + + dev_set_drvdata(dev, mg); + + mg->pdev = pdev; + mg->irq = irq; + mg->irq_base = pdata->gpio_base + MSIC_GPIO_IRQ_OFFSET; + mg->chip.label = "msic_gpio"; + mg->chip.direction_input = msic_gpio_direction_input; + mg->chip.direction_output = msic_gpio_direction_output; + mg->chip.get = msic_gpio_get; + mg->chip.set = msic_gpio_set; + mg->chip.to_irq = msic_gpio_to_irq; + mg->chip.base = pdata->gpio_base; + mg->chip.ngpio = MSIC_NUM_GPIO; + mg->chip.can_sleep = 1; + mg->chip.dev = dev; + + mutex_init(&mg->buslock); + + retval = gpiochip_add(&mg->chip); + if (retval) { + dev_err(dev, "Adding MSIC gpio chip failed\n"); + goto err; + } + + for (i = 0; i < mg->chip.ngpio; i++) { + irq_set_chip_data(i + mg->irq_base, mg); + irq_set_chip_and_handler_name(i + mg->irq_base, + &msic_irqchip, + handle_simple_irq, + "demux"); + } + irq_set_chained_handler(mg->irq, msic_gpio_irq_handler); + irq_set_handler_data(mg->irq, mg); + + return 0; +err: + kfree(mg); + return retval; +} + +static struct platform_driver platform_msic_gpio_driver = { + .driver = { + .name = "msic_gpio", + .owner = THIS_MODULE, + }, + .probe = platform_msic_gpio_probe, +}; + +static int __init platform_msic_gpio_init(void) +{ + return platform_driver_register(&platform_msic_gpio_driver); +} + +subsys_initcall(platform_msic_gpio_init); + +MODULE_AUTHOR("Mathias Nyman <mathias.nyman@linux.intel.com>"); +MODULE_DESCRIPTION("Intel Medfield MSIC GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index e7914763457..c337143b18f 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -417,7 +417,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev) err = bgpio_init(&port->bgc, &pdev->dev, 4, port->base + GPIO_PSR, port->base + GPIO_DR, NULL, - port->base + GPIO_GDIR, NULL, false); + port->base + GPIO_GDIR, NULL, 0); if (err) goto out_iounmap; diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 385c58e8405..b4136501abd 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -244,7 +244,7 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev) err = bgpio_init(&port->bgc, &pdev->dev, 4, port->base + PINCTRL_DIN(port->id), port->base + PINCTRL_DOUT(port->id), NULL, - port->base + PINCTRL_DOE(port->id), NULL, false); + port->base + PINCTRL_DOE(port->id), NULL, 0); if (err) goto out_iounmap; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 4461540653a..c4ed1722734 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -57,14 +57,10 @@ struct gpio_bank { u16 irq; int irq_base; struct irq_domain *domain; - u32 suspend_wakeup; - u32 saved_wakeup; u32 non_wakeup_gpios; u32 enabled_non_wakeup_gpios; struct gpio_regs context; u32 saved_datain; - u32 saved_fallingdetect; - u32 saved_risingdetect; u32 level_mask; u32 toggle_mask; spinlock_t lock; @@ -516,11 +512,11 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable) spin_lock_irqsave(&bank->lock, flags); if (enable) - bank->suspend_wakeup |= gpio_bit; + bank->context.wake_en |= gpio_bit; else - bank->suspend_wakeup &= ~gpio_bit; + bank->context.wake_en &= ~gpio_bit; - __raw_writel(bank->suspend_wakeup, bank->base + bank->regs->wkup_en); + __raw_writel(bank->context.wake_en, bank->base + bank->regs->wkup_en); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -640,7 +636,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) u32 isr; unsigned int gpio_irq, gpio_index; struct gpio_bank *bank; - u32 retrigger = 0; int unmasked = 0; struct irq_chip *chip = irq_desc_get_chip(desc); @@ -677,8 +672,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } - isr |= retrigger; - retrigger = 0; if (!isr) break; @@ -789,8 +782,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - bank->saved_wakeup = __raw_readl(mask_reg); - __raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg); + __raw_writel(0xffff & ~bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -805,7 +797,7 @@ static int omap_mpuio_resume_noirq(struct device *dev) unsigned long flags; spin_lock_irqsave(&bank->lock, flags); - __raw_writel(bank->saved_wakeup, mask_reg); + __raw_writel(bank->context.wake_en, mask_reg); spin_unlock_irqrestore(&bank->lock, flags); return 0; @@ -1152,54 +1144,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_OMAP2PLUS -#if defined(CONFIG_PM_SLEEP) -static int omap_gpio_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct gpio_bank *bank = platform_get_drvdata(pdev); - void __iomem *base = bank->base; - void __iomem *wakeup_enable; - unsigned long flags; - - if (!bank->mod_usage || !bank->loses_context) - return 0; - - if (!bank->regs->wkup_en || !bank->suspend_wakeup) - return 0; - - wakeup_enable = bank->base + bank->regs->wkup_en; - - spin_lock_irqsave(&bank->lock, flags); - bank->saved_wakeup = __raw_readl(wakeup_enable); - _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0); - _gpio_rmw(base, bank->regs->wkup_en, bank->suspend_wakeup, 1); - spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} - -static int omap_gpio_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct gpio_bank *bank = platform_get_drvdata(pdev); - void __iomem *base = bank->base; - unsigned long flags; - - if (!bank->mod_usage || !bank->loses_context) - return 0; - - if (!bank->regs->wkup_en || !bank->saved_wakeup) - return 0; - - spin_lock_irqsave(&bank->lock, flags); - _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0); - _gpio_rmw(base, bank->regs->wkup_en, bank->saved_wakeup, 1); - spin_unlock_irqrestore(&bank->lock, flags); - - return 0; -} -#endif /* CONFIG_PM_SLEEP */ - #if defined(CONFIG_PM_RUNTIME) static void omap_gpio_restore_context(struct gpio_bank *bank); @@ -1233,6 +1177,9 @@ static int omap_gpio_runtime_suspend(struct device *dev) __raw_writel(wake_hi | bank->context.risingdetect, bank->base + bank->regs->risingdetect); + if (!bank->enabled_non_wakeup_gpios) + goto update_gpio_context_count; + if (bank->power_mode != OFF_MODE) { bank->power_mode = 0; goto update_gpio_context_count; @@ -1244,11 +1191,9 @@ static int omap_gpio_runtime_suspend(struct device *dev) */ bank->saved_datain = __raw_readl(bank->base + bank->regs->datain); - l1 = __raw_readl(bank->base + bank->regs->fallingdetect); - l2 = __raw_readl(bank->base + bank->regs->risingdetect); + l1 = bank->context.fallingdetect; + l2 = bank->context.risingdetect; - bank->saved_fallingdetect = l1; - bank->saved_risingdetect = l2; l1 &= ~bank->enabled_non_wakeup_gpios; l2 &= ~bank->enabled_non_wakeup_gpios; @@ -1290,16 +1235,10 @@ static int omap_gpio_runtime_resume(struct device *dev) __raw_writel(bank->context.risingdetect, bank->base + bank->regs->risingdetect); - if (!bank->workaround_enabled) { - spin_unlock_irqrestore(&bank->lock, flags); - return 0; - } - if (bank->get_context_loss_count) { context_lost_cnt_after = bank->get_context_loss_count(bank->dev); - if (context_lost_cnt_after != bank->context_loss_count || - !context_lost_cnt_after) { + if (context_lost_cnt_after != bank->context_loss_count) { omap_gpio_restore_context(bank); } else { spin_unlock_irqrestore(&bank->lock, flags); @@ -1307,9 +1246,14 @@ static int omap_gpio_runtime_resume(struct device *dev) } } - __raw_writel(bank->saved_fallingdetect, + if (!bank->workaround_enabled) { + spin_unlock_irqrestore(&bank->lock, flags); + return 0; + } + + __raw_writel(bank->context.fallingdetect, bank->base + bank->regs->fallingdetect); - __raw_writel(bank->saved_risingdetect, + __raw_writel(bank->context.risingdetect, bank->base + bank->regs->risingdetect); l = __raw_readl(bank->base + bank->regs->datain); @@ -1326,14 +1270,15 @@ static int omap_gpio_runtime_resume(struct device *dev) * No need to generate IRQs for the rising edge for gpio IRQs * configured with falling edge only; and vice versa. */ - gen0 = l & bank->saved_fallingdetect; + gen0 = l & bank->context.fallingdetect; gen0 &= bank->saved_datain; - gen1 = l & bank->saved_risingdetect; + gen1 = l & bank->context.risingdetect; gen1 &= ~(bank->saved_datain); /* FIXME: Consider GPIO IRQs with level detections properly! */ - gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect)); + gen = l & (~(bank->context.fallingdetect) & + ~(bank->context.risingdetect)); /* Consider all GPIO IRQs needed to be updated */ gen |= gen0 | gen1; @@ -1343,14 +1288,14 @@ static int omap_gpio_runtime_resume(struct device *dev) old0 = __raw_readl(bank->base + bank->regs->leveldetect0); old1 = __raw_readl(bank->base + bank->regs->leveldetect1); - if (cpu_is_omap24xx() || cpu_is_omap34xx()) { + if (!bank->regs->irqstatus_raw0) { __raw_writel(old0 | gen, bank->base + bank->regs->leveldetect0); __raw_writel(old1 | gen, bank->base + bank->regs->leveldetect1); } - if (cpu_is_omap44xx()) { + if (bank->regs->irqstatus_raw0) { __raw_writel(old0 | l, bank->base + bank->regs->leveldetect0); __raw_writel(old1 | l, bank->base + @@ -1429,14 +1374,11 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) } #endif /* CONFIG_PM_RUNTIME */ #else -#define omap_gpio_suspend NULL -#define omap_gpio_resume NULL #define omap_gpio_runtime_suspend NULL #define omap_gpio_runtime_resume NULL #endif static const struct dev_pm_ops gpio_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume, NULL) }; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index d3f3e8f5456..1c313c710be 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -28,6 +28,8 @@ #define PCA953X_INVERT 2 #define PCA953X_DIRECTION 3 +#define REG_ADDR_AI 0x80 + #define PCA957X_IN 0 #define PCA957X_INVRT 1 #define PCA957X_BKEN 2 @@ -63,15 +65,15 @@ static const struct i2c_device_id pca953x_id[] = { { "pca6107", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6408", 8 | PCA953X_TYPE | PCA_INT, }, { "tca6416", 16 | PCA953X_TYPE | PCA_INT, }, - /* NYET: { "tca6424", 24, }, */ + { "tca6424", 24 | PCA953X_TYPE | PCA_INT, }, { } }; MODULE_DEVICE_TABLE(i2c, pca953x_id); struct pca953x_chip { unsigned gpio_start; - uint16_t reg_output; - uint16_t reg_direction; + u32 reg_output; + u32 reg_direction; struct mutex i2c_lock; #ifdef CONFIG_GPIO_PCA953X_IRQ @@ -89,12 +91,20 @@ struct pca953x_chip { int chip_type; }; -static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) +static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val) { int ret = 0; if (chip->gpio_chip.ngpio <= 8) ret = i2c_smbus_write_byte_data(chip->client, reg, val); + else if (chip->gpio_chip.ngpio == 24) { + ret = i2c_smbus_write_word_data(chip->client, + (reg << 2) | REG_ADDR_AI, + val & 0xffff); + ret = i2c_smbus_write_byte_data(chip->client, + (reg << 2) + 2, + (val & 0xff0000) >> 16); + } else { switch (chip->chip_type) { case PCA953X_TYPE: @@ -121,12 +131,17 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) return 0; } -static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) +static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val) { int ret; if (chip->gpio_chip.ngpio <= 8) ret = i2c_smbus_read_byte_data(chip->client, reg); + else if (chip->gpio_chip.ngpio == 24) { + ret = i2c_smbus_read_word_data(chip->client, reg << 2); + ret |= (i2c_smbus_read_byte_data(chip->client, + (reg << 2) + 2)<<16); + } else ret = i2c_smbus_read_word_data(chip->client, reg << 1); @@ -135,14 +150,14 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) return ret; } - *val = (uint16_t)ret; + *val = (u32)ret; return 0; } static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) { struct pca953x_chip *chip; - uint16_t reg_val; + uint reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); @@ -173,7 +188,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { struct pca953x_chip *chip; - uint16_t reg_val; + uint reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); @@ -223,7 +238,7 @@ exit: static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) { struct pca953x_chip *chip; - uint16_t reg_val; + u32 reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); @@ -253,7 +268,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) { struct pca953x_chip *chip; - uint16_t reg_val; + u32 reg_val; int ret, offset = 0; chip = container_of(gc, struct pca953x_chip, gpio_chip); @@ -386,7 +401,7 @@ static struct irq_chip pca953x_irq_chip = { static uint16_t pca953x_irq_pending(struct pca953x_chip *chip) { - uint16_t cur_stat; + u32 cur_stat; uint16_t old_stat; uint16_t pending; uint16_t trigger; @@ -449,6 +464,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, { struct i2c_client *client = chip->client; int ret, offset = 0; + u32 temporary; if (irq_base != -1 && (id->driver_data & PCA_INT)) { @@ -462,7 +478,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, offset = PCA957X_IN; break; } - ret = pca953x_read_reg(chip, offset, &chip->irq_stat); + ret = pca953x_read_reg(chip, offset, &temporary); + chip->irq_stat = temporary; if (ret) goto out_failed; @@ -603,7 +620,7 @@ out: static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert) { int ret; - uint16_t val = 0; + u32 val = 0; /* Let every port in proper state, that could save power */ pca953x_write_reg(chip, PCA957X_PUPD, 0x0); diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 2cd958e0b82..139ad3e2001 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -538,17 +538,7 @@ static struct pci_driver pch_gpio_driver = { .resume = pch_gpio_resume }; -static int __init pch_gpio_pci_init(void) -{ - return pci_register_driver(&pch_gpio_driver); -} -module_init(pch_gpio_pci_init); - -static void __exit pch_gpio_pci_exit(void) -{ - pci_unregister_driver(&pch_gpio_driver); -} -module_exit(pch_gpio_pci_exit); +module_pci_driver(pch_gpio_driver); MODULE_DESCRIPTION("PCH GPIO PCI Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c new file mode 100644 index 00000000000..08428bf1771 --- /dev/null +++ b/drivers/gpio/gpio-rc5t583.c @@ -0,0 +1,180 @@ +/* + * GPIO driver for RICOH583 power management chip. + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Author: Laxman dewangan <ldewangan@nvidia.com> + * + * Based on code + * Copyright (C) 2011 RICOH COMPANY,LTD + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + * + */ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/gpio.h> +#include <linux/mfd/rc5t583.h> + +struct rc5t583_gpio { + struct gpio_chip gpio_chip; + struct rc5t583 *rc5t583; +}; + +static inline struct rc5t583_gpio *to_rc5t583_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct rc5t583_gpio, gpio_chip); +} + +static int rc5t583_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + uint8_t val = 0; + int ret; + + ret = rc5t583_read(parent, RC5T583_GPIO_MON_IOIN, &val); + if (ret < 0) + return ret; + + return !!(val & BIT(offset)); +} + +static void rc5t583_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + if (val) + rc5t583_set_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset)); + else + rc5t583_clear_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset)); +} + +static int rc5t583_gpio_dir_input(struct gpio_chip *gc, unsigned int offset) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + int ret; + + ret = rc5t583_clear_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset)); + if (ret < 0) + return ret; + + /* Set pin to gpio mode */ + return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset)); +} + +static int rc5t583_gpio_dir_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + int ret; + + rc5t583_gpio_set(gc, offset, value); + ret = rc5t583_set_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset)); + if (ret < 0) + return ret; + + /* Set pin to gpio mode */ + return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset)); +} + +static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + + if ((offset >= 0) && (offset < 8)) + return rc5t583_gpio->rc5t583->irq_base + + RC5T583_IRQ_GPIO0 + offset; + return -EINVAL; +} + +static void rc5t583_gpio_free(struct gpio_chip *gc, unsigned offset) +{ + struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc); + struct device *parent = rc5t583_gpio->rc5t583->dev; + + rc5t583_set_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset)); +} + +static int __devinit rc5t583_gpio_probe(struct platform_device *pdev) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); + struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); + struct rc5t583_gpio *rc5t583_gpio; + + rc5t583_gpio = devm_kzalloc(&pdev->dev, sizeof(*rc5t583_gpio), + GFP_KERNEL); + if (!rc5t583_gpio) { + dev_warn(&pdev->dev, "Mem allocation for rc5t583_gpio failed"); + return -ENOMEM; + } + + rc5t583_gpio->gpio_chip.label = "gpio-rc5t583", + rc5t583_gpio->gpio_chip.owner = THIS_MODULE, + rc5t583_gpio->gpio_chip.free = rc5t583_gpio_free, + rc5t583_gpio->gpio_chip.direction_input = rc5t583_gpio_dir_input, + rc5t583_gpio->gpio_chip.direction_output = rc5t583_gpio_dir_output, + rc5t583_gpio->gpio_chip.set = rc5t583_gpio_set, + rc5t583_gpio->gpio_chip.get = rc5t583_gpio_get, + rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq, + rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO, + rc5t583_gpio->gpio_chip.can_sleep = 1, + rc5t583_gpio->gpio_chip.dev = &pdev->dev; + rc5t583_gpio->gpio_chip.base = -1; + rc5t583_gpio->rc5t583 = rc5t583; + + if (pdata && pdata->gpio_base) + rc5t583_gpio->gpio_chip.base = pdata->gpio_base; + + platform_set_drvdata(pdev, rc5t583_gpio); + + return gpiochip_add(&rc5t583_gpio->gpio_chip); +} + +static int __devexit rc5t583_gpio_remove(struct platform_device *pdev) +{ + struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&rc5t583_gpio->gpio_chip); +} + +static struct platform_driver rc5t583_gpio_driver = { + .driver = { + .name = "rc5t583-gpio", + .owner = THIS_MODULE, + }, + .probe = rc5t583_gpio_probe, + .remove = __devexit_p(rc5t583_gpio_remove), +}; + +static int __init rc5t583_gpio_init(void) +{ + return platform_driver_register(&rc5t583_gpio_driver); +} +subsys_initcall(rc5t583_gpio_init); + +static void __exit rc5t583_gpio_exit(void) +{ + platform_driver_unregister(&rc5t583_gpio_driver); +} +module_exit(rc5t583_gpio_exit); + +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_DESCRIPTION("GPIO interface for RC5T583"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:rc5t583-gpio"); diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index e991d917196..421f6af0f99 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -2716,14 +2716,224 @@ static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, } #endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */ +static __init void exynos4_gpiolib_init(void) +{ +#ifdef CONFIG_CPU_EXYNOS4210 + struct samsung_gpio_chip *chip; + int i, nr_chips; + void __iomem *gpio_base1, *gpio_base2, *gpio_base3; + int group = 0; + 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 = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS4_PA_GPIO1, i * 0x20); + } + 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 = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS4_PA_GPIO2, i * 0x20); + } + 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 = &exynos_gpio_cfg; + chip->group = group++; + } + exynos_gpiolib_attach_ofnode(chip, + EXYNOS4_PA_GPIO3, i * 0x20); + } + 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 + + return; + +err_ioremap3: + iounmap(gpio_base2); +err_ioremap2: + iounmap(gpio_base1); +err_ioremap1: + return; +#endif /* CONFIG_CPU_EXYNOS4210 */ +} + +static __init void exynos5_gpiolib_init(void) +{ +#ifdef CONFIG_SOC_EXYNOS5250 + struct samsung_gpio_chip *chip; + int i, nr_chips; + void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4; + int group = 0; + 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); + return; + +err_ioremap4: + iounmap(gpio_base3); +err_ioremap3: + iounmap(gpio_base2); +err_ioremap2: + iounmap(gpio_base1); +err_ioremap1: + return; + +#endif /* CONFIG_SOC_EXYNOS5250 */ +} + /* TODO: cleanup soc_is_* */ static __init int samsung_gpiolib_init(void) { struct samsung_gpio_chip *chip; int i, nr_chips; -#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS5250) - void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4; -#endif int group = 0; samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs)); @@ -2789,202 +2999,15 @@ static __init int samsung_gpiolib_init(void) s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); #endif } else if (soc_is_exynos4210()) { -#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 = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS4_PA_GPIO1, i * 0x20); - } - 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 = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS4_PA_GPIO2, i * 0x20); - } - 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 = &exynos_gpio_cfg; - chip->group = group++; - } - exynos_gpiolib_attach_ofnode(chip, - EXYNOS4_PA_GPIO3, i * 0x20); - } - 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 */ + exynos4_gpiolib_init(); } 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 */ + exynos5_gpiolib_init(); } else { WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n"); return -ENODEV; } return 0; - -#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS5250) -err_ioremap4: - iounmap(gpio_base3); -err_ioremap3: - iounmap(gpio_base2); -err_ioremap2: - iounmap(gpio_base1); -err_ioremap1: - return -ENOMEM; -#endif } core_initcall(samsung_gpiolib_init); diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index 031e5d24837..9d9891f7a60 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -224,7 +224,7 @@ static int __devinit sdv_gpio_probe(struct pci_dev *pdev, ret = bgpio_init(&sd->bgpio, &pdev->dev, 4, sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR, - NULL, sd->gpio_pub_base + GPOER, NULL, false); + NULL, sd->gpio_pub_base + GPOER, NULL, 0); if (ret) goto unmap; sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS; @@ -282,17 +282,7 @@ static struct pci_driver sdv_gpio_driver = { .remove = sdv_gpio_remove, }; -static int __init sdv_gpio_init(void) -{ - return pci_register_driver(&sdv_gpio_driver); -} -module_init(sdv_gpio_init); - -static void __exit sdv_gpio_exit(void) -{ - pci_unregister_driver(&sdv_gpio_driver); -} -module_exit(sdv_gpio_exit); +module_pci_driver(sdv_gpio_driver); MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>"); MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs"); diff --git a/drivers/of/gpio.c b/drivers/gpio/gpiolib-of.c index bf984b6dc47..d18068a9f3e 100644 --- a/drivers/of/gpio.c +++ b/drivers/gpio/gpiolib-of.c @@ -15,11 +15,39 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/io.h> +#include <linux/gpio.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include <linux/slab.h> +/* Private data structure for of_gpiochip_is_match */ +struct gg_data { + enum of_gpio_flags *flags; + struct of_phandle_args gpiospec; + + int out_gpio; +}; + +/* Private function for resolving node pointer to gpio_chip */ +static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data) +{ + struct gg_data *gg_data = data; + int ret; + + if ((gc->of_node != gg_data->gpiospec.np) || + (gc->of_gpio_n_cells != gg_data->gpiospec.args_count) || + (!gc->of_xlate)) + return false; + + ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags); + if (ret < 0) + return false; + + gg_data->out_gpio = ret + gc->base; + return true; +} + /** * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API * @np: device node to get GPIO from @@ -34,46 +62,25 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags) { + struct gg_data gg_data = { .flags = flags, .out_gpio = -ENODEV }; int ret; - struct gpio_chip *gc; - struct of_phandle_args gpiospec; + + /* .of_xlate might decide to not fill in the flags, so clear it. */ + if (flags) + *flags = 0; ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, - &gpiospec); + &gg_data.gpiospec); if (ret) { pr_debug("%s: can't parse gpios property\n", __func__); - goto err0; - } - - gc = of_node_to_gpiochip(gpiospec.np); - if (!gc) { - pr_debug("%s: gpio controller %s isn't registered\n", - np->full_name, gpiospec.np->full_name); - ret = -ENODEV; - goto err1; - } - - if (gpiospec.args_count != gc->of_gpio_n_cells) { - pr_debug("%s: wrong #gpio-cells for %s\n", - np->full_name, gpiospec.np->full_name); - ret = -EINVAL; - goto err1; + return -EINVAL; } - /* .xlate might decide to not fill in the flags, so clear it. */ - if (flags) - *flags = 0; - - ret = gc->of_xlate(gc, &gpiospec, flags); - if (ret < 0) - goto err1; + gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); - ret += gc->base; -err1: - of_node_put(gpiospec.np); -err0: + of_node_put(gg_data.gpiospec.np); pr_debug("%s exited with status %d\n", __func__, ret); - return ret; + return gg_data.out_gpio; } EXPORT_SYMBOL(of_get_named_gpio_flags); @@ -227,14 +234,3 @@ void of_gpiochip_remove(struct gpio_chip *chip) if (chip->of_node) of_node_put(chip->of_node); } - -/* Private function for resolving node pointer to gpio_chip */ -static int of_gpiochip_is_match(struct gpio_chip *chip, const void *data) -{ - return chip->of_node == data; -} - -struct gpio_chip *of_node_to_gpiochip(struct device_node *np) -{ - return gpiochip_find(np, of_gpiochip_is_match); -} diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5a75510d66b..120b2a0e316 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1093,7 +1093,7 @@ unlock: if (status) goto fail; - pr_info("gpiochip_add: registered GPIOs %d to %d on device: %s\n", + pr_debug("gpiochip_add: registered GPIOs %d to %d on device: %s\n", chip->base, chip->base + chip->ngpio - 1, chip->label ? : "generic"); @@ -1154,9 +1154,9 @@ EXPORT_SYMBOL_GPL(gpiochip_remove); * non-zero, this function will return to the caller and not iterate over any * more gpio_chips. */ -struct gpio_chip *gpiochip_find(const void *data, +struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *chip, - const void *data)) + void *data)) { struct gpio_chip *chip = NULL; unsigned long flags; @@ -1302,8 +1302,18 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) (flags & GPIOF_INIT_HIGH) ? 1 : 0); if (err) - gpio_free(gpio); + goto free_gpio; + + if (flags & GPIOF_EXPORT) { + err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE); + if (err) + goto free_gpio; + } + + return 0; + free_gpio: + gpio_free(gpio); return err; } EXPORT_SYMBOL_GPL(gpio_request_one); diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index f623f17a0b9..dfba3e64d59 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -51,12 +51,6 @@ config OF_IRQ config OF_DEVICE def_bool y -config OF_GPIO - def_bool y - depends on GPIOLIB && !SPARC - help - OpenFirmware GPIO accessors - config OF_I2C def_tristate I2C depends on I2C && !SPARC diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 0040d185866..e027f444d10 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o obj-$(CONFIG_OF_ADDRESS) += address.o obj-$(CONFIG_OF_IRQ) += irq.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o -obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o obj-$(CONFIG_OF_NET) += of_net.o obj-$(CONFIG_OF_SELFTEST) += selftest.o diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 5f52690c3c8..365ea09ed3b 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -142,9 +142,9 @@ extern int __must_check gpiochip_reserve(int start, int ngpio); /* add/remove chips */ extern int gpiochip_add(struct gpio_chip *chip); extern int __must_check gpiochip_remove(struct gpio_chip *chip); -extern struct gpio_chip *gpiochip_find(const void *data, +extern struct gpio_chip *gpiochip_find(void *data, int (*match)(struct gpio_chip *chip, - const void *data)); + void *data)); /* Always use the library code for GPIO management calls, @@ -179,6 +179,8 @@ extern void gpio_free_array(const struct gpio *array, size_t num); /* bindings for managed devices that want to request gpios */ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); +int devm_gpio_request_one(struct device *dev, unsigned gpio, + unsigned long flags, const char *label); void devm_gpio_free(struct device *dev, unsigned int gpio); #ifdef CONFIG_GPIO_SYSFS diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h index feb91219674..1c504ca5bdb 100644 --- a/include/linux/basic_mmio_gpio.h +++ b/include/linux/basic_mmio_gpio.h @@ -67,6 +67,10 @@ int bgpio_remove(struct bgpio_chip *bgc); int bgpio_init(struct bgpio_chip *bgc, struct device *dev, unsigned long sz, void __iomem *dat, void __iomem *set, void __iomem *clr, void __iomem *dirout, void __iomem *dirin, - bool big_endian); + unsigned long flags); + +#define BGPIOF_BIG_ENDIAN BIT(0) +#define BGPIOF_UNREADABLE_REG_SET BIT(1) /* reg_set is unreadable */ +#define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */ #endif /* __BASIC_MMIO_GPIO_H */ diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 6155ecf192b..f07fc2d0815 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -1,6 +1,8 @@ #ifndef __LINUX_GPIO_H #define __LINUX_GPIO_H +#include <linux/errno.h> + /* see Documentation/gpio.txt */ /* make these flag values available regardless of GPIO kconfig options */ @@ -20,6 +22,11 @@ /* Gpio pin is open source */ #define GPIOF_OPEN_SOURCE (1 << 3) +#define GPIOF_EXPORT (1 << 2) +#define GPIOF_EXPORT_CHANGEABLE (1 << 3) +#define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT) +#define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE) + /** * struct gpio - a structure describing a GPIO with configuration * @gpio: the GPIO number @@ -33,7 +40,39 @@ struct gpio { }; #ifdef CONFIG_GENERIC_GPIO + +#ifdef CONFIG_ARCH_HAVE_CUSTOM_GPIO_H #include <asm/gpio.h> +#else + +#include <asm-generic/gpio.h> + +static inline int gpio_get_value(unsigned int gpio) +{ + return __gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned int gpio, int value) +{ + __gpio_set_value(gpio, value); +} + +static inline int gpio_cansleep(unsigned int gpio) +{ + return __gpio_cansleep(gpio); +} + +static inline int gpio_to_irq(unsigned int gpio) +{ + return __gpio_to_irq(gpio); +} + +static inline int irq_to_gpio(unsigned int irq) +{ + return -EINVAL; +} + +#endif #else @@ -55,12 +94,24 @@ static inline int gpio_request(unsigned gpio, const char *label) return -ENOSYS; } +static inline int devm_gpio_request(struct device *dev, unsigned gpio, + const char *label) +{ + return -ENOSYS; +} + static inline int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) { return -ENOSYS; } +static inline int devm_gpio_request_one(struct device *dev, unsigned gpio, + unsigned long flags, const char *label) +{ + return -ENOSYS; +} + static inline int gpio_request_array(const struct gpio *array, size_t num) { return -ENOSYS; @@ -74,6 +125,14 @@ static inline void gpio_free(unsigned gpio) WARN_ON(1); } +static inline void devm_gpio_free(struct device *dev, unsigned gpio) +{ + might_sleep(); + + /* GPIO can never have been requested */ + WARN_ON(1); +} + static inline void gpio_free_array(const struct gpio *array, size_t num) { might_sleep(); diff --git a/include/linux/mfd/rc5t583.h b/include/linux/mfd/rc5t583.h index c42fe92a727..3661c59aa1e 100644 --- a/include/linux/mfd/rc5t583.h +++ b/include/linux/mfd/rc5t583.h @@ -292,6 +292,7 @@ struct rc5t583 { * rc5t583_platform_data: Platform data for ricoh rc5t583 pmu. * The board specific data is provided through this structure. * @irq_base: Irq base number on which this device registers their interrupts. + * @gpio_base: GPIO base from which gpio of this device will start. * @enable_shutdown: Enable shutdown through the input pin "shutdown". * @regulator_deepsleep_slot: The slot number on which device goes to sleep * in device sleep mode. @@ -303,6 +304,7 @@ struct rc5t583 { struct rc5t583_platform_data { int irq_base; + int gpio_base; bool enable_shutdown; int regulator_deepsleep_slot[RC5T583_REGULATOR_MAX]; unsigned long regulator_ext_pwr_control[RC5T583_REGULATOR_MAX]; diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 81733d12cbe..c454f579674 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -58,7 +58,6 @@ extern int of_mm_gpiochip_add(struct device_node *np, extern void of_gpiochip_add(struct gpio_chip *gc); extern void of_gpiochip_remove(struct gpio_chip *gc); -extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np); extern int of_gpio_simple_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags); |