diff options
author | Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de> | 2007-09-30 23:35:09 +0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-10-13 02:43:36 +0400 |
commit | 689f2a01e68c0033f59055dd816ff27dc51f9dcc (patch) | |
tree | 4ca8339ec5da01e3cea8be9d5f35676c54bcf261 /arch/arm/mach-ns9xxx | |
parent | ba7d850a02c7c3357ec488776405470534e7ccf8 (diff) | |
download | linux-689f2a01e68c0033f59055dd816ff27dc51f9dcc.tar.xz |
[ARM] 4590/1: ns9xxx: add gpio handling functions
This implementation conforms to the general GPIO API
introduced in 2.6.21.
This patch was signed-of by David Brownell before I exported the functions
using EXPORT_SYMBOL.
Signed-off-by: Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-ns9xxx')
-rw-r--r-- | arch/arm/mach-ns9xxx/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-ns9xxx/gpio.c | 184 |
2 files changed, 185 insertions, 1 deletions
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile index 4476411b8140..6fb82b855a55 100644 --- a/arch/arm/mach-ns9xxx/Makefile +++ b/arch/arm/mach-ns9xxx/Makefile @@ -1,4 +1,4 @@ -obj-y := irq.o time.o generic.o +obj-y := irq.o time.o generic.o gpio.o obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o diff --git a/arch/arm/mach-ns9xxx/gpio.c b/arch/arm/mach-ns9xxx/gpio.c new file mode 100644 index 000000000000..87b872fdca7e --- /dev/null +++ b/arch/arm/mach-ns9xxx/gpio.c @@ -0,0 +1,184 @@ +/* + * arch/arm/mach-ns9xxx/gpio.c + * + * Copyright (C) 2006 by Digi International Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/compiler.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/module.h> + +#include <asm/arch-ns9xxx/gpio.h> +#include <asm/arch-ns9xxx/processor.h> +#include <asm/arch-ns9xxx/regs-bbu.h> +#include <asm/bug.h> +#include <asm/types.h> +#include <asm/bitops.h> + +#if defined(CONFIG_PROCESSOR_NS9360) +#define GPIO_MAX 72 +#elif defined(CONFIG_PROCESSOR_NS9750) +#define GPIO_MAX 49 +#endif + +/* protects BBU_GCONFx and BBU_GCTRLx */ +static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock); + +/* only access gpiores with atomic ops */ +static DECLARE_BITMAP(gpiores, GPIO_MAX); + +static inline int ns9xxx_valid_gpio(unsigned gpio) +{ +#if defined(CONFIG_PROCESSOR_NS9360) + if (processor_is_ns9360()) + return gpio <= 72; + else +#endif +#if defined(CONFIG_PROCESSOR_NS9750) + if (processor_is_ns9750()) + return gpio <= 49; + else +#endif + BUG(); +} + +static inline volatile u32 *ns9xxx_gpio_get_gconfaddr(unsigned gpio) +{ + if (gpio < 56) + return &BBU_GCONFb1(gpio / 8); + else + /* + * this could be optimised away on + * ns9750 only builds, but it isn't ... + */ + return &BBU_GCONFb2((gpio - 56) / 8); +} + +static inline volatile u32 *ns9xxx_gpio_get_gctrladdr(unsigned gpio) +{ + if (gpio < 32) + return &BBU_GCTRL1; + else if (gpio < 64) + return &BBU_GCTRL2; + else + /* this could be optimised away on ns9750 only builds */ + return &BBU_GCTRL3; +} + +static inline volatile u32 *ns9xxx_gpio_get_gstataddr(unsigned gpio) +{ + if (gpio < 32) + return &BBU_GSTAT1; + else if (gpio < 64) + return &BBU_GSTAT2; + else + /* this could be optimised away on ns9750 only builds */ + return &BBU_GSTAT3; +} + +int gpio_request(unsigned gpio, const char *label) +{ + if (likely(ns9xxx_valid_gpio(gpio))) + return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0; + else + return -EINVAL; +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned gpio) +{ + clear_bit(gpio, gpiores); + return; +} +EXPORT_SYMBOL(gpio_free); + +/* + * each gpio can serve for 4 different purposes [0..3]. These are called + * "functions" and passed in the parameter func. Functions 0-2 are always some + * special things, function 3 is GPIO. If func == 3 dir specifies input or + * output, and with inv you can enable an inverter (independent of func). + */ +static int __ns9xxx_gpio_configure(unsigned gpio, int dir, int inv, int func) +{ + volatile u32 *conf = ns9xxx_gpio_get_gconfaddr(gpio); + u32 confval; + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + + confval = *conf; + REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir); + REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv); + REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func); + *conf = confval; + + spin_unlock_irqrestore(&gpio_lock, flags); + + return 0; +} + +int ns9xxx_gpio_configure(unsigned gpio, int inv, int func) +{ + if (likely(ns9xxx_valid_gpio(gpio))) { + if (func == 3) { + printk(KERN_WARNING "use gpio_direction_input " + "or gpio_direction_output\n"); + return -EINVAL; + } else + return __ns9xxx_gpio_configure(gpio, 0, inv, func); + } else + return -EINVAL; +} +EXPORT_SYMBOL(ns9xxx_gpio_configure); + +int gpio_direction_input(unsigned gpio) +{ + if (likely(ns9xxx_valid_gpio(gpio))) { + return __ns9xxx_gpio_configure(gpio, 0, 0, 3); + } else + return -EINVAL; +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned gpio, int value) +{ + if (likely(ns9xxx_valid_gpio(gpio))) { + gpio_set_value(gpio, value); + + return __ns9xxx_gpio_configure(gpio, 1, 0, 3); + } else + return -EINVAL; +} +EXPORT_SYMBOL(gpio_direction_output); + +int gpio_get_value(unsigned gpio) +{ + volatile u32 *stat = ns9xxx_gpio_get_gstataddr(gpio); + int ret; + + ret = 1 & (*stat >> (gpio & 31)); + + return ret; +} +EXPORT_SYMBOL(gpio_get_value); + +void gpio_set_value(unsigned gpio, int value) +{ + volatile u32 *ctrl = ns9xxx_gpio_get_gctrladdr(gpio); + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + + if (value) + *ctrl |= 1 << (gpio & 31); + else + *ctrl &= ~(1 << (gpio & 31)); + + spin_unlock_irqrestore(&gpio_lock, flags); +} +EXPORT_SYMBOL(gpio_set_value); |