aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/mach-ns9xxx/Makefile2
-rw-r--r--arch/arm/mach-ns9xxx/gpio.c184
-rw-r--r--include/asm-arm/arch-ns9xxx/gpio.h47
4 files changed, 233 insertions, 1 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 691aae309c8a..6acc59da332d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -318,6 +318,7 @@ config ARCH_KS8695
318 318
319config ARCH_NS9XXX 319config ARCH_NS9XXX
320 bool "NetSilicon NS9xxx" 320 bool "NetSilicon NS9xxx"
321 select GENERIC_GPIO
321 help 322 help
322 Say Y here if you intend to run this kernel on a NetSilicon NS9xxx 323 Say Y here if you intend to run this kernel on a NetSilicon NS9xxx
323 System. 324 System.
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 @@
1obj-y := irq.o time.o generic.o 1obj-y := irq.o time.o generic.o gpio.o
2 2
3obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o 3obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o
4obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o 4obj-$(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 @@
1/*
2 * arch/arm/mach-ns9xxx/gpio.c
3 *
4 * Copyright (C) 2006 by Digi International Inc.
5 * All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 */
11#include <linux/compiler.h>
12#include <linux/init.h>
13#include <linux/spinlock.h>
14#include <linux/module.h>
15
16#include <asm/arch-ns9xxx/gpio.h>
17#include <asm/arch-ns9xxx/processor.h>
18#include <asm/arch-ns9xxx/regs-bbu.h>
19#include <asm/bug.h>
20#include <asm/types.h>
21#include <asm/bitops.h>
22
23#if defined(CONFIG_PROCESSOR_NS9360)
24#define GPIO_MAX 72
25#elif defined(CONFIG_PROCESSOR_NS9750)
26#define GPIO_MAX 49
27#endif
28
29/* protects BBU_GCONFx and BBU_GCTRLx */
30static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock);
31
32/* only access gpiores with atomic ops */
33static DECLARE_BITMAP(gpiores, GPIO_MAX);
34
35static inline int ns9xxx_valid_gpio(unsigned gpio)
36{
37#if defined(CONFIG_PROCESSOR_NS9360)
38 if (processor_is_ns9360())
39 return gpio <= 72;
40 else
41#endif
42#if defined(CONFIG_PROCESSOR_NS9750)
43 if (processor_is_ns9750())
44 return gpio <= 49;
45 else
46#endif
47 BUG();
48}
49
50static inline volatile u32 *ns9xxx_gpio_get_gconfaddr(unsigned gpio)
51{
52 if (gpio < 56)
53 return &BBU_GCONFb1(gpio / 8);
54 else
55 /*
56 * this could be optimised away on
57 * ns9750 only builds, but it isn't ...
58 */
59 return &BBU_GCONFb2((gpio - 56) / 8);
60}
61
62static inline volatile u32 *ns9xxx_gpio_get_gctrladdr(unsigned gpio)
63{
64 if (gpio < 32)
65 return &BBU_GCTRL1;
66 else if (gpio < 64)
67 return &BBU_GCTRL2;
68 else
69 /* this could be optimised away on ns9750 only builds */
70 return &BBU_GCTRL3;
71}
72
73static inline volatile u32 *ns9xxx_gpio_get_gstataddr(unsigned gpio)
74{
75 if (gpio < 32)
76 return &BBU_GSTAT1;
77 else if (gpio < 64)
78 return &BBU_GSTAT2;
79 else
80 /* this could be optimised away on ns9750 only builds */
81 return &BBU_GSTAT3;
82}
83
84int gpio_request(unsigned gpio, const char *label)
85{
86 if (likely(ns9xxx_valid_gpio(gpio)))
87 return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0;
88 else
89 return -EINVAL;
90}
91EXPORT_SYMBOL(gpio_request);
92
93void gpio_free(unsigned gpio)
94{
95 clear_bit(gpio, gpiores);
96 return;
97}
98EXPORT_SYMBOL(gpio_free);
99
100/*
101 * each gpio can serve for 4 different purposes [0..3]. These are called
102 * "functions" and passed in the parameter func. Functions 0-2 are always some
103 * special things, function 3 is GPIO. If func == 3 dir specifies input or
104 * output, and with inv you can enable an inverter (independent of func).
105 */
106static int __ns9xxx_gpio_configure(unsigned gpio, int dir, int inv, int func)
107{
108 volatile u32 *conf = ns9xxx_gpio_get_gconfaddr(gpio);
109 u32 confval;
110 unsigned long flags;
111
112 spin_lock_irqsave(&gpio_lock, flags);
113
114 confval = *conf;
115 REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir);
116 REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv);
117 REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func);
118 *conf = confval;
119
120 spin_unlock_irqrestore(&gpio_lock, flags);
121
122 return 0;
123}
124
125int ns9xxx_gpio_configure(unsigned gpio, int inv, int func)
126{
127 if (likely(ns9xxx_valid_gpio(gpio))) {
128 if (func == 3) {
129 printk(KERN_WARNING "use gpio_direction_input "
130 "or gpio_direction_output\n");
131 return -EINVAL;
132 } else
133 return __ns9xxx_gpio_configure(gpio, 0, inv, func);
134 } else
135 return -EINVAL;
136}
137EXPORT_SYMBOL(ns9xxx_gpio_configure);
138
139int gpio_direction_input(unsigned gpio)
140{
141 if (likely(ns9xxx_valid_gpio(gpio))) {
142 return __ns9xxx_gpio_configure(gpio, 0, 0, 3);
143 } else
144 return -EINVAL;
145}
146EXPORT_SYMBOL(gpio_direction_input);
147
148int gpio_direction_output(unsigned gpio, int value)
149{
150 if (likely(ns9xxx_valid_gpio(gpio))) {
151 gpio_set_value(gpio, value);
152
153 return __ns9xxx_gpio_configure(gpio, 1, 0, 3);
154 } else
155 return -EINVAL;
156}
157EXPORT_SYMBOL(gpio_direction_output);
158
159int gpio_get_value(unsigned gpio)
160{
161 volatile u32 *stat = ns9xxx_gpio_get_gstataddr(gpio);
162 int ret;
163
164 ret = 1 & (*stat >> (gpio & 31));
165
166 return ret;
167}
168EXPORT_SYMBOL(gpio_get_value);
169
170void gpio_set_value(unsigned gpio, int value)
171{
172 volatile u32 *ctrl = ns9xxx_gpio_get_gctrladdr(gpio);
173 unsigned long flags;
174
175 spin_lock_irqsave(&gpio_lock, flags);
176
177 if (value)
178 *ctrl |= 1 << (gpio & 31);
179 else
180 *ctrl &= ~(1 << (gpio & 31));
181
182 spin_unlock_irqrestore(&gpio_lock, flags);
183}
184EXPORT_SYMBOL(gpio_set_value);
diff --git a/include/asm-arm/arch-ns9xxx/gpio.h b/include/asm-arm/arch-ns9xxx/gpio.h
new file mode 100644
index 000000000000..adbca08583c0
--- /dev/null
+++ b/include/asm-arm/arch-ns9xxx/gpio.h
@@ -0,0 +1,47 @@
1/*
2 * include/asm-arm/arch-ns9xxx/gpio.h
3 *
4 * Copyright (C) 2007 by Digi International Inc.
5 * All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10*/
11#ifndef __ASM_ARCH_GPIO_H
12#define __ASM_ARCH_GPIO_H
13
14#include <asm/errno.h>
15
16int gpio_request(unsigned gpio, const char *label);
17
18void gpio_free(unsigned gpio);
19
20int ns9xxx_gpio_configure(unsigned gpio, int inv, int func);
21
22int gpio_direction_input(unsigned gpio);
23
24int gpio_direction_output(unsigned gpio, int value);
25
26int gpio_get_value(unsigned gpio);
27
28void gpio_set_value(unsigned gpio, int value);
29
30/*
31 * ns9xxx can use gpio pins to trigger an irq, but it's not generic
32 * enough to be supported by the gpio_to_irq/irq_to_gpio interface
33 */
34static inline int gpio_to_irq(unsigned gpio)
35{
36 return -EINVAL;
37}
38
39static inline int irq_to_gpio(unsigned irq)
40{
41 return -EINVAL;
42}
43
44/* get the cansleep() stubs */
45#include <asm-generic/gpio.h>
46
47#endif /* ifndef __ASM_ARCH_GPIO_H */