OpenWrt – Blame information for rev 2
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * ADM5120 generic GPIO API support via GPIOLIB |
||
3 | * |
||
4 | * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org> |
||
5 | * |
||
6 | * This program is free software; you can redistribute it and/or modify it |
||
7 | * under the terms of the GNU General Public License version 2 as published |
||
8 | * by the Free Software Foundation. |
||
9 | * |
||
10 | */ |
||
11 | |||
12 | #include <linux/init.h> |
||
13 | #include <linux/types.h> |
||
14 | #include <linux/module.h> |
||
15 | #include <linux/irq.h> |
||
16 | #include <linux/delay.h> |
||
17 | #include <linux/platform_device.h> |
||
18 | #include <linux/io.h> |
||
19 | #include <linux/gpio.h> |
||
20 | |||
21 | #include <asm/addrspace.h> |
||
22 | |||
23 | #include <asm/mach-adm5120/adm5120_defs.h> |
||
24 | #include <asm/mach-adm5120/adm5120_info.h> |
||
25 | #include <asm/mach-adm5120/adm5120_switch.h> |
||
26 | |||
27 | #define GPIO_REG(r) (void __iomem *)(KSEG1ADDR(ADM5120_SWITCH_BASE) + r) |
||
28 | |||
29 | struct gpio1_desc { |
||
30 | void __iomem *reg; /* register address */ |
||
31 | u8 iv_shift; /* shift amount for input bit */ |
||
32 | u8 mode_shift; /* shift amount for mode bits */ |
||
33 | }; |
||
34 | |||
35 | #define GPIO1_DESC(p, l) { \ |
||
36 | .reg = GPIO_REG(SWITCH_REG_PORT0_LED + ((p) * 4)), \ |
||
37 | .iv_shift = LED0_IV_SHIFT + (l), \ |
||
38 | .mode_shift = (l) * 4 \ |
||
39 | } |
||
40 | |||
41 | static struct gpio1_desc gpio1_table[15] = { |
||
42 | GPIO1_DESC(0, 0), GPIO1_DESC(0, 1), GPIO1_DESC(0, 2), |
||
43 | GPIO1_DESC(1, 0), GPIO1_DESC(1, 1), GPIO1_DESC(1, 2), |
||
44 | GPIO1_DESC(2, 0), GPIO1_DESC(2, 1), GPIO1_DESC(2, 2), |
||
45 | GPIO1_DESC(3, 0), GPIO1_DESC(3, 1), GPIO1_DESC(3, 2), |
||
46 | GPIO1_DESC(4, 0), GPIO1_DESC(4, 1), GPIO1_DESC(4, 2) |
||
47 | }; |
||
48 | |||
49 | static u32 gpio_conf2; |
||
50 | |||
51 | int adm5120_gpio_to_irq(unsigned gpio) |
||
52 | { |
||
53 | int ret; |
||
54 | |||
55 | switch (gpio) { |
||
56 | case ADM5120_GPIO_PIN2: |
||
57 | ret = ADM5120_IRQ_GPIO2; |
||
58 | break; |
||
59 | case ADM5120_GPIO_PIN4: |
||
60 | ret = ADM5120_IRQ_GPIO4; |
||
61 | break; |
||
62 | default: |
||
63 | ret = -EINVAL; |
||
64 | break; |
||
65 | } |
||
66 | |||
67 | return ret; |
||
68 | } |
||
69 | EXPORT_SYMBOL(adm5120_gpio_to_irq); |
||
70 | |||
71 | int adm5120_irq_to_gpio(unsigned irq) |
||
72 | { |
||
73 | int ret; |
||
74 | |||
75 | switch (irq) { |
||
76 | case ADM5120_IRQ_GPIO2: |
||
77 | ret = ADM5120_GPIO_PIN2; |
||
78 | break; |
||
79 | case ADM5120_IRQ_GPIO4: |
||
80 | ret = ADM5120_GPIO_PIN4; |
||
81 | break; |
||
82 | default: |
||
83 | ret = -EINVAL; |
||
84 | break; |
||
85 | } |
||
86 | |||
87 | return ret; |
||
88 | } |
||
89 | EXPORT_SYMBOL(adm5120_irq_to_gpio); |
||
90 | |||
91 | /* |
||
92 | * Helpers for GPIO lines in GPIO_CONF0 register |
||
93 | */ |
||
94 | #define PIN_IM(p) ((1 << GPIO_CONF0_IM_SHIFT) << p) |
||
95 | #define PIN_IV(p) ((1 << GPIO_CONF0_IV_SHIFT) << p) |
||
96 | #define PIN_OE(p) ((1 << GPIO_CONF0_OE_SHIFT) << p) |
||
97 | #define PIN_OV(p) ((1 << GPIO_CONF0_OV_SHIFT) << p) |
||
98 | |||
99 | int __adm5120_gpio0_get_value(unsigned offset) |
||
100 | { |
||
101 | void __iomem **reg; |
||
102 | u32 t; |
||
103 | |||
104 | reg = GPIO_REG(SWITCH_REG_GPIO_CONF0); |
||
105 | |||
106 | t = __raw_readl(reg); |
||
107 | if ((t & PIN_IM(offset)) != 0) |
||
108 | t &= PIN_IV(offset); |
||
109 | else |
||
110 | t &= PIN_OV(offset); |
||
111 | |||
112 | return (t) ? 1 : 0; |
||
113 | } |
||
114 | EXPORT_SYMBOL(__adm5120_gpio0_get_value); |
||
115 | |||
116 | void __adm5120_gpio0_set_value(unsigned offset, int value) |
||
117 | { |
||
118 | void __iomem **reg; |
||
119 | u32 t; |
||
120 | |||
121 | reg = GPIO_REG(SWITCH_REG_GPIO_CONF0); |
||
122 | |||
123 | t = __raw_readl(reg); |
||
124 | if (value == 0) |
||
125 | t &= ~(PIN_OV(offset)); |
||
126 | else |
||
127 | t |= PIN_OV(offset); |
||
128 | |||
129 | __raw_writel(t, reg); |
||
130 | } |
||
131 | EXPORT_SYMBOL(__adm5120_gpio0_set_value); |
||
132 | |||
133 | static int adm5120_gpio0_get_value(struct gpio_chip *chip, unsigned offset) |
||
134 | { |
||
135 | return __adm5120_gpio0_get_value(offset); |
||
136 | } |
||
137 | |||
138 | static void adm5120_gpio0_set_value(struct gpio_chip *chip, |
||
139 | unsigned offset, int value) |
||
140 | { |
||
141 | __adm5120_gpio0_set_value(offset, value); |
||
142 | } |
||
143 | |||
144 | static int adm5120_gpio0_direction_input(struct gpio_chip *chip, |
||
145 | unsigned offset) |
||
146 | { |
||
147 | void __iomem **reg; |
||
148 | u32 t; |
||
149 | |||
150 | reg = GPIO_REG(SWITCH_REG_GPIO_CONF0); |
||
151 | |||
152 | t = __raw_readl(reg); |
||
153 | t &= ~(PIN_OE(offset)); |
||
154 | t |= PIN_IM(offset); |
||
155 | __raw_writel(t, reg); |
||
156 | |||
157 | return 0; |
||
158 | } |
||
159 | |||
160 | static int adm5120_gpio0_direction_output(struct gpio_chip *chip, |
||
161 | unsigned offset, int value) |
||
162 | { |
||
163 | void __iomem **reg; |
||
164 | u32 t; |
||
165 | |||
166 | reg = GPIO_REG(SWITCH_REG_GPIO_CONF0); |
||
167 | |||
168 | t = __raw_readl(reg); |
||
169 | t &= ~(PIN_IM(offset) | PIN_OV(offset)); |
||
170 | t |= PIN_OE(offset); |
||
171 | |||
172 | if (value) |
||
173 | t |= PIN_OV(offset); |
||
174 | |||
175 | __raw_writel(t, reg); |
||
176 | |||
177 | return 0; |
||
178 | } |
||
179 | |||
180 | static struct gpio_chip adm5120_gpio0_chip = { |
||
181 | .label = "adm5120 gpio0", |
||
182 | .get = adm5120_gpio0_get_value, |
||
183 | .set = adm5120_gpio0_set_value, |
||
184 | .direction_input = adm5120_gpio0_direction_input, |
||
185 | .direction_output = adm5120_gpio0_direction_output, |
||
186 | .base = ADM5120_GPIO_PIN0, |
||
187 | .ngpio = ADM5120_GPIO_PIN7 - ADM5120_GPIO_PIN0 + 1, |
||
188 | }; |
||
189 | |||
190 | int __adm5120_gpio1_get_value(unsigned offset) |
||
191 | { |
||
192 | void __iomem **reg; |
||
193 | u32 t, m; |
||
194 | |||
195 | reg = gpio1_table[offset].reg; |
||
196 | |||
197 | t = __raw_readl(reg); |
||
198 | m = (t >> gpio1_table[offset].mode_shift) & LED_MODE_MASK; |
||
199 | if (m == LED_MODE_INPUT) |
||
200 | return (t >> gpio1_table[offset].iv_shift) & 1; |
||
201 | |||
202 | if (m == LED_MODE_OUT_LOW) |
||
203 | return 0; |
||
204 | |||
205 | return 1; |
||
206 | } |
||
207 | EXPORT_SYMBOL(__adm5120_gpio1_get_value); |
||
208 | |||
209 | void __adm5120_gpio1_set_value(unsigned offset, int value) |
||
210 | { |
||
211 | void __iomem **reg; |
||
212 | u32 t, s; |
||
213 | |||
214 | reg = gpio1_table[offset].reg; |
||
215 | s = gpio1_table[offset].mode_shift; |
||
216 | |||
217 | t = __raw_readl(reg); |
||
218 | t &= ~(LED_MODE_MASK << s); |
||
219 | |||
220 | switch (value) { |
||
221 | case ADM5120_GPIO_LOW: |
||
222 | t |= (LED_MODE_OUT_LOW << s); |
||
223 | break; |
||
224 | case ADM5120_GPIO_FLASH: |
||
225 | case ADM5120_GPIO_LINK: |
||
226 | case ADM5120_GPIO_SPEED: |
||
227 | case ADM5120_GPIO_DUPLEX: |
||
228 | case ADM5120_GPIO_ACT: |
||
229 | case ADM5120_GPIO_COLL: |
||
230 | case ADM5120_GPIO_LINK_ACT: |
||
231 | case ADM5120_GPIO_DUPLEX_COLL: |
||
232 | case ADM5120_GPIO_10M_ACT: |
||
233 | case ADM5120_GPIO_100M_ACT: |
||
234 | t |= ((value & LED_MODE_MASK) << s); |
||
235 | break; |
||
236 | default: |
||
237 | t |= (LED_MODE_OUT_HIGH << s); |
||
238 | break; |
||
239 | } |
||
240 | |||
241 | __raw_writel(t, reg); |
||
242 | } |
||
243 | EXPORT_SYMBOL(__adm5120_gpio1_set_value); |
||
244 | |||
245 | static int adm5120_gpio1_get_value(struct gpio_chip *chip, unsigned offset) |
||
246 | { |
||
247 | return __adm5120_gpio1_get_value(offset); |
||
248 | } |
||
249 | |||
250 | static void adm5120_gpio1_set_value(struct gpio_chip *chip, |
||
251 | unsigned offset, int value) |
||
252 | { |
||
253 | __adm5120_gpio1_set_value(offset, value); |
||
254 | } |
||
255 | |||
256 | static int adm5120_gpio1_direction_input(struct gpio_chip *chip, |
||
257 | unsigned offset) |
||
258 | { |
||
259 | void __iomem **reg; |
||
260 | u32 t; |
||
261 | |||
262 | reg = gpio1_table[offset].reg; |
||
263 | t = __raw_readl(reg); |
||
264 | t &= ~(LED_MODE_MASK << gpio1_table[offset].mode_shift); |
||
265 | __raw_writel(t, reg); |
||
266 | |||
267 | return 0; |
||
268 | } |
||
269 | |||
270 | static int adm5120_gpio1_direction_output(struct gpio_chip *chip, |
||
271 | unsigned offset, int value) |
||
272 | { |
||
273 | __adm5120_gpio1_set_value(offset, value); |
||
274 | return 0; |
||
275 | } |
||
276 | |||
277 | static struct gpio_chip adm5120_gpio1_chip = { |
||
278 | .label = "adm5120 gpio1", |
||
279 | .get = adm5120_gpio1_get_value, |
||
280 | .set = adm5120_gpio1_set_value, |
||
281 | .direction_input = adm5120_gpio1_direction_input, |
||
282 | .direction_output = adm5120_gpio1_direction_output, |
||
283 | .base = ADM5120_GPIO_P0L0, |
||
284 | .ngpio = ADM5120_GPIO_P4L2 - ADM5120_GPIO_P0L0 + 1, |
||
285 | }; |
||
286 | |||
287 | void __init adm5120_gpio_csx0_enable(void) |
||
288 | { |
||
289 | gpio_conf2 |= GPIO_CONF2_CSX0; |
||
290 | SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, gpio_conf2); |
||
291 | |||
292 | gpio_request(ADM5120_GPIO_PIN1, "CSX0"); |
||
293 | } |
||
294 | |||
295 | void __init adm5120_gpio_csx1_enable(void) |
||
296 | { |
||
297 | gpio_conf2 |= GPIO_CONF2_CSX1; |
||
298 | SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, gpio_conf2); |
||
299 | |||
300 | gpio_request(ADM5120_GPIO_PIN3, "CSX1"); |
||
301 | } |
||
302 | |||
303 | void __init adm5120_gpio_ew_enable(void) |
||
304 | { |
||
305 | gpio_conf2 |= GPIO_CONF2_EW; |
||
306 | SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, gpio_conf2); |
||
307 | |||
308 | gpio_request(ADM5120_GPIO_PIN0, "EW"); |
||
309 | } |
||
310 | |||
311 | void __init adm5120_gpio_init(void) |
||
312 | { |
||
313 | int err; |
||
314 | |||
315 | SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, gpio_conf2); |
||
316 | |||
317 | if (adm5120_package_pqfp()) |
||
318 | adm5120_gpio0_chip.ngpio = 4; |
||
319 | |||
320 | err = gpiochip_add(&adm5120_gpio0_chip); |
||
321 | if (err) |
||
322 | panic("cannot add ADM5120 GPIO0 chip, error=%d", err); |
||
323 | |||
324 | err = gpiochip_add(&adm5120_gpio1_chip); |
||
325 | if (err) |
||
326 | panic("cannot add ADM5120 GPIO1 chip, error=%d", err); |
||
327 | |||
328 | } |