Blame view

drivers/gpio/gpio-nomadik.c 28.7 KB
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1
2
3
4
5
6
  /*
   * Generic GPIO driver for logic cells found in the Nomadik SoC
   *
   * Copyright (C) 2008,2009 STMicroelectronics
   * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
   *   Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
33d78647d   Linus Walleij   gpio/nomadik: fix...
7
   * Copyright (C) 2011 Linus Walleij <linus.walleij@linaro.org>
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
8
9
10
11
12
13
14
15
16
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/device.h>
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
17
  #include <linux/platform_device.h>
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
18
  #include <linux/io.h>
af7dc2281   Rabin Vincent   ARM: 6104/1: noma...
19
20
  #include <linux/clk.h>
  #include <linux/err.h>
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
21
22
23
24
  #include <linux/gpio.h>
  #include <linux/spinlock.h>
  #include <linux/interrupt.h>
  #include <linux/irq.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
26

adfed159a   Will Deacon   ARM: nmk: update ...
27
  #include <asm/mach/irq.h>
378be0663   Rabin Vincent   ARM: 6155/1: noma...
28
  #include <plat/pincfg.h>
0f3328619   Linus Walleij   ARM: 7032/1: plat...
29
  #include <plat/gpio-nomadik.h>
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
30
  #include <mach/hardware.h>
75482dc3d   Russell King   ARM: gpio: nomadi...
31
  #include <asm/gpio.h>
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
32
33
34
35
  
  /*
   * The GPIO module in the Nomadik family of Systems-on-Chip is an
   * AMBA device, managing 32 pins and alternate functions.  The logic block
9c66ee6f5   Jonas Aaberg   plat-nomadik: pul...
36
   * is currently used in the Nomadik and ux500.
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
37
38
39
   *
   * Symbols in this file are called "nmk_gpio" for "nomadik gpio"
   */
01727e61f   Rabin Vincent   plat-nomadik: imp...
40
  #define NMK_GPIO_PER_CHIP	32
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
41
42
43
  struct nmk_gpio_chip {
  	struct gpio_chip chip;
  	void __iomem *addr;
af7dc2281   Rabin Vincent   ARM: 6104/1: noma...
44
  	struct clk *clk;
33b744b35   Rabin Vincent   plat-nomadik: sup...
45
  	unsigned int bank;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
46
  	unsigned int parent_irq;
2c8bb0eba   Virupax Sadashivpetimath   plat-nomadik: typ...
47
  	int secondary_parent_irq;
33b744b35   Rabin Vincent   plat-nomadik: sup...
48
  	u32 (*get_secondary_status)(unsigned int bank);
01727e61f   Rabin Vincent   plat-nomadik: imp...
49
  	void (*set_ioforce)(bool enable);
c0fcb8dba   Rabin Vincent   ARM: 5970/1: noma...
50
  	spinlock_t lock;
33d78647d   Linus Walleij   gpio/nomadik: fix...
51
  	bool sleepmode;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
52
53
54
  	/* Keep track of configured edges */
  	u32 edge_rising;
  	u32 edge_falling;
b9df468d8   Rabin Vincent   plat-nomadik: mak...
55
56
57
58
  	u32 real_wake;
  	u32 rwimsc;
  	u32 fwimsc;
  	u32 slpm;
bc6f5cf64   Rickard Andersson   gpio/nomadik: add...
59
  	u32 pull_up;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
60
  };
01727e61f   Rabin Vincent   plat-nomadik: imp...
61
62
63
64
65
66
  static struct nmk_gpio_chip *
  nmk_gpio_chips[DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP)];
  
  static DEFINE_SPINLOCK(nmk_gpio_slpm_lock);
  
  #define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips)
6f9a974cf   Rabin Vincent   ARM: 6154/1: noma...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip,
  				unsigned offset, int gpio_mode)
  {
  	u32 bit = 1 << offset;
  	u32 afunc, bfunc;
  
  	afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit;
  	bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit;
  	if (gpio_mode & NMK_GPIO_ALT_A)
  		afunc |= bit;
  	if (gpio_mode & NMK_GPIO_ALT_B)
  		bfunc |= bit;
  	writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA);
  	writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB);
  }
81a3c2989   Rabin Vincent   ARM: 6149/1: noma...
82
83
84
85
86
87
88
89
90
91
92
93
94
  static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip,
  				unsigned offset, enum nmk_gpio_slpm mode)
  {
  	u32 bit = 1 << offset;
  	u32 slpm;
  
  	slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC);
  	if (mode == NMK_GPIO_SLPM_NOCHANGE)
  		slpm |= bit;
  	else
  		slpm &= ~bit;
  	writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC);
  }
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
95
96
97
98
99
100
101
  static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
  				unsigned offset, enum nmk_gpio_pull pull)
  {
  	u32 bit = 1 << offset;
  	u32 pdis;
  
  	pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS);
bc6f5cf64   Rickard Andersson   gpio/nomadik: add...
102
  	if (pull == NMK_GPIO_PULL_NONE) {
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
103
  		pdis |= bit;
bc6f5cf64   Rickard Andersson   gpio/nomadik: add...
104
105
  		nmk_chip->pull_up &= ~bit;
  	} else {
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
106
  		pdis &= ~bit;
bc6f5cf64   Rickard Andersson   gpio/nomadik: add...
107
  	}
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
108
  	writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS);
bc6f5cf64   Rickard Andersson   gpio/nomadik: add...
109
110
  	if (pull == NMK_GPIO_PULL_UP) {
  		nmk_chip->pull_up |= bit;
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
111
  		writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
bc6f5cf64   Rickard Andersson   gpio/nomadik: add...
112
113
  	} else if (pull == NMK_GPIO_PULL_DOWN) {
  		nmk_chip->pull_up &= ~bit;
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
114
  		writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
bc6f5cf64   Rickard Andersson   gpio/nomadik: add...
115
  	}
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
116
  }
378be0663   Rabin Vincent   ARM: 6155/1: noma...
117
118
119
120
121
  static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
  				  unsigned offset)
  {
  	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
  }
6720db7cc   Rabin Vincent   ARM: 6354/1: noma...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip,
  				  unsigned offset, int val)
  {
  	if (val)
  		writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS);
  	else
  		writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC);
  }
  
  static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
  				  unsigned offset, int val)
  {
  	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
  	__nmk_gpio_set_output(nmk_chip, offset, val);
  }
