diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-10-20 01:51:03 +0200 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2008-12-20 12:21:02 -0500 |
commit | 9569dae75f6f6987e79fa26cf6da3fc24006c996 (patch) | |
tree | b5982f41aea6ccee37af54fc8f7750aaff7e0bff /arch/arm | |
parent | 6fd7c7fe72a46dfd227fe8db0c7b6863af90a982 (diff) |
[ARM] Orion: share GPIO handling code
Split off Orion GPIO handling code into plat-orion/, and add
support for multiple sets of (32) GPIO pins.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-orion5x/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/common.h | 7 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/gpio.c | 231 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/include/mach/gpio.h | 26 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/include/mach/irqs.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/include/mach/orion5x.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/irq.c | 24 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/mpp.c | 6 | ||||
-rw-r--r-- | arch/arm/plat-orion/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/plat-orion/gpio.c | 239 | ||||
-rw-r--r-- | arch/arm/plat-orion/include/plat/gpio.h | 32 |
11 files changed, 308 insertions, 271 deletions
diff --git a/arch/arm/mach-orion5x/Makefile b/arch/arm/mach-orion5x/Makefile index 3d4a1bc1235..edc38e2c856 100644 --- a/arch/arm/mach-orion5x/Makefile +++ b/arch/arm/mach-orion5x/Makefile @@ -1,4 +1,4 @@ -obj-y += common.o addr-map.o pci.o gpio.o irq.o mpp.o +obj-y += common.o addr-map.o pci.o irq.o mpp.o obj-$(CONFIG_MACH_DB88F5281) += db88f5281-setup.o obj-$(CONFIG_MACH_RD88F5182) += rd88f5182-setup.o obj-$(CONFIG_MACH_KUROBOX_PRO) += kurobox_pro-setup.o diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h index a000c7c6ee9..798b9a5e3da 100644 --- a/arch/arm/mach-orion5x/common.h +++ b/arch/arm/mach-orion5x/common.h @@ -51,13 +51,6 @@ int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys); struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys); int orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin); -/* - * Valid GPIO pins according to MPP setup, used by machine-setup. - * (/mach-orion/gpio.c). - */ -void orion5x_gpio_set_valid(unsigned pin, int valid); -void gpio_display(void); /* debug */ - struct machine_desc; struct meminfo; struct tag; diff --git a/arch/arm/mach-orion5x/gpio.c b/arch/arm/mach-orion5x/gpio.c deleted file mode 100644 index f99d08811e5..00000000000 --- a/arch/arm/mach-orion5x/gpio.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * arch/arm/mach-orion5x/gpio.c - * - * GPIO functions for Marvell Orion System On Chip - * - * Maintainer: Tzachi Perelstein <tzachi@marvell.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/bitops.h> -#include <linux/io.h> -#include <asm/gpio.h> -#include <mach/orion5x.h> -#include "common.h" - -static DEFINE_SPINLOCK(gpio_lock); -static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)]; -static const char *gpio_label[GPIO_MAX]; /* non null for allocated GPIOs */ - -void __init orion5x_gpio_set_valid(unsigned pin, int valid) -{ - if (valid) - __set_bit(pin, gpio_valid); - else - __clear_bit(pin, gpio_valid); -} - -/* - * GENERIC_GPIO primitives - */ -int gpio_direction_input(unsigned pin) -{ - unsigned long flags; - - if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { - pr_debug("%s: invalid GPIO %d\n", __func__, pin); - return -EINVAL; - } - - spin_lock_irqsave(&gpio_lock, flags); - - /* - * Some callers might have not used the gpio_request(), - * so flag this pin as requested now. - */ - if (!gpio_label[pin]) - gpio_label[pin] = "?"; - - orion5x_setbits(GPIO_IO_CONF, 1 << pin); - - spin_unlock_irqrestore(&gpio_lock, flags); - return 0; -} -EXPORT_SYMBOL(gpio_direction_input); - -int gpio_direction_output(unsigned pin, int value) -{ - unsigned long flags; - int mask; - - if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { - pr_debug("%s: invalid GPIO %d\n", __func__, pin); - return -EINVAL; - } - - spin_lock_irqsave(&gpio_lock, flags); - - /* - * Some callers might have not used the gpio_request(), - * so flag this pin as requested now. - */ - if (!gpio_label[pin]) - gpio_label[pin] = "?"; - - mask = 1 << pin; - orion5x_clrbits(GPIO_BLINK_EN, mask); - if (value) - orion5x_setbits(GPIO_OUT, mask); - else - orion5x_clrbits(GPIO_OUT, mask); - orion5x_clrbits(GPIO_IO_CONF, mask); - - spin_unlock_irqrestore(&gpio_lock, flags); - return 0; -} -EXPORT_SYMBOL(gpio_direction_output); - -int gpio_get_value(unsigned pin) -{ - int val, mask = 1 << pin; - - if (readl(GPIO_IO_CONF) & mask) - val = readl(GPIO_DATA_IN) ^ readl(GPIO_IN_POL); - else - val = readl(GPIO_OUT); - - return val & mask; -} -EXPORT_SYMBOL(gpio_get_value); - -void gpio_set_value(unsigned pin, int value) -{ - unsigned long flags; - int mask = 1 << pin; - - spin_lock_irqsave(&gpio_lock, flags); - - orion5x_clrbits(GPIO_BLINK_EN, mask); - if (value) - orion5x_setbits(GPIO_OUT, mask); - else - orion5x_clrbits(GPIO_OUT, mask); - - spin_unlock_irqrestore(&gpio_lock, flags); -} -EXPORT_SYMBOL(gpio_set_value); - -void orion5x_gpio_set_blink(unsigned pin, int blink) -{ - unsigned long flags; - int mask = 1 << pin; - - spin_lock_irqsave(&gpio_lock, flags); - - orion5x_clrbits(GPIO_OUT, mask); - if (blink) - orion5x_setbits(GPIO_BLINK_EN, mask); - else - orion5x_clrbits(GPIO_BLINK_EN, mask); - - spin_unlock_irqrestore(&gpio_lock, flags); -} -EXPORT_SYMBOL(orion5x_gpio_set_blink); - -int gpio_request(unsigned pin, const char *label) -{ - int ret = 0; - unsigned long flags; - - if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { - pr_debug("%s: invalid GPIO %d\n", __func__, pin); - return -EINVAL; - } - - spin_lock_irqsave(&gpio_lock, flags); - - if (gpio_label[pin]) { - pr_debug("%s: GPIO %d already used as %s\n", - __func__, pin, gpio_label[pin]); - ret = -EBUSY; - } else - gpio_label[pin] = label ? label : "?"; - - spin_unlock_irqrestore(&gpio_lock, flags); - return ret; -} -EXPORT_SYMBOL(gpio_request); - -void gpio_free(unsigned pin) -{ - might_sleep(); - - if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { - pr_debug("%s: invalid GPIO %d\n", __func__, pin); - return; - } - - if (!gpio_label[pin]) - pr_warning("%s: GPIO %d already freed\n", __func__, pin); - else - gpio_label[pin] = NULL; -} -EXPORT_SYMBOL(gpio_free); - -/* Debug helper */ -void gpio_display(void) -{ - int i; - - for (i = 0; i < GPIO_MAX; i++) { - printk(KERN_DEBUG "Pin-%d: ", i); - - if (!test_bit(i, gpio_valid)) { - printk("non-GPIO\n"); - } else if (!gpio_label[i]) { - printk("GPIO, free\n"); - } else { - printk("GPIO, used by %s, ", gpio_label[i]); - if (readl(GPIO_IO_CONF) & (1 << i)) { - printk("input, active %s, level %s, edge %s\n", - ((readl(GPIO_IN_POL) >> i) & 1) ? "low" : "high", - ((readl(GPIO_LEVEL_MASK) >> i) & 1) ? "enabled" : "masked", - ((readl(GPIO_EDGE_MASK) >> i) & 1) ? "enabled" : "masked"); - } else { - printk("output, val=%d\n", (readl(GPIO_OUT) >> i) & 1); - } - } - } - - printk(KERN_DEBUG "MPP_0_7_CTRL (0x%08x) = 0x%08x\n", - MPP_0_7_CTRL, readl(MPP_0_7_CTRL)); - printk(KERN_DEBUG "MPP_8_15_CTRL (0x%08x) = 0x%08x\n", - MPP_8_15_CTRL, readl(MPP_8_15_CTRL)); - printk(KERN_DEBUG "MPP_16_19_CTRL (0x%08x) = 0x%08x\n", - MPP_16_19_CTRL, readl(MPP_16_19_CTRL)); - printk(KERN_DEBUG "MPP_DEV_CTRL (0x%08x) = 0x%08x\n", - MPP_DEV_CTRL, readl(MPP_DEV_CTRL)); - printk(KERN_DEBUG "GPIO_OUT (0x%08x) = 0x%08x\n", - GPIO_OUT, readl(GPIO_OUT)); - printk(KERN_DEBUG "GPIO_IO_CONF (0x%08x) = 0x%08x\n", - GPIO_IO_CONF, readl(GPIO_IO_CONF)); - printk(KERN_DEBUG "GPIO_BLINK_EN (0x%08x) = 0x%08x\n", - GPIO_BLINK_EN, readl(GPIO_BLINK_EN)); - printk(KERN_DEBUG "GPIO_IN_POL (0x%08x) = 0x%08x\n", - GPIO_IN_POL, readl(GPIO_IN_POL)); - printk(KERN_DEBUG "GPIO_DATA_IN (0x%08x) = 0x%08x\n", - GPIO_DATA_IN, readl(GPIO_DATA_IN)); - printk(KERN_DEBUG "GPIO_LEVEL_MASK (0x%08x) = 0x%08x\n", - GPIO_LEVEL_MASK, readl(GPIO_LEVEL_MASK)); - printk(KERN_DEBUG "GPIO_EDGE_CAUSE (0x%08x) = 0x%08x\n", - GPIO_EDGE_CAUSE, readl(GPIO_EDGE_CAUSE)); - printk(KERN_DEBUG "GPIO_EDGE_MASK (0x%08x) = 0x%08x\n", - GPIO_EDGE_MASK, readl(GPIO_EDGE_MASK)); -} diff --git a/arch/arm/mach-orion5x/include/mach/gpio.h b/arch/arm/mach-orion5x/include/mach/gpio.h index 65dc136a86f..a1a387b189a 100644 --- a/arch/arm/mach-orion5x/include/mach/gpio.h +++ b/arch/arm/mach-orion5x/include/mach/gpio.h @@ -2,18 +2,23 @@ * arch/arm/mach-orion5x/include/mach/gpio.h * * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any + * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ -extern int gpio_request(unsigned pin, const char *label); -extern void gpio_free(unsigned pin); -extern int gpio_direction_input(unsigned pin); -extern int gpio_direction_output(unsigned pin, int value); -extern int gpio_get_value(unsigned pin); -extern void gpio_set_value(unsigned pin, int value); -extern void orion5x_gpio_set_blink(unsigned pin, int blink); -extern void gpio_display(void); /* debug */ +#ifndef __ASM_ARCH_GPIO_H +#define __ASM_ARCH_GPIO_H + +#include <mach/irqs.h> +#include <plat/gpio.h> +#include <asm-generic/gpio.h> /* cansleep wrappers */ + +#define GPIO_MAX 32 +#define GPIO_OUT(pin) ORION5X_DEV_BUS_REG(0x100) +#define GPIO_IO_CONF(pin) ORION5X_DEV_BUS_REG(0x104) +#define GPIO_BLINK_EN(pin) ORION5X_DEV_BUS_REG(0x108) +#define GPIO_IN_POL(pin) ORION5X_DEV_BUS_REG(0x10c) +#define GPIO_DATA_IN(pin) ORION5X_DEV_BUS_REG(0x110) static inline int gpio_to_irq(int pin) { @@ -25,4 +30,5 @@ static inline int irq_to_gpio(int irq) return irq - IRQ_ORION5X_GPIO_START; } -#include <asm-generic/gpio.h> /* cansleep wrappers */ + +#endif diff --git a/arch/arm/mach-orion5x/include/mach/irqs.h b/arch/arm/mach-orion5x/include/mach/irqs.h index d5b0fbf6b96..a6fa9d8f12d 100644 --- a/arch/arm/mach-orion5x/include/mach/irqs.h +++ b/arch/arm/mach-orion5x/include/mach/irqs.h @@ -13,8 +13,6 @@ #ifndef __ASM_ARCH_IRQS_H #define __ASM_ARCH_IRQS_H -#include "orion5x.h" /* need GPIO_MAX */ - /* * Orion Main Interrupt Controller */ @@ -54,7 +52,7 @@ * Orion General Purpose Pins */ #define IRQ_ORION5X_GPIO_START 32 -#define NR_GPIO_IRQS GPIO_MAX +#define NR_GPIO_IRQS 32 #define NR_IRQS (IRQ_ORION5X_GPIO_START + NR_GPIO_IRQS) diff --git a/arch/arm/mach-orion5x/include/mach/orion5x.h b/arch/arm/mach-orion5x/include/mach/orion5x.h index 9f5ce1ce584..a8915081773 100644 --- a/arch/arm/mach-orion5x/include/mach/orion5x.h +++ b/arch/arm/mach-orion5x/include/mach/orion5x.h @@ -134,11 +134,6 @@ #define MPP_16_19_CTRL ORION5X_DEV_BUS_REG(0x050) #define MPP_DEV_CTRL ORION5X_DEV_BUS_REG(0x008) #define MPP_RESET_SAMPLE ORION5X_DEV_BUS_REG(0x010) -#define GPIO_OUT ORION5X_DEV_BUS_REG(0x100) -#define GPIO_IO_CONF ORION5X_DEV_BUS_REG(0x104) -#define GPIO_BLINK_EN ORION5X_DEV_BUS_REG(0x108) -#define GPIO_IN_POL ORION5X_DEV_BUS_REG(0x10c) -#define GPIO_DATA_IN ORION5X_DEV_BUS_REG(0x110) #define GPIO_EDGE_CAUSE ORION5X_DEV_BUS_REG(0x114) #define GPIO_EDGE_MASK ORION5X_DEV_BUS_REG(0x118) #define GPIO_LEVEL_MASK ORION5X_DEV_BUS_REG(0x11c) @@ -149,7 +144,6 @@ #define DEV_BUS_CTRL ORION5X_DEV_BUS_REG(0x4c0) #define DEV_BUS_INT_CAUSE ORION5X_DEV_BUS_REG(0x4d0) #define DEV_BUS_INT_MASK ORION5X_DEV_BUS_REG(0x4d4) -#define GPIO_MAX 32 /*************************************************************************** * Orion CPU Bridge Registers diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c index 632a36f5cf1..6b2f1353797 100644 --- a/arch/arm/mach-orion5x/irq.c +++ b/arch/arm/mach-orion5x/irq.c @@ -22,7 +22,7 @@ /***************************************************************************** * Orion GPIO IRQ * - * GPIO_IN_POL register controlls whether GPIO_DATA_IN will hold the same + * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same * value of the line or the opposite value. * * Level IRQ handlers: DATA_IN is used directly as cause register. @@ -82,7 +82,7 @@ static int orion5x_gpio_set_irq_type(u32 irq, u32 type) int pin = irq_to_gpio(irq); struct irq_desc *desc; - if ((readl(GPIO_IO_CONF) & (1 << pin)) == 0) { + if ((readl(GPIO_IO_CONF(pin)) & (1 << pin)) == 0) { printk(KERN_ERR "orion5x_gpio_set_irq_type failed " "(irq %d, pin %d).\n", irq, pin); return -EINVAL; @@ -94,22 +94,22 @@ static int orion5x_gpio_set_irq_type(u32 irq, u32 type) case IRQ_TYPE_LEVEL_HIGH: desc->handle_irq = handle_level_irq; desc->status |= IRQ_LEVEL; - orion5x_clrbits(GPIO_IN_POL, (1 << pin)); + orion5x_clrbits(GPIO_IN_POL(pin), (1 << pin)); break; case IRQ_TYPE_LEVEL_LOW: desc->handle_irq = handle_level_irq; desc->status |= IRQ_LEVEL; - orion5x_setbits(GPIO_IN_POL, (1 << pin)); + orion5x_setbits(GPIO_IN_POL(pin), (1 << pin)); break; case IRQ_TYPE_EDGE_RISING: desc->handle_irq = handle_edge_irq; desc->status &= ~IRQ_LEVEL; - orion5x_clrbits(GPIO_IN_POL, (1 << pin)); + orion5x_clrbits(GPIO_IN_POL(pin), (1 << pin)); break; case IRQ_TYPE_EDGE_FALLING: desc->handle_irq = handle_edge_irq; desc->status &= ~IRQ_LEVEL; - orion5x_setbits(GPIO_IN_POL, (1 << pin)); + orion5x_setbits(GPIO_IN_POL(pin), (1 << pin)); break; case IRQ_TYPE_EDGE_BOTH: desc->handle_irq = handle_edge_irq; @@ -117,11 +117,11 @@ static int orion5x_gpio_set_irq_type(u32 irq, u32 type) /* * set initial polarity based on current input level */ - if ((readl(GPIO_IN_POL) ^ readl(GPIO_DATA_IN)) + if ((readl(GPIO_IN_POL(pin)) ^ readl(GPIO_DATA_IN(pin))) & (1 << pin)) - orion5x_setbits(GPIO_IN_POL, (1 << pin)); /* falling */ + orion5x_setbits(GPIO_IN_POL(pin), (1 << pin)); /* falling */ else - orion5x_clrbits(GPIO_IN_POL, (1 << pin)); /* rising */ + orion5x_clrbits(GPIO_IN_POL(pin), (1 << pin)); /* rising */ break; default: @@ -149,7 +149,7 @@ static void orion5x_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) BUG_ON(irq < IRQ_ORION5X_GPIO_0_7 || irq > IRQ_ORION5X_GPIO_24_31); offs = (irq - IRQ_ORION5X_GPIO_0_7) * 8; - cause = (readl(GPIO_DATA_IN) & readl(GPIO_LEVEL_MASK)) | + cause = (readl(GPIO_DATA_IN(offs)) & readl(GPIO_LEVEL_MASK)) | (readl(GPIO_EDGE_CAUSE) & readl(GPIO_EDGE_MASK)); for (pin = offs; pin < offs + 8; pin++) { @@ -158,9 +158,9 @@ static void orion5x_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) desc = irq_desc + irq; if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { /* Swap polarity (race with GPIO line) */ - u32 polarity = readl(GPIO_IN_POL); + u32 polarity = readl(GPIO_IN_POL(pin)); polarity ^= 1 << pin; - writel(polarity, GPIO_IN_POL); + writel(polarity, GPIO_IN_POL(pin)); } generic_handle_irq(irq); } diff --git a/arch/arm/mach-orion5x/mpp.c b/arch/arm/mach-orion5x/mpp.c index 640ea2a3fc6..e23a3f91d6c 100644 --- a/arch/arm/mach-orion5x/mpp.c +++ b/arch/arm/mach-orion5x/mpp.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/mbus.h> #include <linux/io.h> +#include <asm/gpio.h> #include <mach/hardware.h> #include "common.h" #include "mpp.h" @@ -152,7 +153,10 @@ void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode) *reg &= ~(0xf << shift); *reg |= (num_type & 0xf) << shift; - orion5x_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO)); + if (mode->type == MPP_UNUSED && (mode->mpp < 16 || is_5182())) + orion_gpio_set_unused(mode->mpp); + + orion_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO)); mode++; } diff --git a/arch/arm/plat-orion/Makefile b/arch/arm/plat-orion/Makefile index 198f3dde2be..56021a72e10 100644 --- a/arch/arm/plat-orion/Makefile +++ b/arch/arm/plat-orion/Makefile @@ -6,3 +6,5 @@ obj-y := irq.o pcie.o time.o obj-m := obj-n := obj- := + +obj-$(CONFIG_GENERIC_GPIO) += gpio.o diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c new file mode 100644 index 00000000000..d86fc085e48 --- /dev/null +++ b/arch/arm/plat-orion/gpio.c @@ -0,0 +1,239 @@ +/* + * arch/arm/plat-orion/gpio.c + * + * Marvell Orion SoC GPIO handling. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <asm/gpio.h> + +static DEFINE_SPINLOCK(gpio_lock); +static const char *gpio_label[GPIO_MAX]; /* non null for allocated GPIOs */ +static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)]; + +static inline void __set_direction(unsigned pin, int input) +{ + u32 u; + + u = readl(GPIO_IO_CONF(pin)); + if (input) + u |= 1 << (pin & 31); + else + u &= ~(1 << (pin & 31)); + writel(u, GPIO_IO_CONF(pin)); +} + +static void __set_level(unsigned pin, int high) +{ + u32 u; + + u = readl(GPIO_OUT(pin)); + if (high) + u |= 1 << (pin & 31); + else + u &= ~(1 << (pin & 31)); + writel(u, GPIO_OUT(pin)); +} + + +/* + * GENERIC_GPIO primitives. + */ +int gpio_direction_input(unsigned pin) +{ + unsigned long flags; + + if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { + pr_debug("%s: invalid GPIO %d\n", __func__, pin); + return -EINVAL; + } + + spin_lock_irqsave(&gpio_lock, flags); + + /* + * Some callers might not have used gpio_request(), + * so flag this pin as requested now. + */ + if (gpio_label[pin] == NULL) + gpio_label[pin] = "?"; + + /* + * Configure GPIO direction. + */ + __set_direction(pin, 1); + + spin_unlock_irqrestore(&gpio_lock, flags); + + return 0; +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned pin, int value) +{ + unsigned long flags; + u32 u; + + if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { + pr_debug("%s: invalid GPIO %d\n", __func__, pin); + return -EINVAL; + } + + spin_lock_irqsave(&gpio_lock, flags); + + /* + * Some callers might not have used gpio_request(), + * so flag this pin as requested now. + */ + if (gpio_label[pin] == NULL) + gpio_label[pin] = "?"; + + /* + * Disable blinking. + */ + u = readl(GPIO_BLINK_EN(pin)); + u &= ~(1 << (pin & 31)); + writel(u, GPIO_BLINK_EN(pin)); + + /* + * Configure GPIO output value. + */ + __set_level(pin, value); + + /* + * Configure GPIO direction. + */ + __set_direction(pin, 0); + + spin_unlock_irqrestore(&gpio_lock, flags); + + return 0; +} +EXPORT_SYMBOL(gpio_direction_output); + +int gpio_get_value(unsigned pin) +{ + int val; + + if (readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31))) + val = readl(GPIO_DATA_IN(pin)) ^ readl(GPIO_IN_POL(pin)); + else + val = readl(GPIO_OUT(pin)); + + return (val >> (pin & 31)) & 1; +} +EXPORT_SYMBOL(gpio_get_value); + +void gpio_set_value(unsigned pin, int value) +{ + unsigned long flags; + u32 u; + + spin_lock_irqsave(&gpio_lock, flags); + + /* + * Disable blinking. + */ + u = readl(GPIO_BLINK_EN(pin)); + u &= ~(1 << (pin & 31)); + writel(u, GPIO_BLINK_EN(pin)); + + /* + * Configure GPIO output value. + */ + __set_level(pin, value); + + spin_unlock_irqrestore(&gpio_lock, flags); +} +EXPORT_SYMBOL(gpio_set_value); + +int gpio_request(unsigned pin, const char *label) +{ + unsigned long flags; + int ret; + + if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { + pr_debug("%s: invalid GPIO %d\n", __func__, pin); + return -EINVAL; + } + + spin_lock_irqsave(&gpio_lock, flags); + if (gpio_label[pin] == NULL) { + gpio_label[pin] = label ? label : "?"; + ret = 0; + } else { + pr_debug("%s: GPIO %d already used as %s\n", + __func__, pin, gpio_label[pin]); + ret = -EBUSY; + } + spin_unlock_irqrestore(&gpio_lock, flags); + + return ret; +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned pin) +{ + if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { + pr_debug("%s: invalid GPIO %d\n", __func__, pin); + return; + } + + if (gpio_label[pin] == NULL) + pr_warning("%s: GPIO %d already freed\n", __func__, pin); + else + gpio_label[pin] = NULL; +} +EXPORT_SYMBOL(gpio_free); + + +/* + * Orion-specific GPIO API extensions. + */ +void __init orion_gpio_set_unused(unsigned pin) +{ + /* + * Configure as output, drive low. + */ + __set_level(pin, 0); + __set_direction(pin, 0); +} + +void __init orion_gpio_set_valid(unsigned pin, int valid) +{ + if (valid) + __set_bit(pin, gpio_valid); + else + __clear_bit(pin, gpio_valid); +} + +void orion_gpio_set_blink(unsigned pin, int blink) +{ + unsigned long flags; + u32 u; + + spin_lock_irqsave(&gpio_lock, flags); + + /* + * Set output value to zero. + */ + __set_level(pin, 0); + + u = readl(GPIO_BLINK_EN(pin)); + if (blink) + u |= 1 << (pin & 31); + else + u &= ~(1 << (pin & 31)); + writel(u, GPIO_BLINK_EN(pin)); + + spin_unlock_irqrestore(&gpio_lock, flags); +} +EXPORT_SYMBOL(orion_gpio_set_blink); diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h new file mode 100644 index 00000000000..956658df269 --- /dev/null +++ b/arch/arm/plat-orion/include/plat/gpio.h @@ -0,0 +1,32 @@ +/* + * arch/arm/plat-orion/include/plat/gpio.h + * + * Marvell Orion SoC GPIO handling. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __PLAT_GPIO_H +#define __PLAT_GPIO_H + +/* + * GENERIC_GPIO primitives. + */ +int gpio_request(unsigned pin, const char *label); +void gpio_free(unsigned pin); +int gpio_direction_input(unsigned pin); +int gpio_direction_output(unsigned pin, int value); +int gpio_get_value(unsigned pin); +void gpio_set_value(unsigned pin, int value); + +/* + * Orion-specific GPIO API extensions. + */ +void orion_gpio_set_unused(unsigned pin); +void orion_gpio_set_valid(unsigned pin, int valid); +void orion_gpio_set_blink(unsigned pin, int blink); + + +#endif |