summaryrefslogtreecommitdiff
path: root/arch/arm/mach-ns9xxx/include/mach/gpio.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-ns9xxx/include/mach/gpio.h')
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/gpio.h470
1 files changed, 460 insertions, 10 deletions
diff --git a/arch/arm/mach-ns9xxx/include/mach/gpio.h b/arch/arm/mach-ns9xxx/include/mach/gpio.h
index 5eb349032579..40e246dabdcc 100644
--- a/arch/arm/mach-ns9xxx/include/mach/gpio.h
+++ b/arch/arm/mach-ns9xxx/include/mach/gpio.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-ns9xxx/include/mach/gpio.h
*
- * Copyright (C) 2007 by Digi International Inc.
+ * Copyright (C) 2007,2008 by Digi International Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -11,21 +11,457 @@
#ifndef __ASM_ARCH_GPIO_H
#define __ASM_ARCH_GPIO_H
+#include <linux/spinlock.h>
#include <asm/errno.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/processor.h>
-int gpio_request(unsigned gpio, const char *label);
+#include <mach/regs-io-ns921x.h>
+#include <mach/regs-bbu.h>
+
+
+/* Macros for configuring the GPIO-functions */
+#if defined(CONFIG_PROCESSOR_NS9210) || defined(CONFIG_PROCESSOR_NS9215)
+# define NS921X_GPIO_FUNC_0 (0x00)
+# define NS921X_GPIO_FUNC_1 (0x01)
+# define NS921X_GPIO_FUNC_2 (0x02)
+# define NS921X_GPIO_FUNC_3 (0x03)
+# define NS921X_GPIO_FUNC_4 (0x04)
+
+# define NS921X_GPIO_FUNC_GPIO NS921X_GPIO_FUNC_3
+
+# define NS921X_GPIO_INPUT (0x00)
+# define NS921X_GPIO_OUTPUT (0x01)
+
+# define NS921X_GPIO_INVERT (0x01)
+# define NS921X_GPIO_DONT_INVERT (0x00)
+
+# define NS921X_GPIO_ENABLE_PULLUP (0x00)
+# define NS921X_GPIO_DISABLE_PULLUP (0x01)
+#endif
+
+/* Macros for configuring the GPIO-functions */
+#if defined(CONFIG_PROCESSOR_NS9360)
+# define NS9360_GPIO_FUNC_0 (0x00)
+# define NS9360_GPIO_FUNC_1 (0x01)
+# define NS9360_GPIO_FUNC_2 (0x02)
+# define NS9360_GPIO_FUNC_3 (0x03)
+# define NS9360_GPIO_FUNC_4 (0x04)
+
+# define NS9360_GPIO_FUNC_GPIO NS9360_GPIO_FUNC_3
+
+# define NS9360_GPIO_INPUT (0x00)
+# define NS9360_GPIO_OUTPUT (0x01)
+
+# define NS9360_GPIO_INVERT (0x01)
+# define NS9360_GPIO_DONT_INVERT (0x00)
+#endif
+
+
+struct gpio_to_irq_map {
+ unsigned gpio;
+ unsigned irq;
+ int func;
+};
+
+#define NS9XXX_NUM_GPIO 0
+
+#if defined(CONFIG_PROCESSOR_NS9210)
+# define NS9XXX_NUM_GPIO_NS9210 108
+# if NS9XXX_NUM_GPIO < NS9XXX_NUM_GPIO_NS9210
+# undef NS9XXX_NUM_GPIO
+# define NS9XXX_NUM_GPIO NS9XXX_NUM_GPIO_NS9210
+# endif
+static inline int gpio_issocgpio_ns9210(unsigned gpio)
+{
+ return gpio < NS9XXX_NUM_GPIO_NS9210 && !(gpio >= 50 && gpio < 105);
+}
+#endif
+
+#if defined(CONFIG_PROCESSOR_NS9215)
+# define NS9XXX_NUM_GPIO_NS9215 108
+# if NS9XXX_NUM_GPIO < NS9XXX_NUM_GPIO_NS9215
+# undef NS9XXX_NUM_GPIO
+# define NS9XXX_NUM_GPIO NS9XXX_NUM_GPIO_NS9215
+# endif
+static inline int gpio_issocgpio_ns9215(unsigned gpio)
+{
+ return gpio < NS9XXX_NUM_GPIO_NS9215;
+}
+#endif
+
+static const inline struct gpio_to_irq_map *gpio_get_map(unsigned gpio,
+ const struct gpio_to_irq_map map[], size_t array_size)
+{
+ /* TODO: check if a binary search yields some performance advantage */
+ int i;
+
+ for (i = 0; i < array_size; ++i) {
+ if (map[i].gpio == gpio)
+ return &map[i];
+ }
+
+ return NULL;
+}
+
+#if defined(CONFIG_PROCESSOR_NS921X)
+const struct gpio_to_irq_map *gpio_get_map_ns921x(unsigned gpio) __attribute__((const));
+
+static inline void gpio_configure_ns921x_unlocked(unsigned gpio,
+ int dir, int inv, int func, int dispullup)
+{
+ void __iomem *conf = NS921X_IO_GPIOCONFx(gpio / 4);
+ u32 confval;
+
+ confval = __raw_readl(conf);
+ REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, DIR, gpio & 3, dir);
+ REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, INV, gpio & 3, inv);
+ REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, FUNC, gpio & 3, func);
+ if (gpio != 9 && gpio != 12 && (gpio < 102 || gpio > 105))
+ REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, PUEN, gpio & 3, dispullup);
+ else {
+ if (dispullup)
+ pr_warning("cannot disable pullup for gpio %u\n", gpio);
+
+ REGSETIM_IDX(confval, NS921X_IO_GPIOCONFx, PUEN, gpio & 3, 0);
+ }
+
+ __raw_writel(confval, conf);
+}
+
+static inline void gpio_configure_ns921x(unsigned gpio,
+ int dir, int inv, int func, int dispullup)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ gpio_configure_ns921x_unlocked(gpio, dir, inv, func, dispullup);
+
+ local_irq_restore(flags);
+}
+
+static inline int gpio_get_value_ns921x(unsigned gpio)
+{
+ void __iomem *stat = NS921X_IO_GPIOSTATx(gpio / 32);
+
+ return (__raw_readl(stat) >> (gpio & 31)) & 1;
+}
+
+static inline void gpio_set_value_ns921x_unlocked(unsigned gpio, int value)
+{
+ void __iomem *ctrl = NS921X_IO_GPIOCTRLx(gpio / 32);
+ u32 ctrlval;
+
+ ctrlval = __raw_readl(ctrl);
+
+ if (value)
+ ctrlval |= 1 << (gpio & 31);
+ else
+ ctrlval &= ~(1 << (gpio & 31));
+
+ __raw_writel(ctrlval, ctrl);
+}
+
+static inline int gpio_direction_input_ns921x_unlocked(unsigned gpio)
+{
+ gpio_configure_ns921x_unlocked(gpio, 0, 0, 3, 0);
+ return 0;
+}
+
+static inline int gpio_direction_irqinput_ns921x_unlocked(unsigned gpio)
+{
+ const struct gpio_to_irq_map *map = gpio_get_map_ns921x(gpio);
+
+ if (map) {
+ gpio_configure_ns921x_unlocked(gpio, 0, 0, map->func, 0);
+ return 0;
+ } else
+ return gpio_direction_input_ns921x_unlocked(gpio);
+}
+
+static inline int gpio_direction_output_ns921x_unlocked(unsigned gpio,
+ int value)
+{
+ gpio_set_value_ns921x_unlocked(gpio, value);
+ gpio_configure_ns921x_unlocked(gpio, 1, 0, 3, 0);
+ return 0;
+}
+
+#endif /* if defined(CONFIG_PROCESSOR_NS921X) */
+
+#if defined(CONFIG_PROCESSOR_NS9360)
+# define NS9XXX_NUM_GPIO_NS9360 73
+# if NS9XXX_NUM_GPIO < NS9XXX_NUM_GPIO_NS9360
+# undef NS9XXX_NUM_GPIO
+# define NS9XXX_NUM_GPIO NS9XXX_NUM_GPIO_NS9360
+# endif
+static inline void __iomem *gpio_ns9360_gstataddr(unsigned gpio)
+{
+ if (gpio < 32)
+ return NS9360_BBU_GSTAT1;
+ else if (gpio < 64)
+ return NS9360_BBU_GSTAT2;
+ else
+ return NS9360_BBU_GSTAT3;
+}
+
+static inline void __iomem *gpio_ns9360_gctrladdr(unsigned gpio)
+{
+ if (gpio < 32)
+ return NS9360_BBU_GCTRL1;
+ else if (gpio < 64)
+ return NS9360_BBU_GCTRL2;
+ else
+ return NS9360_BBU_GCTRL3;
+}
+
+static inline void __iomem *gpio_ns9360_gconfaddr(unsigned gpio)
+{
+ if (gpio < 56)
+ return NS9360_BBU_GCONFb1(gpio / 8);
+ else
+ /* this could be optimised away on
+ * ns9750 only builds, but it isn't ...
+ */
+ return NS9360_BBU_GCONFb2((gpio - 56) / 8);
+}
+
+static inline int gpio_issocgpio_ns9360(unsigned gpio)
+{
+ return gpio <= 72;
+}
+
+const struct gpio_to_irq_map *gpio_get_map_ns9360(unsigned gpio) __attribute__((const));
+
+static inline void gpio_configure_ns9360_unlocked(unsigned gpio,
+ int dir, int inv, int func)
+{
+ void __iomem *conf = gpio_ns9360_gconfaddr(gpio);
+ u32 confval;
+
+ confval = __raw_readl(conf);
+ REGSETIM_IDX(confval, NS9360_BBU_GCONFx, DIR, gpio & 7, dir);
+ REGSETIM_IDX(confval, NS9360_BBU_GCONFx, INV, gpio & 7, inv);
+ REGSETIM_IDX(confval, NS9360_BBU_GCONFx, FUNC, gpio & 7, func);
+ __raw_writel(confval, conf);
+}
+
+static inline void gpio_configure_ns9360(unsigned gpio,
+ int dir, int inv, int func)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ gpio_configure_ns9360_unlocked(gpio, dir, inv, func);
+
+ local_irq_restore(flags);
+}
+
+static inline int gpio_get_value_ns9360(unsigned gpio)
+{
+ void __iomem *stat = gpio_ns9360_gstataddr(gpio);
+
+ return (__raw_readl(stat) >> (gpio & 31)) & 1;
+}
+
+static inline void gpio_set_value_ns9360_unlocked(unsigned gpio, int value)
+{
+ void __iomem *ctrl = gpio_ns9360_gctrladdr(gpio);
+ u32 ctrlval;
+
+ ctrlval = __raw_readl(ctrl);
+
+ if (value)
+ ctrlval |= 1 << (gpio & 31);
+ else
+ ctrlval &= ~(1 << (gpio & 31));
+
+ __raw_writel(ctrlval, ctrl);
+}
+
+static inline int gpio_direction_input_ns9360_unlocked(unsigned gpio)
+{
+ gpio_configure_ns9360_unlocked(gpio, 0, 0, 3);
+ return 0;
+}
+
+static inline int gpio_direction_irqinput_ns9360_unlocked(unsigned gpio)
+{
+ const struct gpio_to_irq_map *map = gpio_get_map_ns9360(gpio);
+ if (map) {
+ gpio_configure_ns9360_unlocked(gpio, 0, 0, map->func);
+ return 0;
+ } else
+ return gpio_direction_input_ns9360_unlocked(gpio);
+}
+
+static inline int gpio_direction_output_ns9360_unlocked(unsigned gpio,
+ int value)
+{
+ gpio_set_value_ns9360_unlocked(gpio, value);
+ gpio_configure_ns9360_unlocked(gpio, 1, 0, 3);
+ return 0;
+}
+
+#endif /* if defined(CONFIG_PROCESSOR_NS9360) */
+
+static inline int gpio_issocgpio(unsigned gpio)
+{
+#if defined(CONFIG_PROCESSOR_NS9210)
+ if (processor_is_ns9210())
+ return gpio_issocgpio_ns9210(gpio);
+ else
+#endif
+#if defined(CONFIG_PROCESSOR_NS9215)
+ if (processor_is_ns9215())
+ return gpio_issocgpio_ns9215(gpio);
+ else
+#endif
+#if defined(CONFIG_PROCESSOR_NS9360)
+ if (processor_is_ns9360())
+ return gpio_issocgpio_ns9360(gpio);
+ else
+#endif
+ BUG();
+
+ BUG();
+
+ return 0;
+}
+
+#if defined(CONFIG_GPIOLIB)
+
+#include <asm-generic/gpio.h>
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ return __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+ return __gpio_cansleep(gpio);
+}
+
+#else /* if defined(CONFIG_GPIOLIB) */
+
+extern spinlock_t gpio_lock;
+
+int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
-int ns9xxx_gpio_configure(unsigned gpio, int inv, int func);
+static inline int gpio_get_value(unsigned gpio)
+{
+#if defined(CONFIG_PROCESSOR_NS921X)
+ if (processor_is_ns921x())
+ return gpio_get_value_ns921x(gpio);
+ else
+#endif
+#if defined(CONFIG_PROCESSOR_NS9360)
+ if (processor_is_ns9360())
+ return gpio_get_value_ns9360(gpio);
+ else
+#endif
+ BUG();
+}
+
+static inline void gpio_set_value_unlocked(unsigned gpio, int value)
+{
+#if defined(CONFIG_PROCESSOR_NS921X)
+ if (processor_is_ns921x())
+ gpio_set_value_ns921x_unlocked(gpio, value);
+ else
+#endif
+#if defined(CONFIG_PROCESSOR_NS9360)
+ if (processor_is_ns9360())
+ gpio_set_value_ns9360_unlocked(gpio, value);
+ else
+#endif
+ BUG();
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ unsigned long flags;
+
+ BUG_ON(!gpio_issocgpio(gpio));
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ gpio_set_value_unlocked(gpio, value);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ if (likely(gpio_issocgpio(gpio))) {
+ int ret = -EINVAL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+#if defined(CONFIG_PROCESSOR_NS921X)
+ if (processor_is_ns921x())
+ ret = gpio_direction_irqinput_ns921x_unlocked(gpio);
+ else
+#endif
+#if defined(CONFIG_PROCESSOR_NS9360)
+ if (processor_is_ns9360())
+ ret = gpio_direction_irqinput_ns9360_unlocked(gpio);
+ else
+#endif
+ BUG();
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
-int gpio_direction_input(unsigned gpio);
+ return ret;
+ } else
+ return -EINVAL;
+}
+
+static inline int gpio_direction_output(unsigned gpio, int value)
+{
+ if (likely(gpio_issocgpio(gpio))) {
+ int ret = -EINVAL;
+ unsigned long flags;
-int gpio_direction_output(unsigned gpio, int value);
+ spin_lock_irqsave(&gpio_lock, flags);
-int gpio_get_value(unsigned gpio);
+#if defined(CONFIG_PROCESSOR_NS921X)
+ if (processor_is_ns921x())
+ ret = gpio_direction_output_ns921x_unlocked(gpio,
+ value);
+ else
+#endif
+#if defined(CONFIG_PROCESSOR_NS9360)
+ if (processor_is_ns9360())
+ ret = gpio_direction_output_ns9360_unlocked(gpio,
+ value);
+ else
+#endif
+ BUG();
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
+ return ret;
+ } else
+ return -EINVAL;
+}
+
+#include <asm-generic/gpio.h>
+
+#endif /* if defined(CONFIG_GPIOLIB) / else */
-void gpio_set_value(unsigned gpio, int value);
/*
* ns9xxx can use gpio pins to trigger an irq, but it's not generic
@@ -33,6 +469,23 @@ void gpio_set_value(unsigned gpio, int value);
*/
static inline int gpio_to_irq(unsigned gpio)
{
+#if defined(CONFIG_PROCESSOR_NS921X)
+ if (processor_is_ns921x()) {
+ const struct gpio_to_irq_map *map = gpio_get_map_ns921x(gpio);
+
+ if (map)
+ return map->irq;
+ }
+#endif
+#if defined(CONFIG_PROCESSOR_NS9360)
+ if (processor_is_ns9360()) {
+ const struct gpio_to_irq_map *map = gpio_get_map_ns9360(gpio);
+
+ if (map)
+ return map->irq;
+ }
+#endif
+
return -EINVAL;
}
@@ -41,7 +494,4 @@ static inline int irq_to_gpio(unsigned irq)
return -EINVAL;
}
-/* get the cansleep() stubs */
-#include <asm-generic/gpio.h>
-
#endif /* ifndef __ASM_ARCH_GPIO_H */