Blame view

drivers/gpio/gpio-tegra.c 11.5 KB
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   * arch/arm/mach-tegra/gpio.c
   *
   * Copyright (c) 2010 Google, Inc
   *
   * Author:
   *	Erik Gilling <konkers@google.com>
   *
   * This software is licensed under the terms of the GNU General Public
   * License version 2, as published by the Free Software Foundation, and
   * may be copied, distributed, and modified under those terms.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   */
  
  #include <linux/init.h>
  #include <linux/irq.h>
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
22
  #include <linux/interrupt.h>
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
23
24
  #include <linux/io.h>
  #include <linux/gpio.h>
df2212270   Grant Likely   gpio/tegra: add d...
25
  #include <linux/of.h>
88d8951e5   Stephen Warren   gpio/tegra: Conve...
26
27
  #include <linux/platform_device.h>
  #include <linux/module.h>
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
28

98022940c   Will Deacon   ARM: tegra: updat...
29
  #include <asm/mach/irq.h>
ea5abbd21   Stephen Warren   ARM: 7101/1: arm/...
30
  #include <mach/gpio-tegra.h>
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
31
  #include <mach/iomap.h>
2ea67fd14   Colin Cross   ARM: tegra: Add p...
32
  #include <mach/suspend.h>
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
33
34
35
36
  
  #define GPIO_BANK(x)		((x) >> 5)
  #define GPIO_PORT(x)		(((x) >> 3) & 0x3)
  #define GPIO_BIT(x)		((x) & 0x7)
88d8951e5   Stephen Warren   gpio/tegra: Conve...
37
  #define GPIO_REG(x)		(GPIO_BANK(x) * 0x80 + GPIO_PORT(x) * 4)
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  
  #define GPIO_CNF(x)		(GPIO_REG(x) + 0x00)
  #define GPIO_OE(x)		(GPIO_REG(x) + 0x10)
  #define GPIO_OUT(x)		(GPIO_REG(x) + 0X20)
  #define GPIO_IN(x)		(GPIO_REG(x) + 0x30)
  #define GPIO_INT_STA(x)		(GPIO_REG(x) + 0x40)
  #define GPIO_INT_ENB(x)		(GPIO_REG(x) + 0x50)
  #define GPIO_INT_LVL(x)		(GPIO_REG(x) + 0x60)
  #define GPIO_INT_CLR(x)		(GPIO_REG(x) + 0x70)
  
  #define GPIO_MSK_CNF(x)		(GPIO_REG(x) + 0x800)
  #define GPIO_MSK_OE(x)		(GPIO_REG(x) + 0x810)
  #define GPIO_MSK_OUT(x)		(GPIO_REG(x) + 0X820)
  #define GPIO_MSK_INT_STA(x)	(GPIO_REG(x) + 0x840)
  #define GPIO_MSK_INT_ENB(x)	(GPIO_REG(x) + 0x850)
  #define GPIO_MSK_INT_LVL(x)	(GPIO_REG(x) + 0x860)
  
  #define GPIO_INT_LVL_MASK		0x010101
  #define GPIO_INT_LVL_EDGE_RISING	0x000101
  #define GPIO_INT_LVL_EDGE_FALLING	0x000100
  #define GPIO_INT_LVL_EDGE_BOTH		0x010100
  #define GPIO_INT_LVL_LEVEL_HIGH		0x000001
  #define GPIO_INT_LVL_LEVEL_LOW		0x000000
  
  struct tegra_gpio_bank {
  	int bank;
  	int irq;
  	spinlock_t lvl_lock[4];
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
66
67
68
69
70
71
72
  #ifdef CONFIG_PM
  	u32 cnf[4];
  	u32 out[4];
  	u32 oe[4];
  	u32 int_enb[4];
  	u32 int_lvl[4];
  #endif
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
73
  };
