Blame view

arch/mips/jz4740/gpio.c 13.5 KB
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
   *  JZ4740 platform GPIO support
   *
   *  This program is free software; you can redistribute it and/or modify it
   *  under  the terms of the GNU General  Public License as published by the
   *  Free Software Foundation;  either version 2 of the License, or (at your
   *  option) any later version.
   *
   *  You should have received a copy of the GNU General Public License along
   *  with this program; if not, write to the Free Software Foundation, Inc.,
   *  675 Mass Ave, Cambridge, MA 02139, USA.
   *
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
19
20
21
22
23
24
25
26
27
28
  #include <linux/io.h>
  #include <linux/gpio.h>
  #include <linux/delay.h>
  #include <linux/interrupt.h>
  #include <linux/bitops.h>
  
  #include <linux/debugfs.h>
  #include <linux/seq_file.h>
  
  #include <asm/mach-jz4740/base.h>
83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
29
  #include "irq.h"
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
30
31
32
33
34
35
36
37
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
66
67
68
69
70
71
72
73
74
75
76
  #define JZ4740_GPIO_BASE_A (32*0)
  #define JZ4740_GPIO_BASE_B (32*1)
  #define JZ4740_GPIO_BASE_C (32*2)
  #define JZ4740_GPIO_BASE_D (32*3)
  
  #define JZ4740_GPIO_NUM_A 32
  #define JZ4740_GPIO_NUM_B 32
  #define JZ4740_GPIO_NUM_C 31
  #define JZ4740_GPIO_NUM_D 32
  
  #define JZ4740_IRQ_GPIO_BASE_A (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_A)
  #define JZ4740_IRQ_GPIO_BASE_B (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_B)
  #define JZ4740_IRQ_GPIO_BASE_C (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_C)
  #define JZ4740_IRQ_GPIO_BASE_D (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_D)
  
  #define JZ_REG_GPIO_PIN			0x00
  #define JZ_REG_GPIO_DATA		0x10
  #define JZ_REG_GPIO_DATA_SET		0x14
  #define JZ_REG_GPIO_DATA_CLEAR		0x18
  #define JZ_REG_GPIO_MASK		0x20
  #define JZ_REG_GPIO_MASK_SET		0x24
  #define JZ_REG_GPIO_MASK_CLEAR		0x28
  #define JZ_REG_GPIO_PULL		0x30
  #define JZ_REG_GPIO_PULL_SET		0x34
  #define JZ_REG_GPIO_PULL_CLEAR		0x38
  #define JZ_REG_GPIO_FUNC		0x40
  #define JZ_REG_GPIO_FUNC_SET		0x44
  #define JZ_REG_GPIO_FUNC_CLEAR		0x48
  #define JZ_REG_GPIO_SELECT		0x50
  #define JZ_REG_GPIO_SELECT_SET		0x54
  #define JZ_REG_GPIO_SELECT_CLEAR	0x58
  #define JZ_REG_GPIO_DIRECTION		0x60
  #define JZ_REG_GPIO_DIRECTION_SET	0x64
  #define JZ_REG_GPIO_DIRECTION_CLEAR	0x68
  #define JZ_REG_GPIO_TRIGGER		0x70
  #define JZ_REG_GPIO_TRIGGER_SET		0x74
  #define JZ_REG_GPIO_TRIGGER_CLEAR	0x78
  #define JZ_REG_GPIO_FLAG		0x80
  #define JZ_REG_GPIO_FLAG_CLEAR		0x14
  
  #define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
  #define GPIO_TO_REG(gpio, reg) (gpio_to_jz_gpio_chip(gpio)->base + (reg))
  #define CHIP_TO_REG(chip, reg) (gpio_chip_to_jz_gpio_chip(chip)->base + (reg))
  
  struct jz_gpio_chip {
  	unsigned int irq;
  	unsigned int irq_base;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
77
78
79
  	uint32_t edge_trigger_both;
  
  	void __iomem *base;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
80
  	struct gpio_chip gpio_chip;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
81
82
83
84
85
86
87
88
89
90
91
92
93
  };
  
  static struct jz_gpio_chip jz4740_gpio_chips[];
  
  static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
  {
  	return &jz4740_gpio_chips[gpio >> 5];
  }
  
  static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gpio_chip)
  {
  	return container_of(gpio_chip, struct jz_gpio_chip, gpio_chip);
  }
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
94
  static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data)
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
95
  {
83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
96
97
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
  	return gc->private;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  }
  
  static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg)
  {
  	writel(GPIO_TO_BIT(gpio), GPIO_TO_REG(gpio, reg));
  }
  
  int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
  {
  	if (function == JZ_GPIO_FUNC_NONE) {
  		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_CLEAR);
  		jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
  		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
  	} else {
  		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_SET);
  		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
  		switch (function) {
  		case JZ_GPIO_FUNC1:
  			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
  			break;
  		case JZ_GPIO_FUNC3:
  			jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_SET);
  		case JZ_GPIO_FUNC2: /* Falltrough */
  			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_SET);
  			break;
  		default:
  			BUG();
  			break;
  		}
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(jz_gpio_set_function);
  
  int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num)
  {
  	size_t i;
  	int ret;
  
  	for (i = 0; i < num; ++i, ++request) {
  		ret = gpio_request(request->gpio, request->name);
  		if (ret)
  			goto err;
  		jz_gpio_set_function(request->gpio, request->function);
  	}
  
  	return 0;
  
  err:
  	for (--request; i > 0; --i, --request) {
  		gpio_free(request->gpio);
  		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(jz_gpio_bulk_request);
  
  void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num)
  {
  	size_t i;
  
  	for (i = 0; i < num; ++i, ++request) {
  		gpio_free(request->gpio);
  		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
  	}
  
  }
  EXPORT_SYMBOL_GPL(jz_gpio_bulk_free);
  
  void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num)
  {
  	size_t i;
  
  	for (i = 0; i < num; ++i, ++request) {
  		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
  		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_DIRECTION_CLEAR);
  		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_PULL_SET);
  	}
  }
  EXPORT_SYMBOL_GPL(jz_gpio_bulk_suspend);
  
  void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num)
  {
  	size_t i;
  
  	for (i = 0; i < num; ++i, ++request)
  		jz_gpio_set_function(request->gpio, request->function);
  }
  EXPORT_SYMBOL_GPL(jz_gpio_bulk_resume);
  
  void jz_gpio_enable_pullup(unsigned gpio)
  {
  	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_CLEAR);
  }
  EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup);
  
  void jz_gpio_disable_pullup(unsigned gpio)
  {
  	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_SET);
  }
  EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup);
  
  static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
  {
  	return !!(readl(CHIP_TO_REG(chip, JZ_REG_GPIO_PIN)) & BIT(gpio));
  }
  
  static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
  {
  	uint32_t __iomem *reg = CHIP_TO_REG(chip, JZ_REG_GPIO_DATA_SET);
  	reg += !value;
  	writel(BIT(gpio), reg);
  }
  
  static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
  	int value)
  {
  	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_SET));
  	jz_gpio_set_value(chip, gpio, value);
  
  	return 0;
  }
  
  static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
  {
  	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_CLEAR));
  
  	return 0;
  }
  
  int jz_gpio_port_direction_input(int port, uint32_t mask)
  {
  	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR));
  
  	return 0;
  }
  EXPORT_SYMBOL(jz_gpio_port_direction_input);
  
  int jz_gpio_port_direction_output(int port, uint32_t mask)
  {
  	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_SET));
  
  	return 0;
  }
  EXPORT_SYMBOL(jz_gpio_port_direction_output);
  
  void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask)
  {
  	writel(~value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_CLEAR));
  	writel(value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_SET));
  }
  EXPORT_SYMBOL(jz_gpio_port_set_value);
  
  uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
  {
  	uint32_t value = readl(GPIO_TO_REG(port, JZ_REG_GPIO_PIN));
  
  	return value & mask;
  }
  EXPORT_SYMBOL(jz_gpio_port_get_value);
  
  int gpio_to_irq(unsigned gpio)
  {
  	return JZ4740_IRQ_GPIO(0) + gpio;
  }
  EXPORT_SYMBOL_GPL(gpio_to_irq);
  
  int irq_to_gpio(unsigned irq)
  {
  	return irq - JZ4740_IRQ_GPIO(0);
  }
  EXPORT_SYMBOL_GPL(irq_to_gpio);
  
  #define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f)
  
  static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
  {
  	uint32_t value;
  	void __iomem *reg;
  	uint32_t mask = IRQ_TO_BIT(irq);
  
  	if (!(chip->edge_trigger_both & mask))
  		return;
  
  	reg = chip->base;
  
  	value = readl(chip->base + JZ_REG_GPIO_PIN);
  	if (value & mask)
  		reg += JZ_REG_GPIO_DIRECTION_CLEAR;
  	else
  		reg += JZ_REG_GPIO_DIRECTION_SET;
  
  	writel(mask, reg);
  }
  
  static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
  {
  	uint32_t flag;
  	unsigned int gpio_irq;
e4ec7989b   Thomas Gleixner   MIPS: Convert the...
299
  	struct jz_gpio_chip *chip = irq_desc_get_handler_data(desc);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
300

a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
301
  	flag = readl(chip->base + JZ_REG_GPIO_FLAG);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
302
303
  	if (!flag)
  		return;
fe5a8b7f0   Lars-Peter Clausen   MIPS: JZ4740: GPI...
304
  	gpio_irq = chip->irq_base + __fls(flag);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
305

933036386   Lars-Peter Clausen   MIPS: JZ4740: GPI...
306
  	jz_gpio_check_trigger_both(chip, gpio_irq);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
307

a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
308
309
  	generic_handle_irq(gpio_irq);
  };
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
310
  static inline void jz_gpio_set_irq_bit(struct irq_data *data, unsigned int reg)
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
311
  {
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
312
313
  	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
  	writel(IRQ_TO_BIT(data->irq), chip->base + reg);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
314
  }
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
315
  static void jz_gpio_irq_unmask(struct irq_data *data)
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
316
  {
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
317
  	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
318

42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
319
  	jz_gpio_check_trigger_both(chip, data->irq);
83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
320
  	irq_gc_unmask_enable_reg(data);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
321
322
323
  };
  
  /* TODO: Check if function is gpio */
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
324
  static unsigned int jz_gpio_irq_startup(struct irq_data *data)
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
325
  {
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
326
  	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_SET);
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
327
  	jz_gpio_irq_unmask(data);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
