Commit | Line | Data |
---|---|---|
2ec1d359 AR |
1 | /* |
2 | * Generic GPIO driver for logic cells found in the Nomadik SoC | |
3 | * | |
4 | * Copyright (C) 2008,2009 STMicroelectronics | |
5 | * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> | |
6 | * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | #include <linux/kernel.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/init.h> | |
15 | #include <linux/device.h> | |
3e3c62ca | 16 | #include <linux/platform_device.h> |
2ec1d359 | 17 | #include <linux/io.h> |
af7dc228 RV |
18 | #include <linux/clk.h> |
19 | #include <linux/err.h> | |
2ec1d359 AR |
20 | #include <linux/gpio.h> |
21 | #include <linux/spinlock.h> | |
22 | #include <linux/interrupt.h> | |
23 | #include <linux/irq.h> | |
5a0e3ad6 | 24 | #include <linux/slab.h> |
2ec1d359 | 25 | |
378be066 | 26 | #include <plat/pincfg.h> |
2ec1d359 AR |
27 | #include <mach/hardware.h> |
28 | #include <mach/gpio.h> | |
29 | ||
30 | /* | |
31 | * The GPIO module in the Nomadik family of Systems-on-Chip is an | |
32 | * AMBA device, managing 32 pins and alternate functions. The logic block | |
33 | * is currently only used in the Nomadik. | |
34 | * | |
35 | * Symbols in this file are called "nmk_gpio" for "nomadik gpio" | |
36 | */ | |
37 | ||
38 | #define NMK_GPIO_PER_CHIP 32 | |
39 | struct nmk_gpio_chip { | |
40 | struct gpio_chip chip; | |
41 | void __iomem *addr; | |
af7dc228 | 42 | struct clk *clk; |
2ec1d359 | 43 | unsigned int parent_irq; |
c0fcb8db | 44 | spinlock_t lock; |
2ec1d359 AR |
45 | /* Keep track of configured edges */ |
46 | u32 edge_rising; | |
47 | u32 edge_falling; | |
48 | }; | |
49 | ||
6f9a974c RV |
50 | static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip, |
51 | unsigned offset, int gpio_mode) | |
52 | { | |
53 | u32 bit = 1 << offset; | |
54 | u32 afunc, bfunc; | |
55 | ||
56 | afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit; | |
57 | bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit; | |
58 | if (gpio_mode & NMK_GPIO_ALT_A) | |
59 | afunc |= bit; | |
60 | if (gpio_mode & NMK_GPIO_ALT_B) | |
61 | bfunc |= bit; | |
62 | writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA); | |
63 | writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB); | |
64 | } | |
65 | ||
81a3c298 RV |
66 | static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip, |
67 | unsigned offset, enum nmk_gpio_slpm mode) | |
68 | { | |
69 | u32 bit = 1 << offset; | |
70 | u32 slpm; | |
71 | ||
72 | slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC); | |
73 | if (mode == NMK_GPIO_SLPM_NOCHANGE) | |
74 | slpm |= bit; | |
75 | else | |
76 | slpm &= ~bit; | |
77 | writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC); | |
78 | } | |
79 | ||
5b327edf RV |
80 | static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip, |
81 | unsigned offset, enum nmk_gpio_pull pull) | |
82 | { | |
83 | u32 bit = 1 << offset; | |
84 | u32 pdis; | |
85 | ||
86 | pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS); | |
87 | if (pull == NMK_GPIO_PULL_NONE) | |
88 | pdis |= bit; | |
89 | else | |
90 | pdis &= ~bit; | |
91 | writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS); | |
92 | ||
93 | if (pull == NMK_GPIO_PULL_UP) | |
94 | writel(bit, nmk_chip->addr + NMK_GPIO_DATS); | |
95 | else if (pull == NMK_GPIO_PULL_DOWN) | |
96 | writel(bit, nmk_chip->addr + NMK_GPIO_DATC); | |
97 | } | |
98 | ||
378be066 RV |
99 | static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip, |
100 | unsigned offset) | |
101 | { | |
102 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC); | |
103 | } | |
104 | ||
105 | static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, | |
106 | pin_cfg_t cfg) | |
107 | { | |
108 | static const char *afnames[] = { | |
109 | [NMK_GPIO_ALT_GPIO] = "GPIO", | |
110 | [NMK_GPIO_ALT_A] = "A", | |
111 | [NMK_GPIO_ALT_B] = "B", | |
112 | [NMK_GPIO_ALT_C] = "C" | |
113 | }; | |
114 | static const char *pullnames[] = { | |
115 | [NMK_GPIO_PULL_NONE] = "none", | |
116 | [NMK_GPIO_PULL_UP] = "up", | |
117 | [NMK_GPIO_PULL_DOWN] = "down", | |
118 | [3] /* illegal */ = "??" | |
119 | }; | |
120 | static const char *slpmnames[] = { | |
121 | [NMK_GPIO_SLPM_INPUT] = "input", | |
122 | [NMK_GPIO_SLPM_NOCHANGE] = "no-change", | |
123 | }; | |
124 | ||
125 | int pin = PIN_NUM(cfg); | |
126 | int pull = PIN_PULL(cfg); | |
127 | int af = PIN_ALT(cfg); | |
128 | int slpm = PIN_SLPM(cfg); | |
129 | ||
130 | dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s\n", | |
131 | pin, afnames[af], pullnames[pull], slpmnames[slpm]); | |
132 | ||
133 | __nmk_gpio_make_input(nmk_chip, offset); | |
134 | __nmk_gpio_set_pull(nmk_chip, offset, pull); | |
135 | __nmk_gpio_set_slpm(nmk_chip, offset, slpm); | |
136 | __nmk_gpio_set_mode(nmk_chip, offset, af); | |
137 | } | |
138 | ||
139 | /** | |
140 | * nmk_config_pin - configure a pin's mux attributes | |
141 | * @cfg: pin confguration | |
142 | * | |
143 | * Configures a pin's mode (alternate function or GPIO), its pull up status, | |
144 | * and its sleep mode based on the specified configuration. The @cfg is | |
145 | * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These | |
146 | * are constructed using, and can be further enhanced with, the macros in | |
147 | * plat/pincfg.h. | |
148 | * | |
149 | * If a pin's mode is set to GPIO, it is configured as an input to avoid | |
150 | * side-effects. The gpio can be manipulated later using standard GPIO API | |
151 | * calls. | |
152 | */ | |
153 | int nmk_config_pin(pin_cfg_t cfg) | |
154 | { | |
155 | struct nmk_gpio_chip *nmk_chip; | |
156 | int gpio = PIN_NUM(cfg); | |
157 | unsigned long flags; | |
158 | ||
159 | nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | |
160 | if (!nmk_chip) | |
161 | return -EINVAL; | |
162 | ||
163 | spin_lock_irqsave(&nmk_chip->lock, flags); | |
164 | __nmk_config_pin(nmk_chip, gpio - nmk_chip->chip.base, cfg); | |
165 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | |
166 | ||
167 | return 0; | |
168 | } | |
169 | EXPORT_SYMBOL(nmk_config_pin); | |
170 | ||
171 | /** | |
172 | * nmk_config_pins - configure several pins at once | |
173 | * @cfgs: array of pin configurations | |
174 | * @num: number of elments in the array | |
175 | * | |
176 | * Configures several pins using nmk_config_pin(). Refer to that function for | |
177 | * further information. | |
178 | */ | |
179 | int nmk_config_pins(pin_cfg_t *cfgs, int num) | |
180 | { | |
181 | int ret = 0; | |
182 | int i; | |
183 | ||
184 | for (i = 0; i < num; i++) { | |
185 | int ret = nmk_config_pin(cfgs[i]); | |
186 | if (ret) | |
187 | break; | |
188 | } | |
189 | ||
190 | return ret; | |
191 | } | |
192 | EXPORT_SYMBOL(nmk_config_pins); | |
193 | ||
81a3c298 RV |
194 | /** |
195 | * nmk_gpio_set_slpm() - configure the sleep mode of a pin | |
196 | * @gpio: pin number | |
197 | * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE, | |
198 | * | |
199 | * Sets the sleep mode of a pin. If @mode is NMK_GPIO_SLPM_INPUT, the pin is | |
200 | * changed to an input (with pullup/down enabled) in sleep and deep sleep. If | |
201 | * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was | |
202 | * configured even when in sleep and deep sleep. | |
203 | */ | |
204 | int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode) | |
205 | { | |
206 | struct nmk_gpio_chip *nmk_chip; | |
207 | unsigned long flags; | |
208 | ||
209 | nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | |
210 | if (!nmk_chip) | |
211 | return -EINVAL; | |
212 | ||
213 | spin_lock_irqsave(&nmk_chip->lock, flags); | |
214 | __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode); | |
215 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | |
216 | ||
217 | return 0; | |
218 | } | |
219 | ||
5b327edf RV |
220 | /** |
221 | * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio | |
222 | * @gpio: pin number | |
223 | * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE | |
224 | * | |
225 | * Enables/disables pull up/down on a specified pin. This only takes effect if | |
226 | * the pin is configured as an input (either explicitly or by the alternate | |
227 | * function). | |
228 | * | |
229 | * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is | |
230 | * configured as an input. Otherwise, due to the way the controller registers | |
231 | * work, this function will change the value output on the pin. | |
232 | */ | |
233 | int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull) | |
234 | { | |
235 | struct nmk_gpio_chip *nmk_chip; | |
236 | unsigned long flags; | |
237 | ||
238 | nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | |
239 | if (!nmk_chip) | |
240 | return -EINVAL; | |
241 | ||
242 | spin_lock_irqsave(&nmk_chip->lock, flags); | |
243 | __nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull); | |
244 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | |
245 | ||
246 | return 0; | |
247 | } | |
248 | ||
2ec1d359 AR |
249 | /* Mode functions */ |
250 | int nmk_gpio_set_mode(int gpio, int gpio_mode) | |
251 | { | |
252 | struct nmk_gpio_chip *nmk_chip; | |
253 | unsigned long flags; | |
2ec1d359 AR |
254 | |
255 | nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | |
256 | if (!nmk_chip) | |
257 | return -EINVAL; | |
258 | ||
2ec1d359 | 259 | spin_lock_irqsave(&nmk_chip->lock, flags); |
6f9a974c | 260 | __nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode); |
2ec1d359 AR |
261 | spin_unlock_irqrestore(&nmk_chip->lock, flags); |
262 | ||
263 | return 0; | |
264 | } | |
265 | EXPORT_SYMBOL(nmk_gpio_set_mode); | |
266 | ||
267 | int nmk_gpio_get_mode(int gpio) | |
268 | { | |
269 | struct nmk_gpio_chip *nmk_chip; | |
270 | u32 afunc, bfunc, bit; | |
271 | ||
272 | nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | |
273 | if (!nmk_chip) | |
274 | return -EINVAL; | |
275 | ||
276 | bit = 1 << (gpio - nmk_chip->chip.base); | |
277 | ||
278 | afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit; | |
279 | bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit; | |
280 | ||
281 | return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0); | |
282 | } | |
283 | EXPORT_SYMBOL(nmk_gpio_get_mode); | |
284 | ||
285 | ||
286 | /* IRQ functions */ | |
287 | static inline int nmk_gpio_get_bitmask(int gpio) | |
288 | { | |
289 | return 1 << (gpio % 32); | |
290 | } | |
291 | ||
292 | static void nmk_gpio_irq_ack(unsigned int irq) | |
293 | { | |
294 | int gpio; | |
295 | struct nmk_gpio_chip *nmk_chip; | |
296 | ||
297 | gpio = NOMADIK_IRQ_TO_GPIO(irq); | |
298 | nmk_chip = get_irq_chip_data(irq); | |
299 | if (!nmk_chip) | |
300 | return; | |
301 | writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC); | |
302 | } | |
303 | ||
040e5ecd RV |
304 | static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip, |
305 | int gpio, bool enable) | |
2ec1d359 | 306 | { |
040e5ecd RV |
307 | u32 bitmask = nmk_gpio_get_bitmask(gpio); |
308 | u32 reg; | |
2ec1d359 | 309 | |
040e5ecd | 310 | /* we must individually set/clear the two edges */ |
2ec1d359 | 311 | if (nmk_chip->edge_rising & bitmask) { |
6b07aaed | 312 | reg = readl(nmk_chip->addr + NMK_GPIO_RIMSC); |
040e5ecd RV |
313 | if (enable) |
314 | reg |= bitmask; | |
315 | else | |
316 | reg &= ~bitmask; | |
6b07aaed | 317 | writel(reg, nmk_chip->addr + NMK_GPIO_RIMSC); |
2ec1d359 AR |
318 | } |
319 | if (nmk_chip->edge_falling & bitmask) { | |
6b07aaed | 320 | reg = readl(nmk_chip->addr + NMK_GPIO_FIMSC); |
040e5ecd RV |
321 | if (enable) |
322 | reg |= bitmask; | |
323 | else | |
324 | reg &= ~bitmask; | |
6b07aaed | 325 | writel(reg, nmk_chip->addr + NMK_GPIO_FIMSC); |
2ec1d359 | 326 | } |
040e5ecd | 327 | } |
2ec1d359 | 328 | |
040e5ecd | 329 | static void nmk_gpio_irq_modify(unsigned int irq, bool enable) |
2ec1d359 AR |
330 | { |
331 | int gpio; | |
332 | struct nmk_gpio_chip *nmk_chip; | |
333 | unsigned long flags; | |
040e5ecd | 334 | u32 bitmask; |
2ec1d359 AR |
335 | |
336 | gpio = NOMADIK_IRQ_TO_GPIO(irq); | |
337 | nmk_chip = get_irq_chip_data(irq); | |
338 | bitmask = nmk_gpio_get_bitmask(gpio); | |
339 | if (!nmk_chip) | |
340 | return; | |
341 | ||
2ec1d359 | 342 | spin_lock_irqsave(&nmk_chip->lock, flags); |
040e5ecd | 343 | __nmk_gpio_irq_modify(nmk_chip, gpio, enable); |
2ec1d359 AR |
344 | spin_unlock_irqrestore(&nmk_chip->lock, flags); |
345 | } | |
346 | ||
040e5ecd RV |
347 | static void nmk_gpio_irq_mask(unsigned int irq) |
348 | { | |
349 | nmk_gpio_irq_modify(irq, false); | |
350 | }; | |
351 | ||
352 | static void nmk_gpio_irq_unmask(unsigned int irq) | |
353 | { | |
354 | nmk_gpio_irq_modify(irq, true); | |
355 | } | |
356 | ||
2ec1d359 AR |
357 | static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type) |
358 | { | |
7a852d80 | 359 | bool enabled = !(irq_to_desc(irq)->status & IRQ_DISABLED); |
2ec1d359 AR |
360 | int gpio; |
361 | struct nmk_gpio_chip *nmk_chip; | |
362 | unsigned long flags; | |
363 | u32 bitmask; | |
364 | ||
365 | gpio = NOMADIK_IRQ_TO_GPIO(irq); | |
366 | nmk_chip = get_irq_chip_data(irq); | |
367 | bitmask = nmk_gpio_get_bitmask(gpio); | |
368 | if (!nmk_chip) | |
369 | return -EINVAL; | |
370 | ||
371 | if (type & IRQ_TYPE_LEVEL_HIGH) | |
372 | return -EINVAL; | |
373 | if (type & IRQ_TYPE_LEVEL_LOW) | |
374 | return -EINVAL; | |
375 | ||
376 | spin_lock_irqsave(&nmk_chip->lock, flags); | |
377 | ||
7a852d80 RV |
378 | if (enabled) |
379 | __nmk_gpio_irq_modify(nmk_chip, gpio, false); | |
380 | ||
2ec1d359 AR |
381 | nmk_chip->edge_rising &= ~bitmask; |
382 | if (type & IRQ_TYPE_EDGE_RISING) | |
383 | nmk_chip->edge_rising |= bitmask; | |
2ec1d359 AR |
384 | |
385 | nmk_chip->edge_falling &= ~bitmask; | |
386 | if (type & IRQ_TYPE_EDGE_FALLING) | |
387 | nmk_chip->edge_falling |= bitmask; | |
2ec1d359 | 388 | |
7a852d80 RV |
389 | if (enabled) |
390 | __nmk_gpio_irq_modify(nmk_chip, gpio, true); | |
2ec1d359 | 391 | |
7a852d80 | 392 | spin_unlock_irqrestore(&nmk_chip->lock, flags); |
2ec1d359 AR |
393 | |
394 | return 0; | |
395 | } | |
396 | ||
397 | static struct irq_chip nmk_gpio_irq_chip = { | |
398 | .name = "Nomadik-GPIO", | |
399 | .ack = nmk_gpio_irq_ack, | |
400 | .mask = nmk_gpio_irq_mask, | |
401 | .unmask = nmk_gpio_irq_unmask, | |
402 | .set_type = nmk_gpio_irq_set_type, | |
403 | }; | |
404 | ||
405 | static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | |
406 | { | |
407 | struct nmk_gpio_chip *nmk_chip; | |
aaedaa2b | 408 | struct irq_chip *host_chip = get_irq_chip(irq); |
2ec1d359 AR |
409 | unsigned int gpio_irq; |
410 | u32 pending; | |
411 | unsigned int first_irq; | |
412 | ||
aaedaa2b RV |
413 | if (host_chip->mask_ack) |
414 | host_chip->mask_ack(irq); | |
415 | else { | |
416 | host_chip->mask(irq); | |
417 | if (host_chip->ack) | |
418 | host_chip->ack(irq); | |
419 | } | |
420 | ||
2ec1d359 AR |
421 | nmk_chip = get_irq_data(irq); |
422 | first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base); | |
423 | while ( (pending = readl(nmk_chip->addr + NMK_GPIO_IS)) ) { | |
424 | gpio_irq = first_irq + __ffs(pending); | |
425 | generic_handle_irq(gpio_irq); | |
426 | } | |
aaedaa2b RV |
427 | |
428 | host_chip->unmask(irq); | |
2ec1d359 AR |
429 | } |
430 | ||
431 | static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip) | |
432 | { | |
433 | unsigned int first_irq; | |
434 | int i; | |
435 | ||
436 | first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base); | |
437 | for (i = first_irq; i < first_irq + NMK_GPIO_PER_CHIP; i++) { | |
438 | set_irq_chip(i, &nmk_gpio_irq_chip); | |
439 | set_irq_handler(i, handle_edge_irq); | |
440 | set_irq_flags(i, IRQF_VALID); | |
441 | set_irq_chip_data(i, nmk_chip); | |
2210d645 | 442 | set_irq_type(i, IRQ_TYPE_EDGE_FALLING); |
2ec1d359 AR |
443 | } |
444 | set_irq_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler); | |
445 | set_irq_data(nmk_chip->parent_irq, nmk_chip); | |
446 | return 0; | |
447 | } | |
448 | ||
449 | /* I/O Functions */ | |
450 | static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset) | |
451 | { | |
452 | struct nmk_gpio_chip *nmk_chip = | |
453 | container_of(chip, struct nmk_gpio_chip, chip); | |
454 | ||
455 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC); | |
456 | return 0; | |
457 | } | |
458 | ||
2ec1d359 AR |
459 | static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset) |
460 | { | |
461 | struct nmk_gpio_chip *nmk_chip = | |
462 | container_of(chip, struct nmk_gpio_chip, chip); | |
463 | u32 bit = 1 << offset; | |
464 | ||
465 | return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0; | |
466 | } | |
467 | ||
468 | static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset, | |
469 | int val) | |
470 | { | |
471 | struct nmk_gpio_chip *nmk_chip = | |
472 | container_of(chip, struct nmk_gpio_chip, chip); | |
473 | u32 bit = 1 << offset; | |
474 | ||
475 | if (val) | |
476 | writel(bit, nmk_chip->addr + NMK_GPIO_DATS); | |
477 | else | |
478 | writel(bit, nmk_chip->addr + NMK_GPIO_DATC); | |
479 | } | |
480 | ||
6647c6c0 RV |
481 | static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, |
482 | int val) | |
483 | { | |
484 | struct nmk_gpio_chip *nmk_chip = | |
485 | container_of(chip, struct nmk_gpio_chip, chip); | |
486 | ||
487 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS); | |
488 | nmk_gpio_set_output(chip, offset, val); | |
489 | ||
490 | return 0; | |
491 | } | |
492 | ||
2ec1d359 AR |
493 | /* This structure is replicated for each GPIO block allocated at probe time */ |
494 | static struct gpio_chip nmk_gpio_template = { | |
495 | .direction_input = nmk_gpio_make_input, | |
496 | .get = nmk_gpio_get_input, | |
497 | .direction_output = nmk_gpio_make_output, | |
498 | .set = nmk_gpio_set_output, | |
499 | .ngpio = NMK_GPIO_PER_CHIP, | |
500 | .can_sleep = 0, | |
501 | }; | |
502 | ||
3e3c62ca | 503 | static int __init nmk_gpio_probe(struct platform_device *dev) |
2ec1d359 | 504 | { |
3e3c62ca | 505 | struct nmk_gpio_platform_data *pdata = dev->dev.platform_data; |
2ec1d359 AR |
506 | struct nmk_gpio_chip *nmk_chip; |
507 | struct gpio_chip *chip; | |
3e3c62ca | 508 | struct resource *res; |
af7dc228 | 509 | struct clk *clk; |
3e3c62ca | 510 | int irq; |
2ec1d359 AR |
511 | int ret; |
512 | ||
3e3c62ca RV |
513 | if (!pdata) |
514 | return -ENODEV; | |
515 | ||
516 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | |
517 | if (!res) { | |
518 | ret = -ENOENT; | |
519 | goto out; | |
520 | } | |
521 | ||
522 | irq = platform_get_irq(dev, 0); | |
523 | if (irq < 0) { | |
524 | ret = irq; | |
525 | goto out; | |
526 | } | |
527 | ||
528 | if (request_mem_region(res->start, resource_size(res), | |
529 | dev_name(&dev->dev)) == NULL) { | |
530 | ret = -EBUSY; | |
531 | goto out; | |
532 | } | |
2ec1d359 | 533 | |
af7dc228 RV |
534 | clk = clk_get(&dev->dev, NULL); |
535 | if (IS_ERR(clk)) { | |
536 | ret = PTR_ERR(clk); | |
537 | goto out_release; | |
538 | } | |
539 | ||
540 | clk_enable(clk); | |
541 | ||
2ec1d359 AR |
542 | nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL); |
543 | if (!nmk_chip) { | |
544 | ret = -ENOMEM; | |
af7dc228 | 545 | goto out_clk; |
2ec1d359 AR |
546 | } |
547 | /* | |
548 | * The virt address in nmk_chip->addr is in the nomadik register space, | |
549 | * so we can simply convert the resource address, without remapping | |
550 | */ | |
af7dc228 | 551 | nmk_chip->clk = clk; |
3e3c62ca | 552 | nmk_chip->addr = io_p2v(res->start); |
2ec1d359 | 553 | nmk_chip->chip = nmk_gpio_template; |
3e3c62ca | 554 | nmk_chip->parent_irq = irq; |
c0fcb8db | 555 | spin_lock_init(&nmk_chip->lock); |
2ec1d359 AR |
556 | |
557 | chip = &nmk_chip->chip; | |
558 | chip->base = pdata->first_gpio; | |
559 | chip->label = pdata->name; | |
560 | chip->dev = &dev->dev; | |
561 | chip->owner = THIS_MODULE; | |
562 | ||
563 | ret = gpiochip_add(&nmk_chip->chip); | |
564 | if (ret) | |
565 | goto out_free; | |
566 | ||
3e3c62ca | 567 | platform_set_drvdata(dev, nmk_chip); |
2ec1d359 AR |
568 | |
569 | nmk_gpio_init_irq(nmk_chip); | |
570 | ||
571 | dev_info(&dev->dev, "Bits %i-%i at address %p\n", | |
572 | nmk_chip->chip.base, nmk_chip->chip.base+31, nmk_chip->addr); | |
573 | return 0; | |
574 | ||
3e3c62ca | 575 | out_free: |
2ec1d359 | 576 | kfree(nmk_chip); |
af7dc228 RV |
577 | out_clk: |
578 | clk_disable(clk); | |
579 | clk_put(clk); | |
3e3c62ca RV |
580 | out_release: |
581 | release_mem_region(res->start, resource_size(res)); | |
582 | out: | |
2ec1d359 AR |
583 | dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret, |
584 | pdata->first_gpio, pdata->first_gpio+31); | |
585 | return ret; | |
586 | } | |
587 | ||
3e3c62ca | 588 | static int __exit nmk_gpio_remove(struct platform_device *dev) |
2ec1d359 AR |
589 | { |
590 | struct nmk_gpio_chip *nmk_chip; | |
3e3c62ca RV |
591 | struct resource *res; |
592 | ||
593 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | |
2ec1d359 | 594 | |
3e3c62ca | 595 | nmk_chip = platform_get_drvdata(dev); |
2ec1d359 | 596 | gpiochip_remove(&nmk_chip->chip); |
af7dc228 RV |
597 | clk_disable(nmk_chip->clk); |
598 | clk_put(nmk_chip->clk); | |
2ec1d359 | 599 | kfree(nmk_chip); |
3e3c62ca | 600 | release_mem_region(res->start, resource_size(res)); |
2ec1d359 AR |
601 | return 0; |
602 | } | |
603 | ||
604 | ||
3e3c62ca RV |
605 | static struct platform_driver nmk_gpio_driver = { |
606 | .driver = { | |
2ec1d359 AR |
607 | .owner = THIS_MODULE, |
608 | .name = "gpio", | |
609 | }, | |
610 | .probe = nmk_gpio_probe, | |
3e3c62ca | 611 | .remove = __exit_p(nmk_gpio_remove), |
2ec1d359 AR |
612 | .suspend = NULL, /* to be done */ |
613 | .resume = NULL, | |
2ec1d359 AR |
614 | }; |
615 | ||
616 | static int __init nmk_gpio_init(void) | |
617 | { | |
3e3c62ca | 618 | return platform_driver_register(&nmk_gpio_driver); |
2ec1d359 AR |
619 | } |
620 | ||
621 | arch_initcall(nmk_gpio_init); | |
622 | ||
623 | MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini"); | |
624 | MODULE_DESCRIPTION("Nomadik GPIO Driver"); | |
625 | MODULE_LICENSE("GPL"); | |
626 | ||
627 |