01727e61f   Rabin Vincent   plat-nomadik: imp...
137
138
139
140
  static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip,
  				     unsigned offset, int gpio_mode,
  				     bool glitch)
  {
3c4bee04d   Linus Walleij   plat-nomadik: fix...
141
142
  	u32 rwimsc = readl(nmk_chip->addr + NMK_GPIO_RWIMSC);
  	u32 fwimsc = readl(nmk_chip->addr + NMK_GPIO_FWIMSC);
01727e61f   Rabin Vincent   plat-nomadik: imp...
143
144
145
  
  	if (glitch && nmk_chip->set_ioforce) {
  		u32 bit = BIT(offset);
01727e61f   Rabin Vincent   plat-nomadik: imp...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  		/* Prevent spurious wakeups */
  		writel(rwimsc & ~bit, nmk_chip->addr + NMK_GPIO_RWIMSC);
  		writel(fwimsc & ~bit, nmk_chip->addr + NMK_GPIO_FWIMSC);
  
  		nmk_chip->set_ioforce(true);
  	}
  
  	__nmk_gpio_set_mode(nmk_chip, offset, gpio_mode);
  
  	if (glitch && nmk_chip->set_ioforce) {
  		nmk_chip->set_ioforce(false);
  
  		writel(rwimsc, nmk_chip->addr + NMK_GPIO_RWIMSC);
  		writel(fwimsc, nmk_chip->addr + NMK_GPIO_FWIMSC);
  	}
  }
378be0663   Rabin Vincent   ARM: 6155/1: noma...
162
  static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
01727e61f   Rabin Vincent   plat-nomadik: imp...
163
  			     pin_cfg_t cfg, bool sleep, unsigned int *slpmregs)
378be0663   Rabin Vincent   ARM: 6155/1: noma...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  {
  	static const char *afnames[] = {
  		[NMK_GPIO_ALT_GPIO]	= "GPIO",
  		[NMK_GPIO_ALT_A]	= "A",
  		[NMK_GPIO_ALT_B]	= "B",
  		[NMK_GPIO_ALT_C]	= "C"
  	};
  	static const char *pullnames[] = {
  		[NMK_GPIO_PULL_NONE]	= "none",
  		[NMK_GPIO_PULL_UP]	= "up",
  		[NMK_GPIO_PULL_DOWN]	= "down",
  		[3] /* illegal */	= "??"
  	};
  	static const char *slpmnames[] = {
7e3f7e59c   Rabin Vincent   ARM: 6353/1: noma...
178
179
  		[NMK_GPIO_SLPM_INPUT]		= "input/wakeup",
  		[NMK_GPIO_SLPM_NOCHANGE]	= "no-change/no-wakeup",
378be0663   Rabin Vincent   ARM: 6155/1: noma...
180
181
182
183
184
185
  	};
  
  	int pin = PIN_NUM(cfg);
  	int pull = PIN_PULL(cfg);
  	int af = PIN_ALT(cfg);
  	int slpm = PIN_SLPM(cfg);
6720db7cc   Rabin Vincent   ARM: 6354/1: noma...
186
187
  	int output = PIN_DIR(cfg);
  	int val = PIN_VAL(cfg);
01727e61f   Rabin Vincent   plat-nomadik: imp...
188
  	bool glitch = af == NMK_GPIO_ALT_C;
378be0663   Rabin Vincent   ARM: 6155/1: noma...
189

dacdc96cd   Rabin Vincent   nomadik-gpio: all...
190
191
192
  	dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)
  ",
  		pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
6720db7cc   Rabin Vincent   ARM: 6354/1: noma...
193
194
  		output ? "output " : "input",
  		output ? (val ? "high" : "low") : "");
dacdc96cd   Rabin Vincent   nomadik-gpio: all...
195
196
197
198
  	if (sleep) {
  		int slpm_pull = PIN_SLPM_PULL(cfg);
  		int slpm_output = PIN_SLPM_DIR(cfg);
  		int slpm_val = PIN_SLPM_VAL(cfg);
3546d15c5   Rabin Vincent   plat-nomadik: set...
199
  		af = NMK_GPIO_ALT_GPIO;
dacdc96cd   Rabin Vincent   nomadik-gpio: all...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  		/*
  		 * The SLPM_* values are normal values + 1 to allow zero to
  		 * mean "same as normal".
  		 */
  		if (slpm_pull)
  			pull = slpm_pull - 1;
  		if (slpm_output)
  			output = slpm_output - 1;
  		if (slpm_val)
  			val = slpm_val - 1;
  
  		dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s
  ",
  			pin,
  			slpm_pull ? pullnames[pull] : "same",
  			slpm_output ? (output ? "output" : "input") : "same",
  			slpm_val ? (val ? "high" : "low") : "same");
  	}
6720db7cc   Rabin Vincent   ARM: 6354/1: noma...
218
219
220
221
222
223
  	if (output)
  		__nmk_gpio_make_output(nmk_chip, offset, val);
  	else {
  		__nmk_gpio_make_input(nmk_chip, offset);
  		__nmk_gpio_set_pull(nmk_chip, offset, pull);
  	}
378be0663   Rabin Vincent   ARM: 6155/1: noma...
224