88d8951e5   Stephen Warren   gpio/tegra: Conve...
74
75
76
77
78
79
80
81
82
83
84
85
  static void __iomem *regs;
  static struct tegra_gpio_bank tegra_gpio_banks[7];
  
  static inline void tegra_gpio_writel(u32 val, u32 reg)
  {
  	__raw_writel(val, regs + reg);
  }
  
  static inline u32 tegra_gpio_readl(u32 reg)
  {
  	return __raw_readl(regs + reg);
  }
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
86
87
88
89
90
91
92
93
94
95
96
97
98
  
  static int tegra_gpio_compose(int bank, int port, int bit)
  {
  	return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7);
  }
  
  static void tegra_gpio_mask_write(u32 reg, int gpio, int value)
  {
  	u32 val;
  
  	val = 0x100 << GPIO_BIT(gpio);
  	if (value)
  		val |= 1 << GPIO_BIT(gpio);
88d8951e5   Stephen Warren   gpio/tegra: Conve...
99
  	tegra_gpio_writel(val, reg);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  }
  
  void tegra_gpio_enable(int gpio)
  {
  	tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
  }
  
  void tegra_gpio_disable(int gpio)
  {
  	tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
  }
  
  static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  {
  	tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value);
  }
  
  static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
  {
88d8951e5   Stephen Warren   gpio/tegra: Conve...
119
  	return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1;
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  }
  
  static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
  {
  	tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
  	return 0;
  }
  
  static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
  					int value)
  {
  	tegra_gpio_set(chip, offset, value);
  	tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
  	return 0;
  }
438a99c07   Stephen Warren   ARM: 7053/1: gpio...
135
136
137
138
  static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
  {
  	return TEGRA_GPIO_TO_IRQ(offset);
  }
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
139
140
141
142
143
144
145
  
  static struct gpio_chip tegra_gpio_chip = {
  	.label			= "tegra-gpio",
  	.direction_input	= tegra_gpio_direction_input,
  	.get			= tegra_gpio_get,
  	.direction_output	= tegra_gpio_direction_output,
  	.set			= tegra_gpio_set,
438a99c07   Stephen Warren   ARM: 7053/1: gpio...
146
  	.to_irq			= tegra_gpio_to_irq,
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
147
  	.base			= 0,
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
148
  	.ngpio			= TEGRA_NR_GPIOS,
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
149
  };
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
150
  static void tegra_gpio_irq_ack(struct irq_data *d)
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
151
  {
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
152
  	int gpio = d->irq - INT_GPIO_BASE;
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
153

88d8951e5   Stephen Warren   gpio/tegra: Conve...
154
  	tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
155
  }
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
156
  static void tegra_gpio_irq_mask(struct irq_data *d)
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
157
  {
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
158
  	int gpio = d->irq - INT_GPIO_BASE;
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
159
160
161
  
  	tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0);
  }
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
162
  static void tegra_gpio_irq_unmask(struct irq_data *d)
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
163
  {
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
164
  	int gpio = d->irq - INT_GPIO_BASE;
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
165
166
167
  
  	tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1);
  }
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
168
  static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
169
  {
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
170
171
  	int gpio = d->irq - INT_GPIO_BASE;
  	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  	int port = GPIO_PORT(gpio);
  	int lvl_type;
  	int val;
  	unsigned long flags;
  
  	switch (type & IRQ_TYPE_SENSE_MASK) {
  	case IRQ_TYPE_EDGE_RISING:
  		lvl_type = GPIO_INT_LVL_EDGE_RISING;
  		break;
  
  	case IRQ_TYPE_EDGE_FALLING:
  		lvl_type = GPIO_INT_LVL_EDGE_FALLING;
  		break;
  
  	case IRQ_TYPE_EDGE_BOTH:
  		lvl_type = GPIO_INT_LVL_EDGE_BOTH;
  		break;
  
  	case IRQ_TYPE_LEVEL_HIGH:
  		lvl_type = GPIO_INT_LVL_LEVEL_HIGH;
  		break;
  
  	case IRQ_TYPE_LEVEL_LOW:
  		lvl_type = GPIO_INT_LVL_LEVEL_LOW;
  		break;
  
  	default:
  		return -EINVAL;
  	}
  
  	spin_lock_irqsave(&bank->lvl_lock[port], flags);
88d8951e5   Stephen Warren   gpio/tegra: Conve...
203
  	val = tegra_gpio_readl(GPIO_INT_LVL(gpio));
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
204
205
  	val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio));
  	val |= lvl_type << GPIO_BIT(gpio);
