Blame view

arch/arm/plat-orion/gpio.c 11.7 KB
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
1
2
3
4
5
6
7
8
9
10
11
12
  /*
   * arch/arm/plat-orion/gpio.c
   *
   * Marvell Orion SoC GPIO handling.
   *
   * This file is licensed under the terms of the GNU General Public
   * License version 2.  This program is licensed "as is" without any
   * warranty of any kind, whether express or implied.
   */
  
  #include <linux/kernel.h>
  #include <linux/init.h>
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
13
  #include <linux/irq.h>
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
14
15
16
17
  #include <linux/module.h>
  #include <linux/spinlock.h>
  #include <linux/bitops.h>
  #include <linux/io.h>
a88656553   Erik Benada   [ARM] orion: conv...
18
  #include <linux/gpio.h>
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
19

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
20
21
22
23
24
25
26
27
28
29
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
77
78
79
80
  /*
   * GPIO unit register offsets.
   */
  #define GPIO_OUT_OFF		0x0000
  #define GPIO_IO_CONF_OFF	0x0004
  #define GPIO_BLINK_EN_OFF	0x0008
  #define GPIO_IN_POL_OFF		0x000c
  #define GPIO_DATA_IN_OFF	0x0010
  #define GPIO_EDGE_CAUSE_OFF	0x0014
  #define GPIO_EDGE_MASK_OFF	0x0018
  #define GPIO_LEVEL_MASK_OFF	0x001c
  
  struct orion_gpio_chip {
  	struct gpio_chip	chip;
  	spinlock_t		lock;
  	void __iomem		*base;
  	unsigned long		valid_input;
  	unsigned long		valid_output;
  	int			mask_offset;
  	int			secondary_irq_base;
  };
  
  static void __iomem *GPIO_OUT(struct orion_gpio_chip *ochip)
  {
  	return ochip->base + GPIO_OUT_OFF;
  }
  
  static void __iomem *GPIO_IO_CONF(struct orion_gpio_chip *ochip)
  {
  	return ochip->base + GPIO_IO_CONF_OFF;
  }
  
  static void __iomem *GPIO_BLINK_EN(struct orion_gpio_chip *ochip)
  {
  	return ochip->base + GPIO_BLINK_EN_OFF;
  }
  
  static void __iomem *GPIO_IN_POL(struct orion_gpio_chip *ochip)
  {
  	return ochip->base + GPIO_IN_POL_OFF;
  }
  
  static void __iomem *GPIO_DATA_IN(struct orion_gpio_chip *ochip)
  {
  	return ochip->base + GPIO_DATA_IN_OFF;
  }
  
  static void __iomem *GPIO_EDGE_CAUSE(struct orion_gpio_chip *ochip)
  {
  	return ochip->base + GPIO_EDGE_CAUSE_OFF;
  }
  
  static void __iomem *GPIO_EDGE_MASK(struct orion_gpio_chip *ochip)
  {
  	return ochip->base + ochip->mask_offset + GPIO_EDGE_MASK_OFF;
  }
  
  static void __iomem *GPIO_LEVEL_MASK(struct orion_gpio_chip *ochip)
  {
  	return ochip->base + ochip->mask_offset + GPIO_LEVEL_MASK_OFF;
  }
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
81

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
82
83
84
85
86
  static struct orion_gpio_chip orion_gpio_chips[2];
  static int orion_gpio_chip_count;
  
  static inline void
  __set_direction(struct orion_gpio_chip *ochip, unsigned pin, int input)
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
87
88
  {
  	u32 u;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
89
  	u = readl(GPIO_IO_CONF(ochip));
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
90
  	if (input)
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
91
  		u |= 1 << pin;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
92
  	else
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
93
94
  		u &= ~(1 << pin);
  	writel(u, GPIO_IO_CONF(ochip));
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
95
  }
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
96
  static void __set_level(struct orion_gpio_chip *ochip, unsigned pin, int high)
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
97
98
  {
  	u32 u;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
99
  	u = readl(GPIO_OUT(ochip));
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
100
  	if (high)
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
101
  		u |= 1 << pin;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
102
  	else
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
103
104
  		u &= ~(1 << pin);
  	writel(u, GPIO_OUT(ochip));
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
105
  }
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
106
107
  static inline void
  __set_blinking(struct orion_gpio_chip *ochip, unsigned pin, int blink)
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
108
  {
a88656553   Erik Benada   [ARM] orion: conv...
109
  	u32 u;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
110

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
111
  	u = readl(GPIO_BLINK_EN(ochip));
a88656553   Erik Benada   [ARM] orion: conv...
112
  	if (blink)
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
113
  		u |= 1 << pin;
a88656553   Erik Benada   [ARM] orion: conv...
114
  	else
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
115
116
  		u &= ~(1 << pin);
  	writel(u, GPIO_BLINK_EN(ochip));
a88656553   Erik Benada   [ARM] orion: conv...
117
  }
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
118

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
119
120
  static inline int
  orion_gpio_is_valid(struct orion_gpio_chip *ochip, unsigned pin, int mode)