01727e61f   Rabin Vincent   plat-nomadik: imp...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  	/*
  	 * If we've backed up the SLPM registers (glitch workaround), modify
  	 * the backups since they will be restored.
  	 */
  	if (slpmregs) {
  		if (slpm == NMK_GPIO_SLPM_NOCHANGE)
  			slpmregs[nmk_chip->bank] |= BIT(offset);
  		else
  			slpmregs[nmk_chip->bank] &= ~BIT(offset);
  	} else
  		__nmk_gpio_set_slpm(nmk_chip, offset, slpm);
  
  	__nmk_gpio_set_mode_safe(nmk_chip, offset, af, glitch);
  }
  
  /*
   * Safe sequence used to switch IOs between GPIO and Alternate-C mode:
   *  - Save SLPM registers
   *  - Set SLPM=0 for the IOs you want to switch and others to 1
   *  - Configure the GPIO registers for the IOs that are being switched
   *  - Set IOFORCE=1
   *  - Modify the AFLSA/B registers for the IOs that are being switched
   *  - Set IOFORCE=0
   *  - Restore SLPM registers
   *  - Any spurious wake up event during switch sequence to be ignored and
   *    cleared
   */
  static void nmk_gpio_glitch_slpm_init(unsigned int *slpm)
  {
  	int i;
  
  	for (i = 0; i < NUM_BANKS; i++) {
  		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
  		unsigned int temp = slpm[i];
  
  		if (!chip)
  			break;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
262
  		clk_enable(chip->clk);
01727e61f   Rabin Vincent   plat-nomadik: imp...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  		slpm[i] = readl(chip->addr + NMK_GPIO_SLPC);
  		writel(temp, chip->addr + NMK_GPIO_SLPC);
  	}
  }
  
  static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm)
  {
  	int i;
  
  	for (i = 0; i < NUM_BANKS; i++) {
  		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
  
  		if (!chip)
  			break;
  
  		writel(slpm[i], chip->addr + NMK_GPIO_SLPC);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
279
280
  
  		clk_disable(chip->clk);
01727e61f   Rabin Vincent   plat-nomadik: imp...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  	}
  }
  
  static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
  {
  	static unsigned int slpm[NUM_BANKS];
  	unsigned long flags;
  	bool glitch = false;
  	int ret = 0;
  	int i;
  
  	for (i = 0; i < num; i++) {
  		if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) {
  			glitch = true;
  			break;
  		}
  	}
  
  	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
  
  	if (glitch) {
  		memset(slpm, 0xff, sizeof(slpm));
  
  		for (i = 0; i < num; i++) {
  			int pin = PIN_NUM(cfgs[i]);
  			int offset = pin % NMK_GPIO_PER_CHIP;
  
  			if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C)
  				slpm[pin / NMK_GPIO_PER_CHIP] &= ~BIT(offset);
  		}
  
  		nmk_gpio_glitch_slpm_init(slpm);
  	}
  
  	for (i = 0; i < num; i++) {
  		struct nmk_gpio_chip *nmk_chip;
  		int pin = PIN_NUM(cfgs[i]);
6845664a6   Thomas Gleixner   arm: Cleanup the ...
318
  		nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(pin));
01727e61f   Rabin Vincent   plat-nomadik: imp...
319
320
321
322
  		if (!nmk_chip) {
  			ret = -EINVAL;
  			break;
  		}
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
323
  		clk_enable(nmk_chip->clk);
01727e61f   Rabin Vincent   plat-nomadik: imp...
324
325
326
327
  		spin_lock(&nmk_chip->lock);
  		__nmk_config_pin(nmk_chip, pin - nmk_chip->chip.base,
  				 cfgs[i], sleep, glitch ? slpm : NULL);
  		spin_unlock(&nmk_chip->lock);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
328
  		clk_disable(nmk_chip->clk);
01727e61f   Rabin Vincent   plat-nomadik: imp...
329
330
331
332
333
334
335
336
  	}
  
  	if (glitch)
  		nmk_gpio_glitch_slpm_restore(slpm);
  
  	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
  
  	return ret;
378be0663   Rabin Vincent   ARM: 6155/1: noma...
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  }
  
  /**
   * nmk_config_pin - configure a pin's mux attributes
   * @cfg: pin confguration
   *
   * Configures a pin's mode (alternate function or GPIO), its pull up status,
   * and its sleep mode based on the specified configuration.  The @cfg is
   * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
   * are constructed using, and can be further enhanced with, the macros in
   * plat/pincfg.h.
   *
   * If a pin's mode is set to GPIO, it is configured as an input to avoid
   * side-effects.  The gpio can be manipulated later using standard GPIO API
   * calls.
   */
dacdc96cd   Rabin Vincent   nomadik-gpio: all...
353
  int nmk_config_pin(pin_cfg_t cfg, bool sleep)
378be0663   Rabin Vincent   ARM: 6155/1: noma...
354
  {
01727e61f   Rabin Vincent   plat-nomadik: imp...
355
  	return __nmk_config_pins(&cfg, 1, sleep);
378be0663   Rabin Vincent   ARM: 6155/1: noma...
356
357
358
359
360
361
362
363
364
365
366
367
368
  }
  EXPORT_SYMBOL(nmk_config_pin);
  
  /**
   * nmk_config_pins - configure several pins at once
   * @cfgs: array of pin configurations
   * @num: number of elments in the array
   *
   * Configures several pins using nmk_config_pin().  Refer to that function for
   * further information.
   */
  int nmk_config_pins(pin_cfg_t *cfgs, int num)
  {
01727e61f   Rabin Vincent   plat-nomadik: imp...
369
  	return __nmk_config_pins(cfgs, num, false);
378be0663   Rabin Vincent   ARM: 6155/1: noma...
370
371
  }
  EXPORT_SYMBOL(nmk_config_pins);
dacdc96cd   Rabin Vincent   nomadik-gpio: all...
372
373
  int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num)
  {
01727e61f   Rabin Vincent   plat-nomadik: imp...
374
  	return __nmk_config_pins(cfgs, num, true);
dacdc96cd   Rabin Vincent   nomadik-gpio: all...
375
376
  }
  EXPORT_SYMBOL(nmk_config_pins_sleep);
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
377
  /**
81a3c2989   Rabin Vincent   ARM: 6149/1: noma...
378
379
380
381
   * nmk_gpio_set_slpm() - configure the sleep mode of a pin
   * @gpio: pin number
   * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE,
   *
33d78647d   Linus Walleij   gpio/nomadik: fix...
382
383
384
385
386
387
388
   * This register is actually in the pinmux layer, not the GPIO block itself.
   * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP
   * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code).
   * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is
   * HIGH, overriding the normal setting defined by GPIO_AFSELx registers.
   * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit),
   * the GPIOs return to the normal setting defined by GPIO_AFSELx registers.
7e3f7e59c   Rabin Vincent   ARM: 6353/1: noma...
389
   *
33d78647d   Linus Walleij   gpio/nomadik: fix...
390
391
392
393
394
395
396
397
398
399
400
   * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO
   * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is
   * entered) regardless of the altfunction selected. Also wake-up detection is
   * ENABLED.
   *
   * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains
   * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS
   * (for altfunction GPIO) or respective on-chip peripherals (for other
   * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED.
   *
   * Note that enable_irq_wake() will automatically enable wakeup detection.
81a3c2989   Rabin Vincent   ARM: 6149/1: noma...
401
402
403
404
405
   */
  int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
  {
  	struct nmk_gpio_chip *nmk_chip;
  	unsigned long flags;
6845664a6   Thomas Gleixner   arm: Cleanup the ...
406
  	nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
81a3c2989   Rabin Vincent   ARM: 6149/1: noma...
407
408
  	if (!nmk_chip)
  		return -EINVAL;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
409
  	clk_enable(nmk_chip->clk);
01727e61f   Rabin Vincent   plat-nomadik: imp...
410
411
  	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
  	spin_lock(&nmk_chip->lock);
81a3c2989   Rabin Vincent   ARM: 6149/1: noma...
412
  	__nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode);
