From: Grant Likely Date: Sat, 12 May 2012 00:51:19 +0000 (-0600) Subject: Merge branch 'for_3.5/gpio/cleanup' of git://git.kernel.org/pub/scm/linux/kernel... X-Git-Tag: firefly_0821_release~3680^2~2771^2~11 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=453007cf472a2b4c1034e850c3004ee9027005f6;hp=1b1287032df3a69d3ef9a486b444f4ffcca50d01;p=firefly-linux-kernel-4.4.55.git Merge branch 'for_3.5/gpio/cleanup' of git://git./linux/kernel/git/khilman/linux-omap-pm into gpio/next --- diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index 620a07844e8c..e08a883de36e 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 7dc6a6343c06..b3799d88ffcf 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 - * - * 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 -#include - -#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 +#endif diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 36586dba6fa6..777025e773d9 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/avr32/Kconfig b/arch/avr32/Kconfig index 3dea7231f637..859b2de4a624 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 help AVR32 is a high-performance 32-bit RISC microprocessor core, diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 373a6902d8fa..bf3d80f9738b 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 590a20debc4e..b3799d88ffcf 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 - * - * 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 -#include - -#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 +#endif diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu index 8a9c767125a4..8941af1d3ad2 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 2b2c18be71c6..b3799d88ffcf 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 - * - * 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 -#include - -#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 +#endif diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index ce30e2f91d77..63321b283fe4 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 0b0d174f47cd..b3799d88ffcf 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 - * Copyright (C) 2010-2011 Jonas Bonn - * 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 -#include - -#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 +#endif diff --git a/arch/powerpc/include/asm/gpio.h b/arch/powerpc/include/asm/gpio.h index 38762edb5e58..b3799d88ffcf 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 - * - * 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 -#include - -#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 +#endif diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index ff9e033ce626..c40b29ac3644 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 a0e3ac0af599..b3799d88ffcf 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 -#include - -#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 +#endif diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig index eeb8054c7cd8..7ff6d10c0be2 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 91d915a65259..b3799d88ffcf 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 - * - * 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 - -#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 +#endif diff --git a/arch/xtensa/include/asm/gpio.h b/arch/xtensa/include/asm/gpio.h index a8c9fc46c790..b3799d88ffcf 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 - * - * 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 - -#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 +#endif diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index e03653d69357..25535ebf4f90 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 @@ -243,7 +255,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 @@ -252,10 +264,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" @@ -399,6 +412,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. @@ -514,4 +528,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 007f54bd0081..7862f49b4d05 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 @@ -32,6 +33,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 diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index 5ca4098ba092..e4cc7eb69bb2 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-langwell.c b/drivers/gpio/gpio-langwell.c index 00692e89ef87..a1c8754f52cf 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c @@ -36,6 +36,7 @@ #include #include #include +#include /* * 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-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index f0febe5b8221..db01f151d41c 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-msic.c b/drivers/gpio/gpio-msic.c new file mode 100644 index 000000000000..71a838f44501 --- /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 + * 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 +#include +#include +#include +#include +#include +#include +#include + +/* 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 "); +MODULE_DESCRIPTION("Intel Medfield MSIC GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index e8729cc2ba2b..a05fdb6c464c 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -539,17 +539,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-samsung.c b/drivers/gpio/gpio-samsung.c index 19d6fc0229c3..5d49aff3bb9e 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -2714,12 +2714,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; - 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)); @@ -2785,200 +2997,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; - -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-sodaville.c b/drivers/gpio/gpio-sodaville.c index 031e5d24837d..820209c420e3 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -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 "); MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs"); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c new file mode 100644 index 000000000000..bf984b6dc477 --- /dev/null +++ b/drivers/gpio/gpiolib-of.c @@ -0,0 +1,240 @@ +/* + * OF helpers for the GPIO API + * + * Copyright (c) 2007-2008 MontaVista Software, Inc. + * + * Author: Anton Vorontsov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API + * @np: device node to get GPIO from + * @propname: property name containing gpio specifier(s) + * @index: index of the GPIO + * @flags: a flags pointer to fill in + * + * Returns GPIO number to use with Linux generic GPIO API, or one of the errno + * value on the error condition. If @flags is not NULL the function also fills + * in flags for the GPIO. + */ +int of_get_named_gpio_flags(struct device_node *np, const char *propname, + int index, enum of_gpio_flags *flags) +{ + int ret; + struct gpio_chip *gc; + struct of_phandle_args gpiospec; + + ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, + &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; + } + + /* .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; + + ret += gc->base; +err1: + of_node_put(gpiospec.np); +err0: + pr_debug("%s exited with status %d\n", __func__, ret); + return ret; +} +EXPORT_SYMBOL(of_get_named_gpio_flags); + +/** + * of_gpio_named_count - Count GPIOs for a device + * @np: device node to count GPIOs for + * @propname: property name containing gpio specifier(s) + * + * The function returns the count of GPIOs specified for a node. + * + * Note that the empty GPIO specifiers counts too. For example, + * + * gpios = <0 + * &pio1 1 2 + * 0 + * &pio2 3 4>; + * + * defines four GPIOs (so this function will return 4), two of which + * are not specified. + */ +unsigned int of_gpio_named_count(struct device_node *np, const char* propname) +{ + unsigned int cnt = 0; + + do { + int ret; + + ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", + cnt, NULL); + /* A hole in the gpios = <> counts anyway. */ + if (ret < 0 && ret != -EEXIST) + break; + } while (++cnt); + + return cnt; +} +EXPORT_SYMBOL(of_gpio_named_count); + +/** + * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags + * @gc: pointer to the gpio_chip structure + * @np: device node of the GPIO chip + * @gpio_spec: gpio specifier as found in the device tree + * @flags: a flags pointer to fill in + * + * This is simple translation function, suitable for the most 1:1 mapped + * gpio chips. This function performs only one sanity check: whether gpio + * is less than ngpios (that is specified in the gpio_chip). + */ +int of_gpio_simple_xlate(struct gpio_chip *gc, + const struct of_phandle_args *gpiospec, u32 *flags) +{ + /* + * We're discouraging gpio_cells < 2, since that way you'll have to + * write your own xlate function (that will have to retrive the GPIO + * number and the flags from a single gpio cell -- this is possible, + * but not recommended). + */ + if (gc->of_gpio_n_cells < 2) { + WARN_ON(1); + return -EINVAL; + } + + if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) + return -EINVAL; + + if (gpiospec->args[0] >= gc->ngpio) + return -EINVAL; + + if (flags) + *flags = gpiospec->args[1]; + + return gpiospec->args[0]; +} +EXPORT_SYMBOL(of_gpio_simple_xlate); + +/** + * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank) + * @np: device node of the GPIO chip + * @mm_gc: pointer to the of_mm_gpio_chip allocated structure + * + * To use this function you should allocate and fill mm_gc with: + * + * 1) In the gpio_chip structure: + * - all the callbacks + * - of_gpio_n_cells + * - of_xlate callback (optional) + * + * 3) In the of_mm_gpio_chip structure: + * - save_regs callback (optional) + * + * If succeeded, this function will map bank's memory and will + * do all necessary work for you. Then you'll able to use .regs + * to manage GPIOs from the callbacks. + */ +int of_mm_gpiochip_add(struct device_node *np, + struct of_mm_gpio_chip *mm_gc) +{ + int ret = -ENOMEM; + struct gpio_chip *gc = &mm_gc->gc; + + gc->label = kstrdup(np->full_name, GFP_KERNEL); + if (!gc->label) + goto err0; + + mm_gc->regs = of_iomap(np, 0); + if (!mm_gc->regs) + goto err1; + + gc->base = -1; + + if (mm_gc->save_regs) + mm_gc->save_regs(mm_gc); + + mm_gc->gc.of_node = np; + + ret = gpiochip_add(gc); + if (ret) + goto err2; + + return 0; +err2: + iounmap(mm_gc->regs); +err1: + kfree(gc->label); +err0: + pr_err("%s: GPIO chip registration failed with status %d\n", + np->full_name, ret); + return ret; +} +EXPORT_SYMBOL(of_mm_gpiochip_add); + +void of_gpiochip_add(struct gpio_chip *chip) +{ + if ((!chip->of_node) && (chip->dev)) + chip->of_node = chip->dev->of_node; + + if (!chip->of_node) + return; + + if (!chip->of_xlate) { + chip->of_gpio_n_cells = 2; + chip->of_xlate = of_gpio_simple_xlate; + } + + of_node_get(chip->of_node); +} + +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 5a75510d66bb..566d0122d832 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -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 8e84ce9765a9..ce00d11144de 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 aa90e602c8a7..aff2c6230390 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_SPI) += of_spi.o diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c deleted file mode 100644 index bf984b6dc477..000000000000 --- a/drivers/of/gpio.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * OF helpers for the GPIO API - * - * Copyright (c) 2007-2008 MontaVista Software, Inc. - * - * Author: Anton Vorontsov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API - * @np: device node to get GPIO from - * @propname: property name containing gpio specifier(s) - * @index: index of the GPIO - * @flags: a flags pointer to fill in - * - * Returns GPIO number to use with Linux generic GPIO API, or one of the errno - * value on the error condition. If @flags is not NULL the function also fills - * in flags for the GPIO. - */ -int of_get_named_gpio_flags(struct device_node *np, const char *propname, - int index, enum of_gpio_flags *flags) -{ - int ret; - struct gpio_chip *gc; - struct of_phandle_args gpiospec; - - ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, - &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; - } - - /* .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; - - ret += gc->base; -err1: - of_node_put(gpiospec.np); -err0: - pr_debug("%s exited with status %d\n", __func__, ret); - return ret; -} -EXPORT_SYMBOL(of_get_named_gpio_flags); - -/** - * of_gpio_named_count - Count GPIOs for a device - * @np: device node to count GPIOs for - * @propname: property name containing gpio specifier(s) - * - * The function returns the count of GPIOs specified for a node. - * - * Note that the empty GPIO specifiers counts too. For example, - * - * gpios = <0 - * &pio1 1 2 - * 0 - * &pio2 3 4>; - * - * defines four GPIOs (so this function will return 4), two of which - * are not specified. - */ -unsigned int of_gpio_named_count(struct device_node *np, const char* propname) -{ - unsigned int cnt = 0; - - do { - int ret; - - ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", - cnt, NULL); - /* A hole in the gpios = <> counts anyway. */ - if (ret < 0 && ret != -EEXIST) - break; - } while (++cnt); - - return cnt; -} -EXPORT_SYMBOL(of_gpio_named_count); - -/** - * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags - * @gc: pointer to the gpio_chip structure - * @np: device node of the GPIO chip - * @gpio_spec: gpio specifier as found in the device tree - * @flags: a flags pointer to fill in - * - * This is simple translation function, suitable for the most 1:1 mapped - * gpio chips. This function performs only one sanity check: whether gpio - * is less than ngpios (that is specified in the gpio_chip). - */ -int of_gpio_simple_xlate(struct gpio_chip *gc, - const struct of_phandle_args *gpiospec, u32 *flags) -{ - /* - * We're discouraging gpio_cells < 2, since that way you'll have to - * write your own xlate function (that will have to retrive the GPIO - * number and the flags from a single gpio cell -- this is possible, - * but not recommended). - */ - if (gc->of_gpio_n_cells < 2) { - WARN_ON(1); - return -EINVAL; - } - - if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) - return -EINVAL; - - if (gpiospec->args[0] >= gc->ngpio) - return -EINVAL; - - if (flags) - *flags = gpiospec->args[1]; - - return gpiospec->args[0]; -} -EXPORT_SYMBOL(of_gpio_simple_xlate); - -/** - * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank) - * @np: device node of the GPIO chip - * @mm_gc: pointer to the of_mm_gpio_chip allocated structure - * - * To use this function you should allocate and fill mm_gc with: - * - * 1) In the gpio_chip structure: - * - all the callbacks - * - of_gpio_n_cells - * - of_xlate callback (optional) - * - * 3) In the of_mm_gpio_chip structure: - * - save_regs callback (optional) - * - * If succeeded, this function will map bank's memory and will - * do all necessary work for you. Then you'll able to use .regs - * to manage GPIOs from the callbacks. - */ -int of_mm_gpiochip_add(struct device_node *np, - struct of_mm_gpio_chip *mm_gc) -{ - int ret = -ENOMEM; - struct gpio_chip *gc = &mm_gc->gc; - - gc->label = kstrdup(np->full_name, GFP_KERNEL); - if (!gc->label) - goto err0; - - mm_gc->regs = of_iomap(np, 0); - if (!mm_gc->regs) - goto err1; - - gc->base = -1; - - if (mm_gc->save_regs) - mm_gc->save_regs(mm_gc); - - mm_gc->gc.of_node = np; - - ret = gpiochip_add(gc); - if (ret) - goto err2; - - return 0; -err2: - iounmap(mm_gc->regs); -err1: - kfree(gc->label); -err0: - pr_err("%s: GPIO chip registration failed with status %d\n", - np->full_name, ret); - return ret; -} -EXPORT_SYMBOL(of_mm_gpiochip_add); - -void of_gpiochip_add(struct gpio_chip *chip) -{ - if ((!chip->of_node) && (chip->dev)) - chip->of_node = chip->dev->of_node; - - if (!chip->of_node) - return; - - if (!chip->of_xlate) { - chip->of_gpio_n_cells = 2; - chip->of_xlate = of_gpio_simple_xlate; - } - - of_node_get(chip->of_node); -} - -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/include/linux/gpio.h b/include/linux/gpio.h index 6155ecf192b0..7a8816a1a0d8 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -1,6 +1,8 @@ #ifndef __LINUX_GPIO_H #define __LINUX_GPIO_H +#include + /* 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 +#else + +#include + +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,6 +94,12 @@ 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) { @@ -74,6 +119,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();