diff options
author | Pavel Pisa <ppisa@pikron.com> | 2007-05-12 14:31:17 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-07-12 11:11:39 +0100 |
commit | b3e6a508ed920698d367e5993ed056d70364d91f (patch) | |
tree | 4097af7112f18f4e610d16d46c95746f6d1621a6 /arch/arm | |
parent | 7dcca30a32aadb0520417521b0c44f42d09fe05c (diff) | |
download | linux-stable-b3e6a508ed920698d367e5993ed056d70364d91f.tar.gz linux-stable-b3e6a508ed920698d367e5993ed056d70364d91f.tar.bz2 linux-stable-b3e6a508ed920698d367e5993ed056d70364d91f.zip |
[ARM] 4373/1: i.MX/MX1 GPIO support implementation
Support for generic input output for MX1 family.
The implementation prevents allocation of one pin
by two users, but does not store pointer to the user
description permanently, because this solution
would have bigger memory overhead.
The simple way to integrate code with per BSP
pins setup and allocation is required else all GPIO
registration checking is useless. The function
imx_gpio_setup_multiple_pins() can be used for this
purpose in future.
Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/generic.c | 118 |
2 files changed, 119 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 50d9f3e4e0f1..8b553954365f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -241,6 +241,7 @@ config ARCH_H720X config ARCH_IMX bool "IMX" + select GENERIC_GPIO help Support for Motorola's i.MX family of processors (MX1, MXL). diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index 1c474cf709ca..a58b678006df 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c @@ -28,12 +28,16 @@ #include <linux/module.h> #include <linux/string.h> +#include <asm/errno.h> #include <asm/arch/imxfb.h> #include <asm/hardware.h> #include <asm/arch/imx-regs.h> #include <asm/mach/map.h> #include <asm/arch/mmc.h> +#include <asm/arch/gpio.h> + +unsigned long imx_gpio_alloc_map[(GPIO_PORT_MAX + 1) * 32 / BITS_PER_LONG]; void imx_gpio_mode(int gpio_mode) { @@ -95,6 +99,120 @@ void imx_gpio_mode(int gpio_mode) EXPORT_SYMBOL(imx_gpio_mode); +int imx_gpio_request(unsigned gpio, const char *label) +{ + if(gpio >= (GPIO_PORT_MAX + 1) * 32) + printk(KERN_ERR "imx_gpio: Attempt to request nonexistent GPIO %d for \"%s\"\n", + gpio, label ? label : "?"); + return -EINVAL; + + if(test_and_set_bit(gpio, imx_gpio_alloc_map)) { + printk(KERN_ERR "imx_gpio: GPIO %d already used. Allocation for \"%s\" failed\n", + gpio, label ? label : "?"); + return -EBUSY; + } + + return 0; +} + +EXPORT_SYMBOL(imx_gpio_request); + +void imx_gpio_free(unsigned gpio) +{ + if(gpio >= (GPIO_PORT_MAX + 1) * 32) + return; + + clear_bit(gpio, imx_gpio_alloc_map); +} + +EXPORT_SYMBOL(imx_gpio_free); + +int imx_gpio_direction_input(unsigned gpio) +{ + imx_gpio_mode(gpio| GPIO_IN); + return 0; +} + +EXPORT_SYMBOL(imx_gpio_direction_input); + +int imx_gpio_direction_output(unsigned gpio, int value) +{ + imx_gpio_set_value(gpio, value); + imx_gpio_mode(gpio| GPIO_OUT); + return 0; +} + +EXPORT_SYMBOL(imx_gpio_direction_output); + +int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count, + int alloc_mode, const char *label) +{ + const int *p = pin_list; + int i; + unsigned gpio; + unsigned mode; + + for (i = 0; i < count; i++) { + gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK); + mode = *p & ~(GPIO_PIN_MASK | GPIO_PORT_MASK); + + if (gpio >= (GPIO_PORT_MAX + 1) * 32) + goto setup_error; + + if (alloc_mode & IMX_GPIO_ALLOC_MODE_RELEASE) + imx_gpio_free(gpio); + else if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_NO_ALLOC)) + if (imx_gpio_request(gpio, label)) + if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_TRY_ALLOC)) + goto setup_error; + + if (!(alloc_mode & (IMX_GPIO_ALLOC_MODE_ALLOC_ONLY | + IMX_GPIO_ALLOC_MODE_RELEASE))) + imx_gpio_mode(gpio | mode); + + p++; + } + return 0; + +setup_error: + if(alloc_mode & (IMX_GPIO_ALLOC_MODE_NO_ALLOC | + IMX_GPIO_ALLOC_MODE_TRY_ALLOC)) + return -EINVAL; + + while (p != pin_list) { + p--; + gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK); + imx_gpio_free(gpio); + } + + return -EINVAL; +} + +EXPORT_SYMBOL(imx_gpio_setup_multiple_pins); + +void __imx_gpio_set_value(unsigned gpio, int value) +{ + imx_gpio_set_value_inline(gpio, value); +} + +EXPORT_SYMBOL(__imx_gpio_set_value); + +int imx_gpio_to_irq(unsigned gpio) +{ + return IRQ_GPIOA(0) + gpio; +} + +EXPORT_SYMBOL(imx_gpio_to_irq); + +int imx_irq_to_gpio(unsigned irq) +{ + if (irq < IRQ_GPIOA(0)) + return -EINVAL; + return irq - IRQ_GPIOA(0); +} + +EXPORT_SYMBOL(imx_irq_to_gpio); + /* * get the system pll clock in Hz * |