Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen...
[sfrench/cifs-2.6.git] / arch / arm / mach-ns9xxx / gpio.c
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/io.h>
20 #include <asm/bug.h>
21 #include <asm/types.h>
22 #include <asm/bitops.h>
23
24 #if defined(CONFIG_PROCESSOR_NS9360)
25 #define GPIO_MAX 72
26 #elif defined(CONFIG_PROCESSOR_NS9750)
27 #define GPIO_MAX 49
28 #endif
29
30 /* protects BBU_GCONFx and BBU_GCTRLx */
31 static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock);
32
33 /* only access gpiores with atomic ops */
34 static DECLARE_BITMAP(gpiores, GPIO_MAX + 1);
35
36 static inline int ns9xxx_valid_gpio(unsigned gpio)
37 {
38 #if defined(CONFIG_PROCESSOR_NS9360)
39         if (processor_is_ns9360())
40                 return gpio <= 72;
41         else
42 #endif
43 #if defined(CONFIG_PROCESSOR_NS9750)
44         if (processor_is_ns9750())
45                 return gpio <= 49;
46         else
47 #endif
48                 BUG();
49 }
50
51 static inline void __iomem *ns9xxx_gpio_get_gconfaddr(unsigned gpio)
52 {
53         if (gpio < 56)
54                 return BBU_GCONFb1(gpio / 8);
55         else
56                 /*
57                  * this could be optimised away on
58                  * ns9750 only builds, but it isn't ...
59                  */
60                 return BBU_GCONFb2((gpio - 56) / 8);
61 }
62
63 static inline void __iomem *ns9xxx_gpio_get_gctrladdr(unsigned gpio)
64 {
65         if (gpio < 32)
66                 return BBU_GCTRL1;
67         else if (gpio < 64)
68                 return BBU_GCTRL2;
69         else
70                 /* this could be optimised away on ns9750 only builds */
71                 return BBU_GCTRL3;
72 }
73
74 static inline void __iomem *ns9xxx_gpio_get_gstataddr(unsigned gpio)
75 {
76         if (gpio < 32)
77                 return BBU_GSTAT1;
78         else if (gpio < 64)
79                 return BBU_GSTAT2;
80         else
81                 /* this could be optimised away on ns9750 only builds */
82                 return BBU_GSTAT3;
83 }
84
85 int gpio_request(unsigned gpio, const char *label)
86 {
87         if (likely(ns9xxx_valid_gpio(gpio)))
88                 return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0;
89         else
90                 return -EINVAL;
91 }
92 EXPORT_SYMBOL(gpio_request);
93
94 void gpio_free(unsigned gpio)
95 {
96         clear_bit(gpio, gpiores);
97         return;
98 }
99 EXPORT_SYMBOL(gpio_free);
100
101 /*
102  * each gpio can serve for 4 different purposes [0..3].  These are called
103  * "functions" and passed in the parameter func.  Functions 0-2 are always some
104  * special things, function 3 is GPIO.  If func == 3 dir specifies input or
105  * output, and with inv you can enable an inverter (independent of func).
106  */
107 static int __ns9xxx_gpio_configure(unsigned gpio, int dir, int inv, int func)
108 {
109         void __iomem *conf = ns9xxx_gpio_get_gconfaddr(gpio);
110         u32 confval;
111         unsigned long flags;
112
113         spin_lock_irqsave(&gpio_lock, flags);
114
115         confval = __raw_readl(conf);
116         REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir);
117         REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv);
118         REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func);
119         __raw_writel(confval, conf);
120
121         spin_unlock_irqrestore(&gpio_lock, flags);
122
123         return 0;
124 }
125
126 int ns9xxx_gpio_configure(unsigned gpio, int inv, int func)
127 {
128         if (likely(ns9xxx_valid_gpio(gpio))) {
129                 if (func == 3) {
130                         printk(KERN_WARNING "use gpio_direction_input "
131                                         "or gpio_direction_output\n");
132                         return -EINVAL;
133                 } else
134                         return __ns9xxx_gpio_configure(gpio, 0, inv, func);
135         } else
136                 return -EINVAL;
137 }
138 EXPORT_SYMBOL(ns9xxx_gpio_configure);
139
140 int gpio_direction_input(unsigned gpio)
141 {
142         if (likely(ns9xxx_valid_gpio(gpio))) {
143                 return __ns9xxx_gpio_configure(gpio, 0, 0, 3);
144         } else
145                 return -EINVAL;
146 }
147 EXPORT_SYMBOL(gpio_direction_input);
148
149 int gpio_direction_output(unsigned gpio, int value)
150 {
151         if (likely(ns9xxx_valid_gpio(gpio))) {
152                 gpio_set_value(gpio, value);
153
154                 return __ns9xxx_gpio_configure(gpio, 1, 0, 3);
155         } else
156                 return -EINVAL;
157 }
158 EXPORT_SYMBOL(gpio_direction_output);
159
160 int gpio_get_value(unsigned gpio)
161 {
162         void __iomem *stat = ns9xxx_gpio_get_gstataddr(gpio);
163         int ret;
164
165         ret = 1 & (__raw_readl(stat) >> (gpio & 31));
166
167         return ret;
168 }
169 EXPORT_SYMBOL(gpio_get_value);
170
171 void gpio_set_value(unsigned gpio, int value)
172 {
173         void __iomem *ctrl = ns9xxx_gpio_get_gctrladdr(gpio);
174         u32 ctrlval;
175         unsigned long flags;
176
177         spin_lock_irqsave(&gpio_lock, flags);
178
179         ctrlval = __raw_readl(ctrl);
180
181         if (value)
182                 ctrlval |= 1 << (gpio & 31);
183         else
184                 ctrlval &= ~(1 << (gpio & 31));
185
186         __raw_writel(ctrlval, ctrl);
187
188         spin_unlock_irqrestore(&gpio_lock, flags);
189 }
190 EXPORT_SYMBOL(gpio_set_value);