01727e61f   Rabin Vincent   plat-nomadik: imp...
413
414
415
  
  	spin_unlock(&nmk_chip->lock);
  	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
416
  	clk_disable(nmk_chip->clk);
81a3c2989   Rabin Vincent   ARM: 6149/1: noma...
417
418
419
420
421
  
  	return 0;
  }
  
  /**
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
   * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio
   * @gpio: pin number
   * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE
   *
   * Enables/disables pull up/down on a specified pin.  This only takes effect if
   * the pin is configured as an input (either explicitly or by the alternate
   * function).
   *
   * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
   * configured as an input.  Otherwise, due to the way the controller registers
   * work, this function will change the value output on the pin.
   */
  int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
  {
  	struct nmk_gpio_chip *nmk_chip;
  	unsigned long flags;
6845664a6   Thomas Gleixner   arm: Cleanup the ...
438
  	nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
439
440
  	if (!nmk_chip)
  		return -EINVAL;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
441
  	clk_enable(nmk_chip->clk);
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
442
443
444
  	spin_lock_irqsave(&nmk_chip->lock, flags);
  	__nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull);
  	spin_unlock_irqrestore(&nmk_chip->lock, flags);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
445
  	clk_disable(nmk_chip->clk);
5b327edf0   Rabin Vincent   ARM: 6148/1: noma...
446
447
448
  
  	return 0;
  }
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
449
  /* Mode functions */
9c66ee6f5   Jonas Aaberg   plat-nomadik: pul...
450
451
452
453
454
455
456
457
458
  /**
   * nmk_gpio_set_mode() - set the mux mode of a gpio pin
   * @gpio: pin number
   * @gpio_mode: one of NMK_GPIO_ALT_GPIO, NMK_GPIO_ALT_A,
   *	       NMK_GPIO_ALT_B, and NMK_GPIO_ALT_C
   *
   * Sets the mode of the specified pin to one of the alternate functions or
   * plain GPIO.
   */
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
459
460
461
462
  int nmk_gpio_set_mode(int gpio, int gpio_mode)
  {
  	struct nmk_gpio_chip *nmk_chip;
  	unsigned long flags;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
463

6845664a6   Thomas Gleixner   arm: Cleanup the ...
464
  	nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
465
466
  	if (!nmk_chip)
  		return -EINVAL;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
467
  	clk_enable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
468
  	spin_lock_irqsave(&nmk_chip->lock, flags);
6f9a974cf   Rabin Vincent   ARM: 6154/1: noma...
469
  	__nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
470
  	spin_unlock_irqrestore(&nmk_chip->lock, flags);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
471
  	clk_disable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
472
473
474
475
476
477
478
479
480
  
  	return 0;
  }
  EXPORT_SYMBOL(nmk_gpio_set_mode);
  
  int nmk_gpio_get_mode(int gpio)
  {
  	struct nmk_gpio_chip *nmk_chip;
  	u32 afunc, bfunc, bit;
6845664a6   Thomas Gleixner   arm: Cleanup the ...
481
  	nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
482
483
484
485
  	if (!nmk_chip)
  		return -EINVAL;
  
  	bit = 1 << (gpio - nmk_chip->chip.base);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
486
  	clk_enable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
487
488
  	afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit;
  	bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
489
  	clk_disable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
490
491
492
493
494
495
496
497
498
499
  	return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0);
  }
  EXPORT_SYMBOL(nmk_gpio_get_mode);
  
  
  /* IRQ functions */
  static inline int nmk_gpio_get_bitmask(int gpio)
  {
  	return 1 << (gpio % 32);
  }
f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
500
  static void nmk_gpio_irq_ack(struct irq_data *d)
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
501
502
503
  {
  	int gpio;
  	struct nmk_gpio_chip *nmk_chip;
f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
504
505
  	gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
  	nmk_chip = irq_data_get_irq_chip_data(d);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
506
507
  	if (!nmk_chip)
  		return;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
508
509
  
  	clk_enable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
510
  	writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
511
  	clk_disable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
512
  }
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
513
514
515
516
  enum nmk_gpio_irq_type {
  	NORMAL,
  	WAKE,
  };
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
517
  static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
518
519
  				  int gpio, enum nmk_gpio_irq_type which,
  				  bool enable)
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
520
  {
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
521
522
  	u32 rimsc = which == WAKE ? NMK_GPIO_RWIMSC : NMK_GPIO_RIMSC;
  	u32 fimsc = which == WAKE ? NMK_GPIO_FWIMSC : NMK_GPIO_FIMSC;
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
523
524
  	u32 bitmask = nmk_gpio_get_bitmask(gpio);
  	u32 reg;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
525

040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
526
  	/* we must individually set/clear the two edges */
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
527
  	if (nmk_chip->edge_rising & bitmask) {
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
528
  		reg = readl(nmk_chip->addr + rimsc);
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
529
530
531
532
  		if (enable)
  			reg |= bitmask;
  		else
  			reg &= ~bitmask;
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
533
  		writel(reg, nmk_chip->addr + rimsc);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
534
535
  	}
  	if (nmk_chip->edge_falling & bitmask) {
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
536
  		reg = readl(nmk_chip->addr + fimsc);
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
537
538
539
540
  		if (enable)
  			reg |= bitmask;
  		else
  			reg &= ~bitmask;
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
541
  		writel(reg, nmk_chip->addr + fimsc);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
542
  	}
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
543
  }
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
544

b9df468d8   Rabin Vincent   plat-nomadik: mak...
545
546
547
  static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
  				int gpio, bool on)
  {
33d78647d   Linus Walleij   gpio/nomadik: fix...
548
549
550
551
552
  	if (nmk_chip->sleepmode) {
  		__nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base,
  				    on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
  				    : NMK_GPIO_SLPM_WAKEUP_DISABLE);
  	}
b9df468d8   Rabin Vincent   plat-nomadik: mak...
553
554
555
556
  	__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
  }
  
  static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
557
558
559
560
  {
  	int gpio;
  	struct nmk_gpio_chip *nmk_chip;
  	unsigned long flags;
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
561
  	u32 bitmask;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
562

f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
563
564
  	gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
  	nmk_chip = irq_data_get_irq_chip_data(d);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
565
566
  	bitmask = nmk_gpio_get_bitmask(gpio);
  	if (!nmk_chip)
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
567
  		return -EINVAL;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
568

3c0227d26   Rabin Vincent   gpio/nomadik: dis...
569
  	clk_enable(nmk_chip->clk);
b9df468d8   Rabin Vincent   plat-nomadik: mak...
570
571
572
573
574
575
576
577
578
579
  	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
  	spin_lock(&nmk_chip->lock);
  
  	__nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, enable);
  
  	if (!(nmk_chip->real_wake & bitmask))
  		__nmk_gpio_set_wake(nmk_chip, gpio, enable);
  
  	spin_unlock(&nmk_chip->lock);
  	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