a88656553   Erik Benada   [ARM] orion: conv...
121
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
122
123
124
125
126
127
128
129
130
131
  	if (pin >= ochip->chip.ngpio)
  		goto err_out;
  
  	if ((mode & GPIO_INPUT_OK) && !test_bit(pin, &ochip->valid_input))
  		goto err_out;
  
  	if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, &ochip->valid_output))
  		goto err_out;
  
  	return 1;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
132

a88656553   Erik Benada   [ARM] orion: conv...
133
134
135
136
  err_out:
  	pr_debug("%s: invalid GPIO %d
  ", __func__, pin);
  	return false;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
137
  }
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
138

a88656553   Erik Benada   [ARM] orion: conv...
139
140
141
  /*
   * GENERIC_GPIO primitives.
   */
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
142
143
144
145
146
147
148
149
150
151
152
  static int orion_gpio_request(struct gpio_chip *chip, unsigned pin)
  {
  	struct orion_gpio_chip *ochip =
  		container_of(chip, struct orion_gpio_chip, chip);
  
  	if (orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK) ||
  	    orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
  		return 0;
  
  	return -EINVAL;
  }
a88656553   Erik Benada   [ARM] orion: conv...
153
  static int orion_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
154
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
155
156
  	struct orion_gpio_chip *ochip =
  		container_of(chip, struct orion_gpio_chip, chip);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
157
  	unsigned long flags;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
158

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
159
  	if (!orion_gpio_is_valid(ochip, pin, GPIO_INPUT_OK))
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
160
  		return -EINVAL;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
161

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
162
163
164
  	spin_lock_irqsave(&ochip->lock, flags);
  	__set_direction(ochip, pin, 1);
  	spin_unlock_irqrestore(&ochip->lock, flags);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
165
166
167
  
  	return 0;
  }
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
168

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
169
  static int orion_gpio_get(struct gpio_chip *chip, unsigned pin)
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
170
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
171
172
  	struct orion_gpio_chip *ochip =
  		container_of(chip, struct orion_gpio_chip, chip);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
173
  	int val;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
174
175
176
177
178
  	if (readl(GPIO_IO_CONF(ochip)) & (1 << pin)) {
  		val = readl(GPIO_DATA_IN(ochip)) ^ readl(GPIO_IN_POL(ochip));
  	} else {
  		val = readl(GPIO_OUT(ochip));
  	}
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
179

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
180
  	return (val >> pin) & 1;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
181
  }
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
182

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
183
184
  static int
  orion_gpio_direction_output(struct gpio_chip *chip, unsigned pin, int value)
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
185
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
186
187
  	struct orion_gpio_chip *ochip =
  		container_of(chip, struct orion_gpio_chip, chip);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
188
  	unsigned long flags;
a88656553   Erik Benada   [ARM] orion: conv...
189

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
190
  	if (!orion_gpio_is_valid(ochip, pin, GPIO_OUTPUT_OK))
a88656553   Erik Benada   [ARM] orion: conv...
191
  		return -EINVAL;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
192

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
193
194
195
196
197
  	spin_lock_irqsave(&ochip->lock, flags);
  	__set_blinking(ochip, pin, 0);
  	__set_level(ochip, pin, value);
  	__set_direction(ochip, pin, 0);
  	spin_unlock_irqrestore(&ochip->lock, flags);