88d8951e5   Stephen Warren   gpio/tegra: Conve...
206
  	tegra_gpio_writel(val, GPIO_INT_LVL(gpio));
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
207
208
209
210
  
  	spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
  
  	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
6845664a6   Thomas Gleixner   arm: Cleanup the ...
211
  		__irq_set_handler_locked(d->irq, handle_level_irq);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
212
  	else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
6845664a6   Thomas Gleixner   arm: Cleanup the ...
213
  		__irq_set_handler_locked(d->irq, handle_edge_irq);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
214
215
216
217
218
219
220
221
222
223
  
  	return 0;
  }
  
  static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
  {
  	struct tegra_gpio_bank *bank;
  	int port;
  	int pin;
  	int unmasked = 0;
98022940c   Will Deacon   ARM: tegra: updat...
224
  	struct irq_chip *chip = irq_desc_get_chip(desc);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
225

98022940c   Will Deacon   ARM: tegra: updat...
226
  	chained_irq_enter(chip, desc);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
227

6845664a6   Thomas Gleixner   arm: Cleanup the ...
228
  	bank = irq_get_handler_data(irq);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
229
230
231
  
  	for (port = 0; port < 4; port++) {
  		int gpio = tegra_gpio_compose(bank->bank, port, 0);
88d8951e5   Stephen Warren   gpio/tegra: Conve...
232
233
234
  		unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) &
  			tegra_gpio_readl(GPIO_INT_ENB(gpio));
  		u32 lvl = tegra_gpio_readl(GPIO_INT_LVL(gpio));
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
235
236
  
  		for_each_set_bit(pin, &sta, 8) {
88d8951e5   Stephen Warren   gpio/tegra: Conve...
237
  			tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio));
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
238
239
240
241
242
243
244
  
  			/* if gpio is edge triggered, clear condition
  			 * before executing the hander so that we don't
  			 * miss edges
  			 */
  			if (lvl & (0x100 << pin)) {
  				unmasked = 1;
98022940c   Will Deacon   ARM: tegra: updat...
245
  				chained_irq_exit(chip, desc);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
246
247
248
249
250
251
252
  			}
  
  			generic_handle_irq(gpio_to_irq(gpio + pin));
  		}
  	}
  
  	if (!unmasked)
98022940c   Will Deacon   ARM: tegra: updat...
253
  		chained_irq_exit(chip, desc);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