580
  	clk_disable(nmk_chip->clk);
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
581
582
  
  	return 0;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
583
  }
f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
584
  static void nmk_gpio_irq_mask(struct irq_data *d)
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
585
  {
b9df468d8   Rabin Vincent   plat-nomadik: mak...
586
  	nmk_gpio_irq_maskunmask(d, false);
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
587
  }
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
588

f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
589
  static void nmk_gpio_irq_unmask(struct irq_data *d)
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
590
  {
b9df468d8   Rabin Vincent   plat-nomadik: mak...
591
  	nmk_gpio_irq_maskunmask(d, true);
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
592
  }
f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
593
  static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
594
  {
7e3f7e59c   Rabin Vincent   ARM: 6353/1: noma...
595
596
  	struct nmk_gpio_chip *nmk_chip;
  	unsigned long flags;
b9df468d8   Rabin Vincent   plat-nomadik: mak...
597
  	u32 bitmask;
7e3f7e59c   Rabin Vincent   ARM: 6353/1: noma...
598
  	int gpio;
f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
599
600
  	gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
  	nmk_chip = irq_data_get_irq_chip_data(d);
7e3f7e59c   Rabin Vincent   ARM: 6353/1: noma...
601
602
  	if (!nmk_chip)
  		return -EINVAL;
b9df468d8   Rabin Vincent   plat-nomadik: mak...
603
  	bitmask = nmk_gpio_get_bitmask(gpio);
7e3f7e59c   Rabin Vincent   ARM: 6353/1: noma...
604

3c0227d26   Rabin Vincent   gpio/nomadik: dis...
605
  	clk_enable(nmk_chip->clk);
01727e61f   Rabin Vincent   plat-nomadik: imp...
606
607
  	spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
  	spin_lock(&nmk_chip->lock);
479a0c7ee   Linus Walleij   gpio/nomadik: use...
608
  	if (irqd_irq_disabled(d))
b9df468d8   Rabin Vincent   plat-nomadik: mak...
609
610
611
612
613
614
  		__nmk_gpio_set_wake(nmk_chip, gpio, on);
  
  	if (on)
  		nmk_chip->real_wake |= bitmask;
  	else
  		nmk_chip->real_wake &= ~bitmask;
01727e61f   Rabin Vincent   plat-nomadik: imp...
615
616
617
  
  	spin_unlock(&nmk_chip->lock);
  	spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
618
  	clk_disable(nmk_chip->clk);
7e3f7e59c   Rabin Vincent   ARM: 6353/1: noma...
619
620
  
  	return 0;
040e5ecdd   Rabin Vincent   ARM: 6100/1: noma...
621
  }
f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
622
  static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
623
  {
479a0c7ee   Linus Walleij   gpio/nomadik: use...
624
  	bool enabled = !irqd_irq_disabled(d);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
625
  	bool wake = irqd_is_wakeup_set(d);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
626
627
628
629
  	int gpio;
  	struct nmk_gpio_chip *nmk_chip;
  	unsigned long flags;
  	u32 bitmask;
f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
630
631
  	gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
  	nmk_chip = irq_data_get_irq_chip_data(d);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
632
633
634
635
636
637
638
639
  	bitmask = nmk_gpio_get_bitmask(gpio);
  	if (!nmk_chip)
  		return -EINVAL;
  
  	if (type & IRQ_TYPE_LEVEL_HIGH)
  		return -EINVAL;
  	if (type & IRQ_TYPE_LEVEL_LOW)
  		return -EINVAL;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
640
  	clk_enable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
641
  	spin_lock_irqsave(&nmk_chip->lock, flags);
7a852d806   Rabin Vincent   ARM: 6101/1: noma...
642
  	if (enabled)
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
643
  		__nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false);
b9df468d8   Rabin Vincent   plat-nomadik: mak...
644
  	if (enabled || wake)
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
645
  		__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false);
7a852d806   Rabin Vincent   ARM: 6101/1: noma...
646

2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
647
648
649
  	nmk_chip->edge_rising &= ~bitmask;
  	if (type & IRQ_TYPE_EDGE_RISING)
  		nmk_chip->edge_rising |= bitmask;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
650
651
652
653
  
  	nmk_chip->edge_falling &= ~bitmask;
  	if (type & IRQ_TYPE_EDGE_FALLING)
  		nmk_chip->edge_falling |= bitmask;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
654

7a852d806   Rabin Vincent   ARM: 6101/1: noma...
655
  	if (enabled)
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
656
  		__nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true);
b9df468d8   Rabin Vincent   plat-nomadik: mak...
657
  	if (enabled || wake)
4d4e20f77   Rabin Vincent   ARM: 6175/1: noma...
658
  		__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
659

7a852d806   Rabin Vincent   ARM: 6101/1: noma...
660
  	spin_unlock_irqrestore(&nmk_chip->lock, flags);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
661
  	clk_disable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
662
663
664
  
  	return 0;
  }
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
665
666
667
  static unsigned int nmk_gpio_irq_startup(struct irq_data *d)
  {
  	struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
668

3c0227d26   Rabin Vincent   gpio/nomadik: dis...
669
670
  	clk_enable(nmk_chip->clk);
  	nmk_gpio_irq_unmask(d);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
671
672
  	return 0;
  }
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
673
674
675
676
677
678
679
  static void nmk_gpio_irq_shutdown(struct irq_data *d)
  {
  	struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
  
  	nmk_gpio_irq_mask(d);
  	clk_disable(nmk_chip->clk);
  }
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
680
681
  static struct irq_chip nmk_gpio_irq_chip = {
  	.name		= "Nomadik-GPIO",
f272c00e6   Lennert Buytenhek   ARM: plat-nomadik...
682
683
684
685
686
  	.irq_ack	= nmk_gpio_irq_ack,
  	.irq_mask	= nmk_gpio_irq_mask,
  	.irq_unmask	= nmk_gpio_irq_unmask,
  	.irq_set_type	= nmk_gpio_irq_set_type,
  	.irq_set_wake	= nmk_gpio_irq_set_wake,
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
687
688
  	.irq_startup	= nmk_gpio_irq_startup,
  	.irq_shutdown	= nmk_gpio_irq_shutdown,
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
689
  };