a88656553   Erik Benada   [ARM] orion: conv...
198
199
  
  	return 0;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
200
  }
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
201

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
202
  static void orion_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
203
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
204
205
  	struct orion_gpio_chip *ochip =
  		container_of(chip, struct orion_gpio_chip, chip);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
206
  	unsigned long flags;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
207

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
208
209
210
  	spin_lock_irqsave(&ochip->lock, flags);
  	__set_level(ochip, pin, value);
  	spin_unlock_irqrestore(&ochip->lock, flags);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
211
  }
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
212

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
213
  static int orion_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
214
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
215
216
  	struct orion_gpio_chip *ochip =
  		container_of(chip, struct orion_gpio_chip, chip);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
217

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
218
  	return ochip->secondary_irq_base + pin;
a88656553   Erik Benada   [ARM] orion: conv...
219
  }
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
220

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
221

9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
222
223
224
  /*
   * Orion-specific GPIO API extensions.
   */
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  static struct orion_gpio_chip *orion_gpio_chip_find(int pin)
  {
  	int i;
  
  	for (i = 0; i < orion_gpio_chip_count; i++) {
  		struct orion_gpio_chip *ochip = orion_gpio_chips + i;
  		struct gpio_chip *chip = &ochip->chip;
  
  		if (pin >= chip->base && pin < chip->base + chip->ngpio)
  			return ochip;
  	}
  
  	return NULL;
  }
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
239
240
  void __init orion_gpio_set_unused(unsigned pin)
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
241
242
243
244
245
246
  	struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin);
  
  	if (ochip == NULL)
  		return;
  
  	pin -= ochip->chip.base;
a88656553   Erik Benada   [ARM] orion: conv...
247
  	/* Configure as output, drive low. */
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
248
249
  	__set_level(ochip, pin, 0);
  	__set_direction(ochip, pin, 0);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
250
  }
28d27cf4c   Nicolas Pitre   [ARM] Orion: make...
251
  void __init orion_gpio_set_valid(unsigned pin, int mode)
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
252
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
253
254
255
256
257
258
  	struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin);
  
  	if (ochip == NULL)
  		return;
  
  	pin -= ochip->chip.base;
28d27cf4c   Nicolas Pitre   [ARM] Orion: make...
259
260
  	if (mode == 1)
  		mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
261

28d27cf4c   Nicolas Pitre   [ARM] Orion: make...
262
  	if (mode & GPIO_INPUT_OK)
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
263
  		__set_bit(pin, &ochip->valid_input);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
264
  	else
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
265
  		__clear_bit(pin, &ochip->valid_input);
28d27cf4c   Nicolas Pitre   [ARM] Orion: make...
266
  	if (mode & GPIO_OUTPUT_OK)
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
267
  		__set_bit(pin, &ochip->valid_output);
28d27cf4c   Nicolas Pitre   [ARM] Orion: make...
268
  	else
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
269
  		__clear_bit(pin, &ochip->valid_output);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
270
271
272
273
  }
  
  void orion_gpio_set_blink(unsigned pin, int blink)
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
274
  	struct orion_gpio_chip *ochip = orion_gpio_chip_find(pin);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
275
  	unsigned long flags;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
276

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
277
278
  	if (ochip == NULL)
  		return;
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
279

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
280
281
282
283
  	spin_lock_irqsave(&ochip->lock, flags);
  	__set_level(ochip, pin, 0);
  	__set_blinking(ochip, pin, blink);
  	spin_unlock_irqrestore(&ochip->lock, flags);
9569dae75   Lennert Buytenhek   [ARM] Orion: shar...
284
285
  }
  EXPORT_SYMBOL(orion_gpio_set_blink);
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
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
  
  
  /*****************************************************************************
   * Orion GPIO IRQ
   *
   * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same
   * value of the line or the opposite value.
   *
   * Level IRQ handlers: DATA_IN is used directly as cause register.
   *                     Interrupt are masked by LEVEL_MASK registers.
   * Edge IRQ handlers:  Change in DATA_IN are latched in EDGE_CAUSE.
   *                     Interrupt are masked by EDGE_MASK registers.
   * Both-edge handlers: Similar to regular Edge handlers, but also swaps
   *                     the polarity to catch the next line transaction.
   *                     This is a race condition that might not perfectly
   *                     work on some use cases.
   *
   * Every eight GPIO lines are grouped (OR'ed) before going up to main
   * cause register.
   *
   *                    EDGE  cause    mask
   *        data-in   /--------| |-----| |----\
   *     -----| |-----                         ---- to main cause reg
   *           X      \----------------| |----/
   *        polarity    LEVEL          mask
   *
   ****************************************************************************/
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
313