254
255
  
  }
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
256
257
258
259
  #ifdef CONFIG_PM
  void tegra_gpio_resume(void)
  {
  	unsigned long flags;
c8309ef6a   Colin Cross   ARM: tegra: gpio:...
260
261
  	int b;
  	int p;
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
262
263
264
265
266
267
268
269
  
  	local_irq_save(flags);
  
  	for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
  		struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
  
  		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
  			unsigned int gpio = (b<<5) | (p<<3);
88d8951e5   Stephen Warren   gpio/tegra: Conve...
270
271
272
273
274
  			tegra_gpio_writel(bank->cnf[p], GPIO_CNF(gpio));
  			tegra_gpio_writel(bank->out[p], GPIO_OUT(gpio));
  			tegra_gpio_writel(bank->oe[p], GPIO_OE(gpio));
  			tegra_gpio_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio));
  			tegra_gpio_writel(bank->int_enb[p], GPIO_INT_ENB(gpio));
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
275
276
277
278
  		}
  	}
  
  	local_irq_restore(flags);
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
279
280
281
282
283
  }
  
  void tegra_gpio_suspend(void)
  {
  	unsigned long flags;
c8309ef6a   Colin Cross   ARM: tegra: gpio:...
284
285
  	int b;
  	int p;
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
286

2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
287
288
289
290
291
292
  	local_irq_save(flags);
  	for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
  		struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
  
  		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
  			unsigned int gpio = (b<<5) | (p<<3);
88d8951e5   Stephen Warren   gpio/tegra: Conve...
293
294
295
296
297
  			bank->cnf[p] = tegra_gpio_readl(GPIO_CNF(gpio));
  			bank->out[p] = tegra_gpio_readl(GPIO_OUT(gpio));
  			bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio));
  			bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio));
  			bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio));
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
298
299
300
301
  		}
  	}
  	local_irq_restore(flags);
  }
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
302
  static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable)
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
303
  {
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
304
  	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
6845664a6   Thomas Gleixner   arm: Cleanup the ...
305
  	return irq_set_irq_wake(bank->irq, enable);
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
306
307
  }
  #endif
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
308
309
310
  
  static struct irq_chip tegra_gpio_irq_chip = {
  	.name		= "GPIO",
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
311
312
313
314
  	.irq_ack	= tegra_gpio_irq_ack,
  	.irq_mask	= tegra_gpio_irq_mask,
  	.irq_unmask	= tegra_gpio_irq_unmask,
  	.irq_set_type	= tegra_gpio_irq_set_type,
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
315
  #ifdef CONFIG_PM
37337a8d5   Lennert Buytenhek   ARM: tegra: irq_d...
316
  	.irq_set_wake	= tegra_gpio_wake_enable,
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
317
  #endif
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
318
319
320
321
322
323
324
  };
  
  
  /* This lock class tells lockdep that GPIO irqs are in a different
   * category than their parents, so it won't report false recursion.
   */
  static struct lock_class_key gpio_lock_class;
88d8951e5   Stephen Warren   gpio/tegra: Conve...
325
  static int __devinit tegra_gpio_probe(struct platform_device *pdev)
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
326
  {
88d8951e5   Stephen Warren   gpio/tegra: Conve...
327
  	struct resource *res;
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
328
  	struct tegra_gpio_bank *bank;
470080015   Stephen Warren   ARM: 7052/1: gpio...
329
  	int gpio;
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
330
331
  	int i;
  	int j;
88d8951e5   Stephen Warren   gpio/tegra: Conve...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
  	for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
  		res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
  		if (!res) {
  			dev_err(&pdev->dev, "Missing IRQ resource
  ");
  			return -ENODEV;
  		}
  
  		bank = &tegra_gpio_banks[i];
  		bank->bank = i;
  		bank->irq = res->start;
  	}
  
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!res) {
  		dev_err(&pdev->dev, "Missing MEM resource
  ");
  		return -ENODEV;
  	}
aedd4fdf6   Julia Lawall   drivers/gpio/gpio...
351
  	regs = devm_request_and_ioremap(&pdev->dev, res);
88d8951e5   Stephen Warren   gpio/tegra: Conve...
352
353
354
355
356
  	if (!regs) {
  		dev_err(&pdev->dev, "Couldn't ioremap regs
  ");
  		return -ENODEV;
  	}
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
357
358
359
  	for (i = 0; i < 7; i++) {
  		for (j = 0; j < 4; j++) {
  			int gpio = tegra_gpio_compose(i, j, 0);
88d8951e5   Stephen Warren   gpio/tegra: Conve...
360
  			tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio));
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
361
362
  		}
  	}
df2212270   Grant Likely   gpio/tegra: add d...
363
  #ifdef CONFIG_OF_GPIO
88d8951e5   Stephen Warren   gpio/tegra: Conve...
364
365
  	tegra_gpio_chip.of_node = pdev->dev.of_node;
  #endif
df2212270   Grant Likely   gpio/tegra: add d...
366

3c92db9ac   Erik Gilling   [ARM] tegra: add ...
367
  	gpiochip_add(&tegra_gpio_chip);