33b744b35   Rabin Vincent   plat-nomadik: sup...
690
691
  static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
  				   u32 status)
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
692
693
  {
  	struct nmk_gpio_chip *nmk_chip;
6845664a6   Thomas Gleixner   arm: Cleanup the ...
694
  	struct irq_chip *host_chip = irq_get_chip(irq);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
695
  	unsigned int first_irq;
adfed159a   Will Deacon   ARM: nmk: update ...
696
  	chained_irq_enter(host_chip, desc);
aaedaa2b5   Rabin Vincent   ARM: 5971/1: noma...
697

6845664a6   Thomas Gleixner   arm: Cleanup the ...
698
  	nmk_chip = irq_get_handler_data(irq);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
699
  	first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
33b744b35   Rabin Vincent   plat-nomadik: sup...
700
701
702
703
704
  	while (status) {
  		int bit = __ffs(status);
  
  		generic_handle_irq(first_irq + bit);
  		status &= ~BIT(bit);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
705
  	}
aaedaa2b5   Rabin Vincent   ARM: 5971/1: noma...
706

adfed159a   Will Deacon   ARM: nmk: update ...
707
  	chained_irq_exit(host_chip, desc);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
708
  }
33b744b35   Rabin Vincent   plat-nomadik: sup...
709
710
  static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
  {
6845664a6   Thomas Gleixner   arm: Cleanup the ...
711
  	struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
712
713
714
715
716
  	u32 status;
  
  	clk_enable(nmk_chip->clk);
  	status = readl(nmk_chip->addr + NMK_GPIO_IS);
  	clk_disable(nmk_chip->clk);
33b744b35   Rabin Vincent   plat-nomadik: sup...
717
718
719
720
721
722
723
  
  	__nmk_gpio_irq_handler(irq, desc, status);
  }
  
  static void nmk_gpio_secondary_irq_handler(unsigned int irq,
  					   struct irq_desc *desc)
  {
6845664a6   Thomas Gleixner   arm: Cleanup the ...
724
  	struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
33b744b35   Rabin Vincent   plat-nomadik: sup...
725
726
727
728
  	u32 status = nmk_chip->get_secondary_status(nmk_chip->bank);
  
  	__nmk_gpio_irq_handler(irq, desc, status);
  }
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
729
730
731
732
733
734
  static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
  {
  	unsigned int first_irq;
  	int i;
  
  	first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
e493e06fe   Rabin Vincent   plat-nomadik: sup...
735
  	for (i = first_irq; i < first_irq + nmk_chip->chip.ngpio; i++) {
f38c02f3b   Thomas Gleixner   arm: Fold irq_set...
736
737
  		irq_set_chip_and_handler(i, &nmk_gpio_irq_chip,
  					 handle_edge_irq);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
738
  		set_irq_flags(i, IRQF_VALID);
6845664a6   Thomas Gleixner   arm: Cleanup the ...
739
740
  		irq_set_chip_data(i, nmk_chip);
  		irq_set_irq_type(i, IRQ_TYPE_EDGE_FALLING);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
741
  	}
33b744b35   Rabin Vincent   plat-nomadik: sup...
742

6845664a6   Thomas Gleixner   arm: Cleanup the ...
743
744
  	irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
  	irq_set_handler_data(nmk_chip->parent_irq, nmk_chip);
33b744b35   Rabin Vincent   plat-nomadik: sup...
745
746
  
  	if (nmk_chip->secondary_parent_irq >= 0) {
6845664a6   Thomas Gleixner   arm: Cleanup the ...
747
  		irq_set_chained_handler(nmk_chip->secondary_parent_irq,
33b744b35   Rabin Vincent   plat-nomadik: sup...
748
  					nmk_gpio_secondary_irq_handler);
6845664a6   Thomas Gleixner   arm: Cleanup the ...
749
  		irq_set_handler_data(nmk_chip->secondary_parent_irq, nmk_chip);
33b744b35   Rabin Vincent   plat-nomadik: sup...
750
  	}
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
751
752
753
754
755
756
757
758
  	return 0;
  }
  
  /* I/O Functions */
  static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
  {
  	struct nmk_gpio_chip *nmk_chip =
  		container_of(chip, struct nmk_gpio_chip, chip);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
759
  	clk_enable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
760
  	writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
761
762
  
  	clk_disable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
763
764
  	return 0;
  }
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
765
766
767
768
769
  static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
  {
  	struct nmk_gpio_chip *nmk_chip =
  		container_of(chip, struct nmk_gpio_chip, chip);
  	u32 bit = 1 << offset;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
770
771
772
  	int value;
  
  	clk_enable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
773

3c0227d26   Rabin Vincent   gpio/nomadik: dis...
774
  	value = (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
775

3c0227d26   Rabin Vincent   gpio/nomadik: dis...
776
777
778
  	clk_disable(nmk_chip->clk);
  
  	return value;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
779
780
781
782
783
784
785
  }
  
  static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
  				int val)
  {
  	struct nmk_gpio_chip *nmk_chip =
  		container_of(chip, struct nmk_gpio_chip, chip);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
786

3c0227d26   Rabin Vincent   gpio/nomadik: dis...
787
  	clk_enable(nmk_chip->clk);
6720db7cc   Rabin Vincent   ARM: 6354/1: noma...
788
  	__nmk_gpio_set_output(nmk_chip, offset, val);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
789
790
  
  	clk_disable(nmk_chip->clk);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
791
  }
6647c6c0b   Rabin Vincent   ARM: 6147/1: noma...
792
793
794
795
796
  static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
  				int val)
  {
  	struct nmk_gpio_chip *nmk_chip =
  		container_of(chip, struct nmk_gpio_chip, chip);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
797
  	clk_enable(nmk_chip->clk);
6720db7cc   Rabin Vincent   ARM: 6354/1: noma...
798
  	__nmk_gpio_make_output(nmk_chip, offset, val);
6647c6c0b   Rabin Vincent   ARM: 6147/1: noma...
799

3c0227d26   Rabin Vincent   gpio/nomadik: dis...
800
  	clk_disable(nmk_chip->clk);
6647c6c0b   Rabin Vincent   ARM: 6147/1: noma...
801
802
  	return 0;
  }
0d2aec9cd   Rabin Vincent   ARM: 6176/1: noma...
803
804
805
806
807
808
809
  static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
  {
  	struct nmk_gpio_chip *nmk_chip =
  		container_of(chip, struct nmk_gpio_chip, chip);
  
  	return NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base) + offset;
  }