3b0c8d403   Lennert Buytenhek   ARM: plat-orion: ...
314
  static int gpio_irq_set_type(struct irq_data *d, u32 type)
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
315
  {
e59347a1d   Thomas Gleixner   arm: orion: Use g...
316
317
318
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
  	struct orion_gpio_chip *ochip = gc->private;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
319
  	int pin;
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
320
  	u32 u;
e59347a1d   Thomas Gleixner   arm: orion: Use g...
321
  	pin = d->irq - gc->irq_base;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
322
323
  
  	u = readl(GPIO_IO_CONF(ochip)) & (1 << pin);
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
324
325
  	if (!u) {
  		printk(KERN_ERR "orion gpio_irq_set_type failed "
3b0c8d403   Lennert Buytenhek   ARM: plat-orion: ...
326
327
  				"(irq %d, pin %d).
  ", d->irq, pin);
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
328
329
  		return -EINVAL;
  	}
e59347a1d   Thomas Gleixner   arm: orion: Use g...
330
331
  	type &= IRQ_TYPE_SENSE_MASK;
  	if (type == IRQ_TYPE_NONE)
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
332
  		return -EINVAL;
e59347a1d   Thomas Gleixner   arm: orion: Use g...
333
334
335
336
337
  
  	/* Check if we need to change chip and handler */
  	if (!(ct->type & type))
  		if (irq_setup_alt_chip(d, type))
  			return -EINVAL;
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
338
339
340
341
342
  
  	/*
  	 * Configure interrupt polarity.
  	 */
  	if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
343
344
345
  		u = readl(GPIO_IN_POL(ochip));
  		u &= ~(1 << pin);
  		writel(u, GPIO_IN_POL(ochip));
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
346
  	} else if (type == IRQ_TYPE_EDGE_FALLING || type == IRQ_TYPE_LEVEL_LOW) {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
347
348
349
  		u = readl(GPIO_IN_POL(ochip));
  		u |= 1 << pin;
  		writel(u, GPIO_IN_POL(ochip));
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
350
351
  	} else if (type == IRQ_TYPE_EDGE_BOTH) {
  		u32 v;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
352
  		v = readl(GPIO_IN_POL(ochip)) ^ readl(GPIO_DATA_IN(ochip));
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
353
354
355
356
  
  		/*
  		 * set initial polarity based on current input level
  		 */
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
357
358
359
  		u = readl(GPIO_IN_POL(ochip));
  		if (v & (1 << pin))
  			u |= 1 << pin;		/* falling */
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
360
  		else
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
361
362
  			u &= ~(1 << pin);	/* rising */
  		writel(u, GPIO_IN_POL(ochip));
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
363
  	}
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
364
365
  	return 0;
  }
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
366
367
368
369
  void __init orion_gpio_init(int gpio_base, int ngpio,
  			    u32 base, int mask_offset, int secondary_irq_base)
  {
  	struct orion_gpio_chip *ochip;
e59347a1d   Thomas Gleixner   arm: orion: Use g...
370
371
  	struct irq_chip_generic *gc;
  	struct irq_chip_type *ct;
0b35a45bd   Holger Brunck   ARM: plat-orion: ...
372
  	char gc_label[16];
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
373
374
375
  
  	if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips))
  		return;
0b35a45bd   Holger Brunck   ARM: plat-orion: ...
376
377
  	snprintf(gc_label, sizeof(gc_label), "orion_gpio%d",
  		orion_gpio_chip_count);
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
378
  	ochip = orion_gpio_chips + orion_gpio_chip_count;
