blob: 5b5fd1ee3c044510e473d80ec77885f494a5a40a [file] [log] [blame]
Alessandro Rubini2ec1d352009-07-02 15:29:12 +01001/*
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>
Rabin Vincent3e3c62c2010-03-03 04:52:34 +010016#include <linux/platform_device.h>
Alessandro Rubini2ec1d352009-07-02 15:29:12 +010017#include <linux/io.h>
Rabin Vincentaf7dc222010-05-06 11:14:17 +010018#include <linux/clk.h>
19#include <linux/err.h>
Alessandro Rubini2ec1d352009-07-02 15:29:12 +010020#include <linux/gpio.h>
21#include <linux/spinlock.h>
22#include <linux/interrupt.h>
23#include <linux/irq.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090024#include <linux/slab.h>
Alessandro Rubini2ec1d352009-07-02 15:29:12 +010025
Rabin Vincent378be062010-06-02 06:06:29 +010026#include <plat/pincfg.h>
Alessandro Rubini2ec1d352009-07-02 15:29:12 +010027#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
Alessandro Rubini2ec1d352009-07-02 15:29:12 +010038struct nmk_gpio_chip {
39 struct gpio_chip chip;
40 void __iomem *addr;
Rabin Vincentaf7dc222010-05-06 11:14:17 +010041 struct clk *clk;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +010042 unsigned int parent_irq;
Rabin Vincentc0fcb8d2010-03-03 04:48:54 +010043 spinlock_t lock;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +010044 /* Keep track of configured edges */
45 u32 edge_rising;
46 u32 edge_falling;
47};
48
Rabin Vincent6f9a9742010-06-02 05:50:28 +010049static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip,
50 unsigned offset, int gpio_mode)
51{
52 u32 bit = 1 << offset;
53 u32 afunc, bfunc;
54
55 afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit;
56 bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit;
57 if (gpio_mode & NMK_GPIO_ALT_A)
58 afunc |= bit;
59 if (gpio_mode & NMK_GPIO_ALT_B)
60 bfunc |= bit;
61 writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA);
62 writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB);
63}
64
Rabin Vincent81a3c292010-05-27 12:39:23 +010065static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip,
66 unsigned offset, enum nmk_gpio_slpm mode)
67{
68 u32 bit = 1 << offset;
69 u32 slpm;
70
71 slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC);
72 if (mode == NMK_GPIO_SLPM_NOCHANGE)
73 slpm |= bit;
74 else
75 slpm &= ~bit;
76 writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC);
77}
78
Rabin Vincent5b327ed2010-05-27 12:29:50 +010079static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
80 unsigned offset, enum nmk_gpio_pull pull)
81{
82 u32 bit = 1 << offset;
83 u32 pdis;
84
85 pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS);
86 if (pull == NMK_GPIO_PULL_NONE)
87 pdis |= bit;
88 else
89 pdis &= ~bit;
90 writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS);
91
92 if (pull == NMK_GPIO_PULL_UP)
93 writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
94 else if (pull == NMK_GPIO_PULL_DOWN)
95 writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
96}
97
Rabin Vincent378be062010-06-02 06:06:29 +010098static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
99 unsigned offset)
100{
101 writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
102}
103
Rabin Vincent6720db72010-09-02 11:28:48 +0100104static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip,
105 unsigned offset, int val)
106{
107 if (val)
108 writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS);
109 else
110 writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC);
111}
112
113static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
114 unsigned offset, int val)
115{
116 writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
117 __nmk_gpio_set_output(nmk_chip, offset, val);
118}
119
Rabin Vincent378be062010-06-02 06:06:29 +0100120static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
Rabin Vincentdacdc962010-12-03 20:35:37 +0530121 pin_cfg_t cfg, bool sleep)
Rabin Vincent378be062010-06-02 06:06:29 +0100122{
123 static const char *afnames[] = {
124 [NMK_GPIO_ALT_GPIO] = "GPIO",
125 [NMK_GPIO_ALT_A] = "A",
126 [NMK_GPIO_ALT_B] = "B",
127 [NMK_GPIO_ALT_C] = "C"
128 };
129 static const char *pullnames[] = {
130 [NMK_GPIO_PULL_NONE] = "none",
131 [NMK_GPIO_PULL_UP] = "up",
132 [NMK_GPIO_PULL_DOWN] = "down",
133 [3] /* illegal */ = "??"
134 };
135 static const char *slpmnames[] = {
Rabin Vincent7e3f7e52010-09-02 11:28:05 +0100136 [NMK_GPIO_SLPM_INPUT] = "input/wakeup",
137 [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup",
Rabin Vincent378be062010-06-02 06:06:29 +0100138 };
139
140 int pin = PIN_NUM(cfg);
141 int pull = PIN_PULL(cfg);
142 int af = PIN_ALT(cfg);
143 int slpm = PIN_SLPM(cfg);
Rabin Vincent6720db72010-09-02 11:28:48 +0100144 int output = PIN_DIR(cfg);
145 int val = PIN_VAL(cfg);
Rabin Vincent378be062010-06-02 06:06:29 +0100146
Rabin Vincentdacdc962010-12-03 20:35:37 +0530147 dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n",
148 pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
Rabin Vincent6720db72010-09-02 11:28:48 +0100149 output ? "output " : "input",
150 output ? (val ? "high" : "low") : "");
Rabin Vincent378be062010-06-02 06:06:29 +0100151
Rabin Vincentdacdc962010-12-03 20:35:37 +0530152 if (sleep) {
153 int slpm_pull = PIN_SLPM_PULL(cfg);
154 int slpm_output = PIN_SLPM_DIR(cfg);
155 int slpm_val = PIN_SLPM_VAL(cfg);
156
157 /*
158 * The SLPM_* values are normal values + 1 to allow zero to
159 * mean "same as normal".
160 */
161 if (slpm_pull)
162 pull = slpm_pull - 1;
163 if (slpm_output)
164 output = slpm_output - 1;
165 if (slpm_val)
166 val = slpm_val - 1;
167
168 dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
169 pin,
170 slpm_pull ? pullnames[pull] : "same",
171 slpm_output ? (output ? "output" : "input") : "same",
172 slpm_val ? (val ? "high" : "low") : "same");
173 }
174
Rabin Vincent6720db72010-09-02 11:28:48 +0100175 if (output)
176 __nmk_gpio_make_output(nmk_chip, offset, val);
177 else {
178 __nmk_gpio_make_input(nmk_chip, offset);
179 __nmk_gpio_set_pull(nmk_chip, offset, pull);
180 }
181
Rabin Vincent378be062010-06-02 06:06:29 +0100182 __nmk_gpio_set_slpm(nmk_chip, offset, slpm);
183 __nmk_gpio_set_mode(nmk_chip, offset, af);
184}
185
186/**
187 * nmk_config_pin - configure a pin's mux attributes
188 * @cfg: pin confguration
189 *
190 * Configures a pin's mode (alternate function or GPIO), its pull up status,
191 * and its sleep mode based on the specified configuration. The @cfg is
192 * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These
193 * are constructed using, and can be further enhanced with, the macros in
194 * plat/pincfg.h.
195 *
196 * If a pin's mode is set to GPIO, it is configured as an input to avoid
197 * side-effects. The gpio can be manipulated later using standard GPIO API
198 * calls.
199 */
Rabin Vincentdacdc962010-12-03 20:35:37 +0530200int nmk_config_pin(pin_cfg_t cfg, bool sleep)
Rabin Vincent378be062010-06-02 06:06:29 +0100201{
202 struct nmk_gpio_chip *nmk_chip;
203 int gpio = PIN_NUM(cfg);
204 unsigned long flags;
205
206 nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
207 if (!nmk_chip)
208 return -EINVAL;
209
210 spin_lock_irqsave(&nmk_chip->lock, flags);
Rabin Vincentdacdc962010-12-03 20:35:37 +0530211 __nmk_config_pin(nmk_chip, gpio - nmk_chip->chip.base, cfg, sleep);
Rabin Vincent378be062010-06-02 06:06:29 +0100212 spin_unlock_irqrestore(&nmk_chip->lock, flags);
213
214 return 0;
215}
216EXPORT_SYMBOL(nmk_config_pin);
217
218/**
219 * nmk_config_pins - configure several pins at once
220 * @cfgs: array of pin configurations
221 * @num: number of elments in the array
222 *
223 * Configures several pins using nmk_config_pin(). Refer to that function for
224 * further information.
225 */
226int nmk_config_pins(pin_cfg_t *cfgs, int num)
227{
228 int ret = 0;
229 int i;
230
231 for (i = 0; i < num; i++) {
Rabin Vincentdacdc962010-12-03 20:35:37 +0530232 ret = nmk_config_pin(cfgs[i], false);
Rabin Vincent378be062010-06-02 06:06:29 +0100233 if (ret)
234 break;
235 }
236
237 return ret;
238}
239EXPORT_SYMBOL(nmk_config_pins);
240
Rabin Vincentdacdc962010-12-03 20:35:37 +0530241int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num)
242{
243 int ret = 0;
244 int i;
245
246 for (i = 0; i < num; i++) {
247 ret = nmk_config_pin(cfgs[i], true);
248 if (ret)
249 break;
250 }
251
252 return ret;
253}
254EXPORT_SYMBOL(nmk_config_pins_sleep);
255
Rabin Vincent5b327ed2010-05-27 12:29:50 +0100256/**
Rabin Vincent81a3c292010-05-27 12:39:23 +0100257 * nmk_gpio_set_slpm() - configure the sleep mode of a pin
258 * @gpio: pin number
259 * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE,
260 *
261 * Sets the sleep mode of a pin. If @mode is NMK_GPIO_SLPM_INPUT, the pin is
262 * changed to an input (with pullup/down enabled) in sleep and deep sleep. If
263 * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was
264 * configured even when in sleep and deep sleep.
Rabin Vincent7e3f7e52010-09-02 11:28:05 +0100265 *
266 * On DB8500v2 onwards, this setting loses the previous meaning and instead
267 * indicates if wakeup detection is enabled on the pin. Note that
268 * enable_irq_wake() will automatically enable wakeup detection.
Rabin Vincent81a3c292010-05-27 12:39:23 +0100269 */
270int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
271{
272 struct nmk_gpio_chip *nmk_chip;
273 unsigned long flags;
274
275 nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
276 if (!nmk_chip)
277 return -EINVAL;
278
279 spin_lock_irqsave(&nmk_chip->lock, flags);
280 __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode);
281 spin_unlock_irqrestore(&nmk_chip->lock, flags);
282
283 return 0;
284}
285
286/**
Rabin Vincent5b327ed2010-05-27 12:29:50 +0100287 * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio
288 * @gpio: pin number
289 * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE
290 *
291 * Enables/disables pull up/down on a specified pin. This only takes effect if
292 * the pin is configured as an input (either explicitly or by the alternate
293 * function).
294 *
295 * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
296 * configured as an input. Otherwise, due to the way the controller registers
297 * work, this function will change the value output on the pin.
298 */
299int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
300{
301 struct nmk_gpio_chip *nmk_chip;
302 unsigned long flags;
303
304 nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
305 if (!nmk_chip)
306 return -EINVAL;
307
308 spin_lock_irqsave(&nmk_chip->lock, flags);
309 __nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull);
310 spin_unlock_irqrestore(&nmk_chip->lock, flags);
311
312 return 0;
313}
314
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100315/* Mode functions */
316int nmk_gpio_set_mode(int gpio, int gpio_mode)
317{
318 struct nmk_gpio_chip *nmk_chip;
319 unsigned long flags;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100320
321 nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
322 if (!nmk_chip)
323 return -EINVAL;
324
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100325 spin_lock_irqsave(&nmk_chip->lock, flags);
Rabin Vincent6f9a9742010-06-02 05:50:28 +0100326 __nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100327 spin_unlock_irqrestore(&nmk_chip->lock, flags);
328
329 return 0;
330}
331EXPORT_SYMBOL(nmk_gpio_set_mode);
332
333int nmk_gpio_get_mode(int gpio)
334{
335 struct nmk_gpio_chip *nmk_chip;
336 u32 afunc, bfunc, bit;
337
338 nmk_chip = get_irq_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
339 if (!nmk_chip)
340 return -EINVAL;
341
342 bit = 1 << (gpio - nmk_chip->chip.base);
343
344 afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit;
345 bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit;
346
347 return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0);
348}
349EXPORT_SYMBOL(nmk_gpio_get_mode);
350
351
352/* IRQ functions */
353static inline int nmk_gpio_get_bitmask(int gpio)
354{
355 return 1 << (gpio % 32);
356}
357
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100358static void nmk_gpio_irq_ack(struct irq_data *d)
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100359{
360 int gpio;
361 struct nmk_gpio_chip *nmk_chip;
362
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100363 gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
364 nmk_chip = irq_data_get_irq_chip_data(d);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100365 if (!nmk_chip)
366 return;
367 writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
368}
369
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100370enum nmk_gpio_irq_type {
371 NORMAL,
372 WAKE,
373};
374
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100375static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100376 int gpio, enum nmk_gpio_irq_type which,
377 bool enable)
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100378{
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100379 u32 rimsc = which == WAKE ? NMK_GPIO_RWIMSC : NMK_GPIO_RIMSC;
380 u32 fimsc = which == WAKE ? NMK_GPIO_FWIMSC : NMK_GPIO_FIMSC;
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100381 u32 bitmask = nmk_gpio_get_bitmask(gpio);
382 u32 reg;
383
384 /* we must individually set/clear the two edges */
385 if (nmk_chip->edge_rising & bitmask) {
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100386 reg = readl(nmk_chip->addr + rimsc);
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100387 if (enable)
388 reg |= bitmask;
389 else
390 reg &= ~bitmask;
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100391 writel(reg, nmk_chip->addr + rimsc);
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100392 }
393 if (nmk_chip->edge_falling & bitmask) {
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100394 reg = readl(nmk_chip->addr + fimsc);
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100395 if (enable)
396 reg |= bitmask;
397 else
398 reg &= ~bitmask;
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100399 writel(reg, nmk_chip->addr + fimsc);
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100400 }
401}
402
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100403static int nmk_gpio_irq_modify(struct irq_data *d, enum nmk_gpio_irq_type which,
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100404 bool enable)
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100405{
406 int gpio;
407 struct nmk_gpio_chip *nmk_chip;
408 unsigned long flags;
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100409 u32 bitmask;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100410
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100411 gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
412 nmk_chip = irq_data_get_irq_chip_data(d);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100413 bitmask = nmk_gpio_get_bitmask(gpio);
414 if (!nmk_chip)
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100415 return -EINVAL;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100416
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100417 spin_lock_irqsave(&nmk_chip->lock, flags);
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100418 __nmk_gpio_irq_modify(nmk_chip, gpio, which, enable);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100419 spin_unlock_irqrestore(&nmk_chip->lock, flags);
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100420
421 return 0;
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100422}
423
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100424static void nmk_gpio_irq_mask(struct irq_data *d)
Rabin Vincent040e5ec2010-05-06 10:42:42 +0100425{
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100426 nmk_gpio_irq_modify(d, NORMAL, false);
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100427}
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100428
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100429static void nmk_gpio_irq_unmask(struct irq_data *d)
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100430{
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100431 nmk_gpio_irq_modify(d, NORMAL, true);
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100432}
433
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100434static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100435{
Rabin Vincent7e3f7e52010-09-02 11:28:05 +0100436 struct nmk_gpio_chip *nmk_chip;
437 unsigned long flags;
438 int gpio;
439
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100440 gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
441 nmk_chip = irq_data_get_irq_chip_data(d);
Rabin Vincent7e3f7e52010-09-02 11:28:05 +0100442 if (!nmk_chip)
443 return -EINVAL;
444
445 spin_lock_irqsave(&nmk_chip->lock, flags);
446#ifdef CONFIG_ARCH_U8500
447 if (cpu_is_u8500v2()) {
448 __nmk_gpio_set_slpm(nmk_chip, gpio,
449 on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
450 : NMK_GPIO_SLPM_WAKEUP_DISABLE);
451 }
452#endif
453 __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
454 spin_unlock_irqrestore(&nmk_chip->lock, flags);
455
456 return 0;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100457}
458
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100459static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100460{
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100461 struct irq_desc *desc = irq_to_desc(d->irq);
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100462 bool enabled = !(desc->status & IRQ_DISABLED);
463 bool wake = desc->wake_depth;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100464 int gpio;
465 struct nmk_gpio_chip *nmk_chip;
466 unsigned long flags;
467 u32 bitmask;
468
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100469 gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
470 nmk_chip = irq_data_get_irq_chip_data(d);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100471 bitmask = nmk_gpio_get_bitmask(gpio);
472 if (!nmk_chip)
473 return -EINVAL;
474
475 if (type & IRQ_TYPE_LEVEL_HIGH)
476 return -EINVAL;
477 if (type & IRQ_TYPE_LEVEL_LOW)
478 return -EINVAL;
479
480 spin_lock_irqsave(&nmk_chip->lock, flags);
481
Rabin Vincent7a852d82010-05-06 10:43:55 +0100482 if (enabled)
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100483 __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false);
484
485 if (wake)
486 __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false);
Rabin Vincent7a852d82010-05-06 10:43:55 +0100487
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100488 nmk_chip->edge_rising &= ~bitmask;
489 if (type & IRQ_TYPE_EDGE_RISING)
490 nmk_chip->edge_rising |= bitmask;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100491
492 nmk_chip->edge_falling &= ~bitmask;
493 if (type & IRQ_TYPE_EDGE_FALLING)
494 nmk_chip->edge_falling |= bitmask;
Rabin Vincent7a852d82010-05-06 10:43:55 +0100495
496 if (enabled)
Rabin Vincent4d4e20f2010-06-16 06:09:34 +0100497 __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true);
498
499 if (wake)
500 __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100501
502 spin_unlock_irqrestore(&nmk_chip->lock, flags);
503
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100504 return 0;
505}
506
507static struct irq_chip nmk_gpio_irq_chip = {
508 .name = "Nomadik-GPIO",
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100509 .irq_ack = nmk_gpio_irq_ack,
510 .irq_mask = nmk_gpio_irq_mask,
511 .irq_unmask = nmk_gpio_irq_unmask,
512 .irq_set_type = nmk_gpio_irq_set_type,
513 .irq_set_wake = nmk_gpio_irq_set_wake,
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100514};
515
516static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
517{
518 struct nmk_gpio_chip *nmk_chip;
Rabin Vincentaaedaa22010-03-03 04:50:27 +0100519 struct irq_chip *host_chip = get_irq_chip(irq);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100520 unsigned int gpio_irq;
521 u32 pending;
522 unsigned int first_irq;
523
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100524 if (host_chip->irq_mask_ack)
525 host_chip->irq_mask_ack(&desc->irq_data);
Rabin Vincentaaedaa22010-03-03 04:50:27 +0100526 else {
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100527 host_chip->irq_mask(&desc->irq_data);
528 if (host_chip->irq_ack)
529 host_chip->irq_ack(&desc->irq_data);
Rabin Vincentaaedaa22010-03-03 04:50:27 +0100530 }
531
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100532 nmk_chip = get_irq_data(irq);
533 first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
534 while ( (pending = readl(nmk_chip->addr + NMK_GPIO_IS)) ) {
535 gpio_irq = first_irq + __ffs(pending);
536 generic_handle_irq(gpio_irq);
537 }
Rabin Vincentaaedaa22010-03-03 04:50:27 +0100538
Lennert Buytenhekf272c002010-11-29 11:16:48 +0100539 host_chip->irq_unmask(&desc->irq_data);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100540}
541
542static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
543{
544 unsigned int first_irq;
545 int i;
546
547 first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
Rabin Vincente493e062010-03-18 12:35:22 +0530548 for (i = first_irq; i < first_irq + nmk_chip->chip.ngpio; i++) {
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100549 set_irq_chip(i, &nmk_gpio_irq_chip);
550 set_irq_handler(i, handle_edge_irq);
551 set_irq_flags(i, IRQF_VALID);
552 set_irq_chip_data(i, nmk_chip);
Rabin Vincent2210d642010-05-06 10:45:18 +0100553 set_irq_type(i, IRQ_TYPE_EDGE_FALLING);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100554 }
555 set_irq_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
556 set_irq_data(nmk_chip->parent_irq, nmk_chip);
557 return 0;
558}
559
560/* I/O Functions */
561static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
562{
563 struct nmk_gpio_chip *nmk_chip =
564 container_of(chip, struct nmk_gpio_chip, chip);
565
566 writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
567 return 0;
568}
569
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100570static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
571{
572 struct nmk_gpio_chip *nmk_chip =
573 container_of(chip, struct nmk_gpio_chip, chip);
574 u32 bit = 1 << offset;
575
576 return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
577}
578
579static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
580 int val)
581{
582 struct nmk_gpio_chip *nmk_chip =
583 container_of(chip, struct nmk_gpio_chip, chip);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100584
Rabin Vincent6720db72010-09-02 11:28:48 +0100585 __nmk_gpio_set_output(nmk_chip, offset, val);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100586}
587
Rabin Vincent6647c6c2010-05-27 12:22:42 +0100588static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
589 int val)
590{
591 struct nmk_gpio_chip *nmk_chip =
592 container_of(chip, struct nmk_gpio_chip, chip);
593
Rabin Vincent6720db72010-09-02 11:28:48 +0100594 __nmk_gpio_make_output(nmk_chip, offset, val);
Rabin Vincent6647c6c2010-05-27 12:22:42 +0100595
596 return 0;
597}
598
Rabin Vincent0d2aec92010-06-16 06:10:43 +0100599static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
600{
601 struct nmk_gpio_chip *nmk_chip =
602 container_of(chip, struct nmk_gpio_chip, chip);
603
604 return NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base) + offset;
605}
606
Rabin Vincentd0b543c2010-03-04 17:39:05 +0530607#ifdef CONFIG_DEBUG_FS
608
609#include <linux/seq_file.h>
610
611static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
612{
613 int mode;
614 unsigned i;
615 unsigned gpio = chip->base;
616 int is_out;
617 struct nmk_gpio_chip *nmk_chip =
618 container_of(chip, struct nmk_gpio_chip, chip);
619 const char *modes[] = {
620 [NMK_GPIO_ALT_GPIO] = "gpio",
621 [NMK_GPIO_ALT_A] = "altA",
622 [NMK_GPIO_ALT_B] = "altB",
623 [NMK_GPIO_ALT_C] = "altC",
624 };
625
626 for (i = 0; i < chip->ngpio; i++, gpio++) {
627 const char *label = gpiochip_is_requested(chip, i);
628 bool pull;
629 u32 bit = 1 << i;
630
631 if (!label)
632 continue;
633
634 is_out = readl(nmk_chip->addr + NMK_GPIO_DIR) & bit;
635 pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
636 mode = nmk_gpio_get_mode(gpio);
637 seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
638 gpio, label,
639 is_out ? "out" : "in ",
640 chip->get
641 ? (chip->get(chip, i) ? "hi" : "lo")
642 : "? ",
643 (mode < 0) ? "unknown" : modes[mode],
644 pull ? "pull" : "none");
645
646 if (!is_out) {
647 int irq = gpio_to_irq(gpio);
648 struct irq_desc *desc = irq_to_desc(irq);
649
650 /* This races with request_irq(), set_irq_type(),
651 * and set_irq_wake() ... but those are "rare".
652 *
653 * More significantly, trigger type flags aren't
654 * currently maintained by genirq.
655 */
656 if (irq >= 0 && desc->action) {
657 char *trigger;
658
659 switch (desc->status & IRQ_TYPE_SENSE_MASK) {
660 case IRQ_TYPE_NONE:
661 trigger = "(default)";
662 break;
663 case IRQ_TYPE_EDGE_FALLING:
664 trigger = "edge-falling";
665 break;
666 case IRQ_TYPE_EDGE_RISING:
667 trigger = "edge-rising";
668 break;
669 case IRQ_TYPE_EDGE_BOTH:
670 trigger = "edge-both";
671 break;
672 case IRQ_TYPE_LEVEL_HIGH:
673 trigger = "level-high";
674 break;
675 case IRQ_TYPE_LEVEL_LOW:
676 trigger = "level-low";
677 break;
678 default:
679 trigger = "?trigger?";
680 break;
681 }
682
683 seq_printf(s, " irq-%d %s%s",
684 irq, trigger,
685 (desc->status & IRQ_WAKEUP)
686 ? " wakeup" : "");
687 }
688 }
689
690 seq_printf(s, "\n");
691 }
692}
693
694#else
695#define nmk_gpio_dbg_show NULL
696#endif
697
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100698/* This structure is replicated for each GPIO block allocated at probe time */
699static struct gpio_chip nmk_gpio_template = {
700 .direction_input = nmk_gpio_make_input,
701 .get = nmk_gpio_get_input,
702 .direction_output = nmk_gpio_make_output,
703 .set = nmk_gpio_set_output,
Rabin Vincent0d2aec92010-06-16 06:10:43 +0100704 .to_irq = nmk_gpio_to_irq,
Rabin Vincentd0b543c2010-03-04 17:39:05 +0530705 .dbg_show = nmk_gpio_dbg_show,
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100706 .can_sleep = 0,
707};
708
Uwe Kleine-Königfd0d67d2010-09-02 16:13:35 +0100709static int __devinit nmk_gpio_probe(struct platform_device *dev)
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100710{
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100711 struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100712 struct nmk_gpio_chip *nmk_chip;
713 struct gpio_chip *chip;
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100714 struct resource *res;
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100715 struct clk *clk;
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100716 int irq;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100717 int ret;
718
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100719 if (!pdata)
720 return -ENODEV;
721
722 res = platform_get_resource(dev, IORESOURCE_MEM, 0);
723 if (!res) {
724 ret = -ENOENT;
725 goto out;
726 }
727
728 irq = platform_get_irq(dev, 0);
729 if (irq < 0) {
730 ret = irq;
731 goto out;
732 }
733
734 if (request_mem_region(res->start, resource_size(res),
735 dev_name(&dev->dev)) == NULL) {
736 ret = -EBUSY;
737 goto out;
738 }
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100739
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100740 clk = clk_get(&dev->dev, NULL);
741 if (IS_ERR(clk)) {
742 ret = PTR_ERR(clk);
743 goto out_release;
744 }
745
746 clk_enable(clk);
747
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100748 nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
749 if (!nmk_chip) {
750 ret = -ENOMEM;
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100751 goto out_clk;
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100752 }
753 /*
754 * The virt address in nmk_chip->addr is in the nomadik register space,
755 * so we can simply convert the resource address, without remapping
756 */
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100757 nmk_chip->clk = clk;
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100758 nmk_chip->addr = io_p2v(res->start);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100759 nmk_chip->chip = nmk_gpio_template;
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100760 nmk_chip->parent_irq = irq;
Rabin Vincentc0fcb8d2010-03-03 04:48:54 +0100761 spin_lock_init(&nmk_chip->lock);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100762
763 chip = &nmk_chip->chip;
764 chip->base = pdata->first_gpio;
Rabin Vincente493e062010-03-18 12:35:22 +0530765 chip->ngpio = pdata->num_gpio;
Rabin Vincent8d568ae2010-12-08 11:07:54 +0530766 chip->label = pdata->name ?: dev_name(&dev->dev);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100767 chip->dev = &dev->dev;
768 chip->owner = THIS_MODULE;
769
770 ret = gpiochip_add(&nmk_chip->chip);
771 if (ret)
772 goto out_free;
773
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100774 platform_set_drvdata(dev, nmk_chip);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100775
776 nmk_gpio_init_irq(nmk_chip);
777
778 dev_info(&dev->dev, "Bits %i-%i at address %p\n",
779 nmk_chip->chip.base, nmk_chip->chip.base+31, nmk_chip->addr);
780 return 0;
781
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100782out_free:
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100783 kfree(nmk_chip);
Rabin Vincentaf7dc222010-05-06 11:14:17 +0100784out_clk:
785 clk_disable(clk);
786 clk_put(clk);
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100787out_release:
788 release_mem_region(res->start, resource_size(res));
789out:
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100790 dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret,
791 pdata->first_gpio, pdata->first_gpio+31);
792 return ret;
793}
794
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100795static struct platform_driver nmk_gpio_driver = {
796 .driver = {
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100797 .owner = THIS_MODULE,
798 .name = "gpio",
799 },
800 .probe = nmk_gpio_probe,
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100801 .suspend = NULL, /* to be done */
802 .resume = NULL,
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100803};
804
805static int __init nmk_gpio_init(void)
806{
Rabin Vincent3e3c62c2010-03-03 04:52:34 +0100807 return platform_driver_register(&nmk_gpio_driver);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100808}
809
Rabin Vincent33f45ea2010-06-02 06:09:52 +0100810core_initcall(nmk_gpio_init);
Alessandro Rubini2ec1d352009-07-02 15:29:12 +0100811
812MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini");
813MODULE_DESCRIPTION("Nomadik GPIO Driver");
814MODULE_LICENSE("GPL");
815
816