d0b543c77   Rabin Vincent   plat-nomadik: add...
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
  #ifdef CONFIG_DEBUG_FS
  
  #include <linux/seq_file.h>
  
  static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
  {
  	int mode;
  	unsigned		i;
  	unsigned		gpio = chip->base;
  	int			is_out;
  	struct nmk_gpio_chip *nmk_chip =
  		container_of(chip, struct nmk_gpio_chip, chip);
  	const char *modes[] = {
  		[NMK_GPIO_ALT_GPIO]	= "gpio",
  		[NMK_GPIO_ALT_A]	= "altA",
  		[NMK_GPIO_ALT_B]	= "altB",
  		[NMK_GPIO_ALT_C]	= "altC",
  	};
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
828
  	clk_enable(nmk_chip->clk);
d0b543c77   Rabin Vincent   plat-nomadik: add...
829
830
831
832
  	for (i = 0; i < chip->ngpio; i++, gpio++) {
  		const char *label = gpiochip_is_requested(chip, i);
  		bool pull;
  		u32 bit = 1 << i;
d0b543c77   Rabin Vincent   plat-nomadik: add...
833
834
835
836
  		is_out = readl(nmk_chip->addr + NMK_GPIO_DIR) & bit;
  		pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
  		mode = nmk_gpio_get_mode(gpio);
  		seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
8ea72a30a   Rabin Vincent   gpio/nomadik: sho...
837
  			gpio, label ?: "(none)",
d0b543c77   Rabin Vincent   plat-nomadik: add...
838
839
840
841
842
843
  			is_out ? "out" : "in ",
  			chip->get
  				? (chip->get(chip, i) ? "hi" : "lo")
  				: "?  ",
  			(mode < 0) ? "unknown" : modes[mode],
  			pull ? "pull" : "none");
8ea72a30a   Rabin Vincent   gpio/nomadik: sho...
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
  
  		if (label && !is_out) {
  			int		irq = gpio_to_irq(gpio);
  			struct irq_desc	*desc = irq_to_desc(irq);
  
  			/* This races with request_irq(), set_irq_type(),
  			 * and set_irq_wake() ... but those are "rare".
  			 */
  			if (irq >= 0 && desc->action) {
  				char *trigger;
  				u32 bitmask = nmk_gpio_get_bitmask(gpio);
  
  				if (nmk_chip->edge_rising & bitmask)
  					trigger = "edge-rising";
  				else if (nmk_chip->edge_falling & bitmask)
  					trigger = "edge-falling";
  				else
  					trigger = "edge-undefined";
  
  				seq_printf(s, " irq-%d %s%s",
  					irq, trigger,
  					irqd_is_wakeup_set(&desc->irq_data)
  						? " wakeup" : "");
  			}
  		}
d0b543c77   Rabin Vincent   plat-nomadik: add...
869
870
871
  		seq_printf(s, "
  ");
  	}
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
872
873
  
  	clk_disable(nmk_chip->clk);
d0b543c77   Rabin Vincent   plat-nomadik: add...
874
875
876
877
878
  }
  
  #else
  #define nmk_gpio_dbg_show	NULL
  #endif
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
879
880
881
882
883
884
  /* This structure is replicated for each GPIO block allocated at probe time */
  static struct gpio_chip nmk_gpio_template = {
  	.direction_input	= nmk_gpio_make_input,
  	.get			= nmk_gpio_get_input,
  	.direction_output	= nmk_gpio_make_output,
  	.set			= nmk_gpio_set_output,
0d2aec9cd   Rabin Vincent   ARM: 6176/1: noma...
885
  	.to_irq			= nmk_gpio_to_irq,
d0b543c77   Rabin Vincent   plat-nomadik: add...
886
  	.dbg_show		= nmk_gpio_dbg_show,
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
887
888
  	.can_sleep		= 0,
  };
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  void nmk_gpio_clocks_enable(void)
  {
  	int i;
  
  	for (i = 0; i < NUM_BANKS; i++) {
  		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
  
  		if (!chip)
  			continue;
  
  		clk_enable(chip->clk);
  	}
  }
  
  void nmk_gpio_clocks_disable(void)
  {
  	int i;
  
  	for (i = 0; i < NUM_BANKS; i++) {
  		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
  
  		if (!chip)
  			continue;
  
  		clk_disable(chip->clk);
  	}
  }
b9df468d8   Rabin Vincent   plat-nomadik: mak...
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
  /*
   * Called from the suspend/resume path to only keep the real wakeup interrupts
   * (those that have had set_irq_wake() called on them) as wakeup interrupts,
   * and not the rest of the interrupts which we needed to have as wakeups for
   * cpuidle.
   *
   * PM ops are not used since this needs to be done at the end, after all the
   * other drivers are done with their suspend callbacks.
   */
  void nmk_gpio_wakeups_suspend(void)
  {
  	int i;
  
  	for (i = 0; i < NUM_BANKS; i++) {
  		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
  
  		if (!chip)
  			break;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
934
  		clk_enable(chip->clk);
b9df468d8   Rabin Vincent   plat-nomadik: mak...
935
936
937
938
939
940
941
  		chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC);
  		chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC);
  
  		writel(chip->rwimsc & chip->real_wake,
  		       chip->addr + NMK_GPIO_RWIMSC);
  		writel(chip->fwimsc & chip->real_wake,
  		       chip->addr + NMK_GPIO_FWIMSC);
33d78647d   Linus Walleij   gpio/nomadik: fix...
942
  		if (chip->sleepmode) {
b9df468d8   Rabin Vincent   plat-nomadik: mak...
943
944
945
946
947
  			chip->slpm = readl(chip->addr + NMK_GPIO_SLPC);
  
  			/* 0 -> wakeup enable */
  			writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC);
  		}
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
948
949
  
  		clk_disable(chip->clk);
b9df468d8   Rabin Vincent   plat-nomadik: mak...
950
951
952
953
954
955
956
957
958
959
960
961
  	}
  }
  
  void nmk_gpio_wakeups_resume(void)
  {
  	int i;
  
  	for (i = 0; i < NUM_BANKS; i++) {
  		struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
  
  		if (!chip)
  			break;
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
962
  		clk_enable(chip->clk);
b9df468d8   Rabin Vincent   plat-nomadik: mak...
963
964
  		writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
  		writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
33d78647d   Linus Walleij   gpio/nomadik: fix...
965
  		if (chip->sleepmode)
b9df468d8   Rabin Vincent   plat-nomadik: mak...
966
  			writel(chip->slpm, chip->addr + NMK_GPIO_SLPC);
3c0227d26   Rabin Vincent   gpio/nomadik: dis...
967
968
  
  		clk_disable(chip->clk);
b9df468d8   Rabin Vincent   plat-nomadik: mak...
969
970
  	}
  }