328
329
  	return 0;
  }
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
330
  static void jz_gpio_irq_shutdown(struct irq_data *data)
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
331
  {
83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
332
  	irq_gc_mask_disable_reg(data);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
333
334
  
  	/* Set direction to input */
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
335
336
  	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
  	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
337
  }
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
338
  static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
339
  {
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
340
  	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
341
  	unsigned int irq = data->irq;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
342

a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
343
344
345
346
347
348
349
350
351
352
353
354
355
  	if (flow_type == IRQ_TYPE_EDGE_BOTH) {
  		uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN);
  		if (value & IRQ_TO_BIT(irq))
  			flow_type = IRQ_TYPE_EDGE_FALLING;
  		else
  			flow_type = IRQ_TYPE_EDGE_RISING;
  		chip->edge_trigger_both |= IRQ_TO_BIT(irq);
  	} else {
  		chip->edge_trigger_both &= ~IRQ_TO_BIT(irq);
  	}
  
  	switch (flow_type) {
  	case IRQ_TYPE_EDGE_RISING:
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
356
357
  		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
  		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
358
359
  		break;
  	case IRQ_TYPE_EDGE_FALLING:
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
360
361
  		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
  		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
362
363
  		break;
  	case IRQ_TYPE_LEVEL_HIGH:
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
364
365
  		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
  		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
366
367
  		break;
  	case IRQ_TYPE_LEVEL_LOW:
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
368
369
  		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
  		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
370
371
372
373
  		break;
  	default:
  		return -EINVAL;
  	}
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
374
375
  	return 0;
  }
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
376
  static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