0b35a45bd   Holger Brunck   ARM: plat-orion: ...
379
  	ochip->chip.label = kstrdup(gc_label, GFP_KERNEL);
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  	ochip->chip.request = orion_gpio_request;
  	ochip->chip.direction_input = orion_gpio_direction_input;
  	ochip->chip.get = orion_gpio_get;
  	ochip->chip.direction_output = orion_gpio_direction_output;
  	ochip->chip.set = orion_gpio_set;
  	ochip->chip.to_irq = orion_gpio_to_irq;
  	ochip->chip.base = gpio_base;
  	ochip->chip.ngpio = ngpio;
  	ochip->chip.can_sleep = 0;
  	spin_lock_init(&ochip->lock);
  	ochip->base = (void __iomem *)base;
  	ochip->valid_input = 0;
  	ochip->valid_output = 0;
  	ochip->mask_offset = mask_offset;
  	ochip->secondary_irq_base = secondary_irq_base;
  
  	gpiochip_add(&ochip->chip);
  
  	orion_gpio_chip_count++;
  
  	/*
  	 * Mask and clear GPIO interrupts.
  	 */
  	writel(0, GPIO_EDGE_CAUSE(ochip));
  	writel(0, GPIO_EDGE_MASK(ochip));
  	writel(0, GPIO_LEVEL_MASK(ochip));
e59347a1d   Thomas Gleixner   arm: orion: Use g...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  	gc = irq_alloc_generic_chip("orion_gpio_irq", 2, secondary_irq_base,
  				    ochip->base, handle_level_irq);
  	gc->private = ochip;
  
  	ct = gc->chip_types;
  	ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF;
  	ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
  	ct->chip.irq_mask = irq_gc_mask_clr_bit;
  	ct->chip.irq_unmask = irq_gc_mask_set_bit;
  	ct->chip.irq_set_type = gpio_irq_set_type;
  
  	ct++;
  	ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF;
  	ct->regs.ack = GPIO_EDGE_CAUSE_OFF;
  	ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
659fb32d1   Simon Guinot   genirq: replace i...
421
  	ct->chip.irq_ack = irq_gc_ack_clr_bit;
e59347a1d   Thomas Gleixner   arm: orion: Use g...
422
423
424
425
426
427
428
  	ct->chip.irq_mask = irq_gc_mask_clr_bit;
  	ct->chip.irq_unmask = irq_gc_mask_set_bit;
  	ct->chip.irq_set_type = gpio_irq_set_type;
  	ct->handler = handle_edge_irq;
  
  	irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE,
  			       IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
429
  }
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
430
431
  void orion_gpio_irq_handler(int pinoff)
  {
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
432
  	struct orion_gpio_chip *ochip;
e83bbb115   Thomas Gleixner   arm: Cleanup irq_...
433
  	u32 cause, type;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
434
  	int i;
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
435

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
436
437
438
  	ochip = orion_gpio_chip_find(pinoff);
  	if (ochip == NULL)
  		return;
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
439

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
440
441
  	cause = readl(GPIO_DATA_IN(ochip)) & readl(GPIO_LEVEL_MASK(ochip));
  	cause |= readl(GPIO_EDGE_CAUSE(ochip)) & readl(GPIO_EDGE_MASK(ochip));
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
442

9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
443
444
  	for (i = 0; i < ochip->chip.ngpio; i++) {
  		int irq;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
445
446
447
448
  
  		irq = ochip->secondary_irq_base + i;
  
  		if (!(cause & (1 << i)))
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
449
  			continue;
e83bbb115   Thomas Gleixner   arm: Cleanup irq_...
450
451
  		type = irqd_get_trigger_type(irq_get_irq_data(irq));
  		if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
452
453
  			/* Swap polarity (race with GPIO line) */
  			u32 polarity;
9eac6d0a4   Lennert Buytenhek   ARM: Remove depen...
454
455
456
  			polarity = readl(GPIO_IN_POL(ochip));
  			polarity ^= 1 << i;
  			writel(polarity, GPIO_IN_POL(ochip));
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
457
  		}
e83bbb115   Thomas Gleixner   arm: Cleanup irq_...
458
  		generic_handle_irq(irq);
07332318f   Lennert Buytenhek   [ARM] Orion: shar...
459
460
  	}
  }