470080015   Stephen Warren   ARM: 7052/1: gpio...
368
369
370
  	for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) {
  		int irq = TEGRA_GPIO_TO_IRQ(gpio);
  		/* No validity check; all Tegra GPIOs are valid IRQs */
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
371

470080015   Stephen Warren   ARM: 7052/1: gpio...
372
  		bank = &tegra_gpio_banks[GPIO_BANK(gpio)];
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
373

470080015   Stephen Warren   ARM: 7052/1: gpio...
374
375
376
  		irq_set_lockdep_class(irq, &gpio_lock_class);
  		irq_set_chip_data(irq, bank);
  		irq_set_chip_and_handler(irq, &tegra_gpio_irq_chip,
f38c02f3b   Thomas Gleixner   arm: Fold irq_set...
377
  					 handle_simple_irq);
470080015   Stephen Warren   ARM: 7052/1: gpio...
378
  		set_irq_flags(irq, IRQF_VALID);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
379
380
381
382
  	}
  
  	for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
  		bank = &tegra_gpio_banks[i];
6845664a6   Thomas Gleixner   arm: Cleanup the ...
383
384
  		irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler);
  		irq_set_handler_data(bank->irq, bank);
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
385
386
387
388
389
390
391
  
  		for (j = 0; j < 4; j++)
  			spin_lock_init(&bank->lvl_lock[j]);
  	}
  
  	return 0;
  }
88d8951e5   Stephen Warren   gpio/tegra: Conve...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  static struct of_device_id tegra_gpio_of_match[] __devinitdata = {
  	{ .compatible = "nvidia,tegra20-gpio", },
  	{ },
  };
  
  static struct platform_driver tegra_gpio_driver = {
  	.driver		= {
  		.name	= "tegra-gpio",
  		.owner	= THIS_MODULE,
  		.of_match_table = tegra_gpio_of_match,
  	},
  	.probe		= tegra_gpio_probe,
  };
  
  static int __init tegra_gpio_init(void)
  {
  	return platform_driver_register(&tegra_gpio_driver);
  }
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
410
  postcore_initcall(tegra_gpio_init);
632095ea1   Olof Johansson   ARM: tegra: add t...
411
412
413
414
415
416
417
418
419
420
421
422
423
  void __init tegra_gpio_config(struct tegra_gpio_table *table, int num)
  {
  	int i;
  
  	for (i = 0; i < num; i++) {
  		int gpio = table[i].gpio;
  
  		if (table[i].enable)
  			tegra_gpio_enable(gpio);
  		else
  			tegra_gpio_disable(gpio);
  	}
  }
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
424
425
426
427
428
429
430
431
432
433
434
435
436
  #ifdef	CONFIG_DEBUG_FS
  
  #include <linux/debugfs.h>
  #include <linux/seq_file.h>
  
  static int dbg_gpio_show(struct seq_file *s, void *unused)
  {
  	int i;
  	int j;
  
  	for (i = 0; i < 7; i++) {
  		for (j = 0; j < 4; j++) {
  			int gpio = tegra_gpio_compose(i, j, 0);
2e47b8b3c   Colin Cross   [ARM] tegra: gpio...
437
438
439
440
  			seq_printf(s,
  				"%d:%d %02x %02x %02x %02x %02x %02x %06x
  ",
  				i, j,
88d8951e5   Stephen Warren   gpio/tegra: Conve...
441
442
443
444
445
446
447
  				tegra_gpio_readl(GPIO_CNF(gpio)),
  				tegra_gpio_readl(GPIO_OE(gpio)),
  				tegra_gpio_readl(GPIO_OUT(gpio)),
  				tegra_gpio_readl(GPIO_IN(gpio)),
  				tegra_gpio_readl(GPIO_INT_STA(gpio)),
  				tegra_gpio_readl(GPIO_INT_ENB(gpio)),
  				tegra_gpio_readl(GPIO_INT_LVL(gpio)));
3c92db9ac   Erik Gilling   [ARM] tegra: add ...
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
  		}
  	}
  	return 0;
  }
  
  static int dbg_gpio_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, dbg_gpio_show, &inode->i_private);
  }
  
  static const struct file_operations debug_fops = {
  	.open		= dbg_gpio_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
  
  static int __init tegra_gpio_debuginit(void)
  {
  	(void) debugfs_create_file("tegra_gpio", S_IRUGO,
  					NULL, NULL, &debug_fops);
  	return 0;
  }
  late_initcall(tegra_gpio_debuginit);
  #endif