377
  {
42b64f388   Thomas Gleixner   MIPS: JZ4740: Con...
378
  	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
379

83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
380
  	irq_gc_set_wake(data, on);
e4ec7989b   Thomas Gleixner   MIPS: Convert the...
381
  	irq_set_irq_wake(chip->irq, on);
83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
382

a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
383
384
  	return 0;
  }
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
385
386
387
388
389
390
391
392
393
394
395
396
  #define JZ4740_GPIO_CHIP(_bank) { \
  	.irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \
  	.gpio_chip = { \
  		.label = "Bank " # _bank, \
  		.owner = THIS_MODULE, \
  		.set = jz_gpio_set_value, \
  		.get = jz_gpio_get_value, \
  		.direction_output = jz_gpio_direction_output, \
  		.direction_input = jz_gpio_direction_input, \
  		.base = JZ4740_GPIO_BASE_ ## _bank, \
  		.ngpio = JZ4740_GPIO_NUM_ ## _bank, \
  	}, \
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
397
398
399
400
401
402
403
404
  }
  
  static struct jz_gpio_chip jz4740_gpio_chips[] = {
  	JZ4740_GPIO_CHIP(A),
  	JZ4740_GPIO_CHIP(B),
  	JZ4740_GPIO_CHIP(C),
  	JZ4740_GPIO_CHIP(D),
  };
83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
405
  static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