bc6f5cf64   Rickard Andersson   gpio/nomadik: add...
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
  /*
   * Read the pull up/pull down status.
   * A bit set in 'pull_up' means that pull up
   * is selected if pull is enabled in PDIS register.
   * Note: only pull up/down set via this driver can
   * be detected due to HW limitations.
   */
  void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
  {
  	if (gpio_bank < NUM_BANKS) {
  		struct nmk_gpio_chip *chip = nmk_gpio_chips[gpio_bank];
  
  		if (!chip)
  			return;
  
  		*pull_up = chip->pull_up;
  	}
  }
fd0d67d62   Uwe Kleine-König   ARM: 6347/2: noma...
989
  static int __devinit nmk_gpio_probe(struct platform_device *dev)
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
990
  {
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
991
  	struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
992
993
  	struct nmk_gpio_chip *nmk_chip;
  	struct gpio_chip *chip;
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
994
  	struct resource *res;
af7dc2281   Rabin Vincent   ARM: 6104/1: noma...
995
  	struct clk *clk;
33b744b35   Rabin Vincent   plat-nomadik: sup...
996
  	int secondary_irq;
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
997
  	int irq;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
998
  	int ret;
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
  	if (!pdata)
  		return -ENODEV;
  
  	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
  	if (!res) {
  		ret = -ENOENT;
  		goto out;
  	}
  
  	irq = platform_get_irq(dev, 0);
  	if (irq < 0) {
  		ret = irq;
  		goto out;
  	}
33b744b35   Rabin Vincent   plat-nomadik: sup...
1013
1014
1015
1016
1017
  	secondary_irq = platform_get_irq(dev, 1);
  	if (secondary_irq >= 0 && !pdata->get_secondary_status) {
  		ret = -EINVAL;
  		goto out;
  	}
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
1018
1019
1020
1021
1022
  	if (request_mem_region(res->start, resource_size(res),
  			       dev_name(&dev->dev)) == NULL) {
  		ret = -EBUSY;
  		goto out;
  	}
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1023

af7dc2281   Rabin Vincent   ARM: 6104/1: noma...
1024
1025
1026
1027
1028
  	clk = clk_get(&dev->dev, NULL);
  	if (IS_ERR(clk)) {
  		ret = PTR_ERR(clk);
  		goto out_release;
  	}
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1029
1030
1031
  	nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
  	if (!nmk_chip) {
  		ret = -ENOMEM;
af7dc2281   Rabin Vincent   ARM: 6104/1: noma...
1032
  		goto out_clk;
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1033
1034
1035
1036
1037
  	}
  	/*
  	 * The virt address in nmk_chip->addr is in the nomadik register space,
  	 * so we can simply convert the resource address, without remapping
  	 */
33b744b35   Rabin Vincent   plat-nomadik: sup...
1038
  	nmk_chip->bank = dev->id;
af7dc2281   Rabin Vincent   ARM: 6104/1: noma...
1039
  	nmk_chip->clk = clk;
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
1040
  	nmk_chip->addr = io_p2v(res->start);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1041
  	nmk_chip->chip = nmk_gpio_template;
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
1042
  	nmk_chip->parent_irq = irq;
33b744b35   Rabin Vincent   plat-nomadik: sup...
1043
1044
  	nmk_chip->secondary_parent_irq = secondary_irq;
  	nmk_chip->get_secondary_status = pdata->get_secondary_status;
01727e61f   Rabin Vincent   plat-nomadik: imp...
1045
  	nmk_chip->set_ioforce = pdata->set_ioforce;
33d78647d   Linus Walleij   gpio/nomadik: fix...
1046
  	nmk_chip->sleepmode = pdata->supports_sleepmode;
c0fcb8dba   Rabin Vincent   ARM: 5970/1: noma...
1047
  	spin_lock_init(&nmk_chip->lock);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1048
1049
1050
  
  	chip = &nmk_chip->chip;
  	chip->base = pdata->first_gpio;
e493e06fe   Rabin Vincent   plat-nomadik: sup...
1051
  	chip->ngpio = pdata->num_gpio;
8d568ae53   Rabin Vincent   nomadik-gpio: use...
1052
  	chip->label = pdata->name ?: dev_name(&dev->dev);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1053
1054
1055
1056
1057
1058
  	chip->dev = &dev->dev;
  	chip->owner = THIS_MODULE;
  
  	ret = gpiochip_add(&nmk_chip->chip);
  	if (ret)
  		goto out_free;
01727e61f   Rabin Vincent   plat-nomadik: imp...
1059
1060
1061
  	BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips));
  
  	nmk_gpio_chips[nmk_chip->bank] = nmk_chip;
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
1062
  	platform_set_drvdata(dev, nmk_chip);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1063
1064
  
  	nmk_gpio_init_irq(nmk_chip);
64842aad5   Grant Likely   gpiolib: output b...
1065
1066
1067
  	dev_info(&dev->dev, "at address %p
  ",
  		 nmk_chip->addr);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1068
  	return 0;
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
1069
  out_free:
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1070
  	kfree(nmk_chip);
af7dc2281   Rabin Vincent   ARM: 6104/1: noma...
1071
1072
1073
  out_clk:
  	clk_disable(clk);
  	clk_put(clk);
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
1074
1075
1076
  out_release:
  	release_mem_region(res->start, resource_size(res));
  out:
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1077
1078
1079
1080
1081
  	dev_err(&dev->dev, "Failure %i for GPIO %i-%i
  ", ret,
  		  pdata->first_gpio, pdata->first_gpio+31);
  	return ret;
  }
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
1082
1083
  static struct platform_driver nmk_gpio_driver = {
  	.driver = {
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1084
1085
  		.owner = THIS_MODULE,
  		.name = "gpio",
5317e4d11   Rabin Vincent   plat-nomadik: get...
1086
  	},
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1087
  	.probe = nmk_gpio_probe,
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1088
1089
1090
1091
  };
  
  static int __init nmk_gpio_init(void)
  {
3e3c62ca5   Rabin Vincent   ARM: 5972/1: noma...
1092
  	return platform_driver_register(&nmk_gpio_driver);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1093
  }
33f45ea91   Rabin Vincent   ARM: 6156/1: noma...
1094
  core_initcall(nmk_gpio_init);
2ec1d3594   Alessandro Rubini   [ARM] 5584/1: nom...
1095
1096
1097
1098
  
  MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini");
  MODULE_DESCRIPTION("Nomadik GPIO Driver");
  MODULE_LICENSE("GPL");