406
  {
83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
407
408
  	struct irq_chip_generic *gc;
  	struct irq_chip_type *ct;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
409

83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
410
  	chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
411

83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
412
413
414
  	chip->irq = JZ4740_IRQ_INTC_GPIO(id);
  	irq_set_handler_data(chip->irq, chip);
  	irq_set_chained_handler(chip->irq, jz_gpio_irq_demux_handler);
bd7100099   Rafael J. Wysocki   MIPS: PM: Use str...
415

83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
416
417
  	gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base,
  		chip->base, handle_level_irq);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
418

83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
419
420
  	gc->wake_enabled = IRQ_MSK(chip->gpio_chip.ngpio);
  	gc->private = chip;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
421

83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
422
423
424
425
  	ct = gc->chip_types;
  	ct->regs.enable = JZ_REG_GPIO_MASK_CLEAR;
  	ct->regs.disable = JZ_REG_GPIO_MASK_SET;
  	ct->regs.ack = JZ_REG_GPIO_FLAG_CLEAR;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
426

83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
427
428
429
430
431
432
433
434
435
436
437
  	ct->chip.name = "GPIO";
  	ct->chip.irq_mask = irq_gc_mask_disable_reg;
  	ct->chip.irq_unmask = jz_gpio_irq_unmask;
  	ct->chip.irq_ack = irq_gc_ack_set_bit;
  	ct->chip.irq_suspend = jz4740_irq_suspend;
  	ct->chip.irq_resume = jz4740_irq_resume;
  	ct->chip.irq_startup = jz_gpio_irq_startup;
  	ct->chip.irq_shutdown = jz_gpio_irq_shutdown;
  	ct->chip.irq_set_type = jz_gpio_irq_set_type;
  	ct->chip.irq_set_wake = jz_gpio_irq_set_wake;
  	ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
438

83bc76920   Lars-Peter Clausen   MIPS: JZ4740: Use...
439
440
  	irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio),
  		IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
441
442
  
  	gpiochip_add(&chip->gpio_chip);
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
443
444
445
446
447
  }
  
  static int __init jz4740_gpio_init(void)
  {
  	unsigned int i;
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
448
449
450
  
  	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
  		jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
b595076a1   Uwe Kleine-König   tree-wide: fix co...
451
452
  	printk(KERN_INFO "JZ4740 GPIO initialized
  ");
a55f45066   Lars-Peter Clausen   MIPS: JZ4740: Add...
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  
  	return 0;
  }
  arch_initcall(jz4740_gpio_init);
  
  #ifdef CONFIG_DEBUG_FS
  
  static inline void gpio_seq_reg(struct seq_file *s, struct jz_gpio_chip *chip,
  	const char *name, unsigned int reg)
  {
  	seq_printf(s, "\t%s: %08x
  ", name, readl(chip->base + reg));
  }
  
  static int gpio_regs_show(struct seq_file *s, void *unused)
  {
  	struct jz_gpio_chip *chip = jz4740_gpio_chips;
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i, ++chip) {
  		seq_printf(s, "==GPIO %d==
  ", i);
  		gpio_seq_reg(s, chip, "Pin", JZ_REG_GPIO_PIN);
  		gpio_seq_reg(s, chip, "Data", JZ_REG_GPIO_DATA);
  		gpio_seq_reg(s, chip, "Mask", JZ_REG_GPIO_MASK);
  		gpio_seq_reg(s, chip, "Pull", JZ_REG_GPIO_PULL);
  		gpio_seq_reg(s, chip, "Func", JZ_REG_GPIO_FUNC);
  		gpio_seq_reg(s, chip, "Select", JZ_REG_GPIO_SELECT);
  		gpio_seq_reg(s, chip, "Direction", JZ_REG_GPIO_DIRECTION);
  		gpio_seq_reg(s, chip, "Trigger", JZ_REG_GPIO_TRIGGER);
  		gpio_seq_reg(s, chip, "Flag", JZ_REG_GPIO_FLAG);
  	}
  
  	return 0;
  }
  
  static int gpio_regs_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, gpio_regs_show, NULL);
  }
  
  static const struct file_operations gpio_regs_operations = {
  	.open		= gpio_regs_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
  	.release	= single_release,
  };
  
  static int __init gpio_debugfs_init(void)
  {
  	(void) debugfs_create_file("jz_regs_gpio", S_IFREG | S_IRUGO,
  				NULL, NULL, &gpio_regs_operations);
  	return 0;
  }
  subsys_initcall(gpio_debugfs_init);
  
  #endif