Blame view

drivers/gpio/gpio-ep93xx.c 12.2 KB
68b649318   Linus Walleij   gpio: ep93xx: Swi...
1
  // SPDX-License-Identifier: GPL-2.0
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
2
  /*
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
3
4
   * Generic EP93xx GPIO handling
   *
1c5454eed   Ryan Mallon   Change Ryan Mallo...
5
   * Copyright (c) 2008 Ryan Mallon
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
6
   * Copyright (c) 2011 H Hartley Sweeten <hsweeten@visionengravers.com>
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
7
8
9
   *
   * Based on code originally from:
   *  linux/arch/arm/mach-ep93xx/core.c
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
10
11
12
   */
  
  #include <linux/init.h>
bb207ef1e   Paul Gortmaker   drivers/gpio: Fix...
13
  #include <linux/module.h>
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
14
  #include <linux/platform_device.h>
fced80c73   Russell King   [ARM] Convert asm...
15
  #include <linux/io.h>
595c050d8   Ryan Mallon   [ARM] 5605/1: Fix...
16
  #include <linux/irq.h>
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
17
  #include <linux/slab.h>
0f4630f37   Linus Walleij   gpio: generic: fa...
18
  #include <linux/gpio/driver.h>
51ba88e32   Linus Walleij   gpio: ep93xx: Use...
19
  #include <linux/bitops.h>
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
20

991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
21
22
23
  #define EP93XX_GPIO_F_INT_STATUS 0x5c
  #define EP93XX_GPIO_A_INT_STATUS 0xa0
  #define EP93XX_GPIO_B_INT_STATUS 0xbc
4c2baed3a   Arnd Bergmann   ARM/gpio: ep93xx:...
24
25
26
27
28
29
  
  /* Maximum value for gpio line identifiers */
  #define EP93XX_GPIO_LINE_MAX 63
  
  /* Maximum value for irq capable line identifiers */
  #define EP93XX_GPIO_LINE_MAX_IRQ 23
d875cc27e   Linus Walleij   gpio: ep93xx: Cut...
30
  /*
a419a3d92   Linus Walleij   gpio: ep93xx: Swi...
31
32
   * Static mapping of GPIO bank F IRQS:
   * F0..F7 (16..24) to irq 80..87.
d875cc27e   Linus Walleij   gpio: ep93xx: Cut...
33
   */
a419a3d92   Linus Walleij   gpio: ep93xx: Swi...
34
  #define EP93XX_GPIO_F_IRQ_BASE 80
d875cc27e   Linus Walleij   gpio: ep93xx: Cut...
35

1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
36
  struct ep93xx_gpio {
1d2bb17aa   Linus Walleij   gpio: ep93xx: Cut...
37
  	void __iomem		*base;
0f4630f37   Linus Walleij   gpio: generic: fa...
38
  	struct gpio_chip	gc[8];
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
39
  };
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
40
  /*************************************************************************
4742723cb   Hartley Sweeten   ARM: 6029/1: ep93...
41
   * Interrupt handling for EP93xx on-chip GPIOs
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
42
43
44
45
46
47
48
49
50
51
52
53
54
   *************************************************************************/
  static unsigned char gpio_int_unmasked[3];
  static unsigned char gpio_int_enabled[3];
  static unsigned char gpio_int_type1[3];
  static unsigned char gpio_int_type2[3];
  static unsigned char gpio_int_debounce[3];
  
  /* Port ordering is: A B F */
  static const u8 int_type1_register_offset[3]	= { 0x90, 0xac, 0x4c };
  static const u8 int_type2_register_offset[3]	= { 0x94, 0xb0, 0x50 };
  static const u8 eoi_register_offset[3]		= { 0x98, 0xb4, 0x54 };
  static const u8 int_en_register_offset[3]	= { 0x9c, 0xb8, 0x58 };
  static const u8 int_debounce_register_offset[3]	= { 0xa8, 0xc4, 0x64 };
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
55
  static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg, unsigned port)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
56
57
  {
  	BUG_ON(port > 2);
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
58
  	writeb_relaxed(0, epg->base + int_en_register_offset[port]);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
59

d27e06ac5   Linus Walleij   gpio: ep93xx: get...
60
  	writeb_relaxed(gpio_int_type2[port],
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
61
  		       epg->base + int_type2_register_offset[port]);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
62

d27e06ac5   Linus Walleij   gpio: ep93xx: get...
63
  	writeb_relaxed(gpio_int_type1[port],
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
64
  		       epg->base + int_type1_register_offset[port]);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
65

d27e06ac5   Linus Walleij   gpio: ep93xx: get...
66
  	writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
67
  	       epg->base + int_en_register_offset[port]);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
68
  }
fd935fc42   Linus Walleij   gpio: ep93xx: Do ...
69
  static int ep93xx_gpio_port(struct gpio_chip *gc)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
70
  {
fd935fc42   Linus Walleij   gpio: ep93xx: Do ...
71
72
  	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
  	int port = 0;
f40f73075   Colin Ian King   gpio: ep93xx: fix...
73
  	while (port < ARRAY_SIZE(epg->gc) && gc != &epg->gc[port])
fd935fc42   Linus Walleij   gpio: ep93xx: Do ...
74
75
76
  		port++;
  
  	/* This should not happen but is there as a last safeguard */
f6d9af477   Dan Carpenter   gpio: ep93xx: fix...
77
  	if (port == ARRAY_SIZE(epg->gc)) {
fd935fc42   Linus Walleij   gpio: ep93xx: Do ...
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  		pr_crit("can't find the GPIO port
  ");
  		return 0;
  	}
  
  	return port;
  }
  
  static void ep93xx_gpio_int_debounce(struct gpio_chip *gc,
  				     unsigned int offset, bool enable)
  {
  	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
  	int port = ep93xx_gpio_port(gc);
  	int port_mask = BIT(offset);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
92
93
94
95
96
  
  	if (enable)
  		gpio_int_debounce[port] |= port_mask;
  	else
  		gpio_int_debounce[port] &= ~port_mask;
d27e06ac5   Linus Walleij   gpio: ep93xx: get...
97
  	writeb(gpio_int_debounce[port],
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
98
  	       epg->base + int_debounce_register_offset[port]);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
99
  }
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
100

bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
101
  static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
102
  {
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
103
104
  	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
  	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
99399f40d   Linus Walleij   gpio: ep93xx: Pro...
105
  	struct irq_chip *irqchip = irq_desc_get_chip(desc);
68491b075   Linus Walleij   gpio: ep93xx: Use...
106
107
  	unsigned long stat;
  	int offset;
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
108

99399f40d   Linus Walleij   gpio: ep93xx: Pro...
109
  	chained_irq_enter(irqchip, desc);
a419a3d92   Linus Walleij   gpio: ep93xx: Swi...
110
111
112
113
114
115
  	/*
  	 * Dispatch the IRQs to the irqdomain of each A and B
  	 * gpiochip irqdomains depending on what has fired.
  	 * The tricky part is that the IRQ line is shared
  	 * between bank A and B and each has their own gpiochip.
  	 */
68491b075   Linus Walleij   gpio: ep93xx: Use...
116
  	stat = readb(epg->base + EP93XX_GPIO_A_INT_STATUS);
a419a3d92   Linus Walleij   gpio: ep93xx: Swi...
117
118
119
  	for_each_set_bit(offset, &stat, 8)
  		generic_handle_irq(irq_find_mapping(epg->gc[0].irq.domain,
  						    offset));
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
120

68491b075   Linus Walleij   gpio: ep93xx: Use...
121
  	stat = readb(epg->base + EP93XX_GPIO_B_INT_STATUS);
a419a3d92   Linus Walleij   gpio: ep93xx: Swi...
122
123
124
  	for_each_set_bit(offset, &stat, 8)
  		generic_handle_irq(irq_find_mapping(epg->gc[1].irq.domain,
  						    offset));
99399f40d   Linus Walleij   gpio: ep93xx: Pro...
125
126
  
  	chained_irq_exit(irqchip, desc);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
127
  }
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
128
  static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
129
130
  {
  	/*
25985edce   Lucas De Marchi   Fix common misspe...
131
  	 * map discontiguous hw irq range to continuous sw irq range:
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
132
  	 *
d875cc27e   Linus Walleij   gpio: ep93xx: Cut...
133
  	 *  IRQ_EP93XX_GPIO{0..7}MUX -> EP93XX_GPIO_LINE_F{0..7}
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
134
  	 */
99399f40d   Linus Walleij   gpio: ep93xx: Pro...
135
  	struct irq_chip *irqchip = irq_desc_get_chip(desc);
e43ea7a77   Thomas Gleixner   gpio/ep93xx: Prep...
136
  	unsigned int irq = irq_desc_get_irq(desc);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
137
  	int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
a419a3d92   Linus Walleij   gpio: ep93xx: Swi...
138
  	int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx;
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
139

99399f40d   Linus Walleij   gpio: ep93xx: Pro...
140
  	chained_irq_enter(irqchip, desc);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
141
  	generic_handle_irq(gpio_irq);
99399f40d   Linus Walleij   gpio: ep93xx: Pro...
142
  	chained_irq_exit(irqchip, desc);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
143
  }
c0afc9160   Lennert Buytenhek   ARM: ep93xx: irq_...
144
  static void ep93xx_gpio_irq_ack(struct irq_data *d)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
145
  {
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
146
147
  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
  	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
51ba88e32   Linus Walleij   gpio: ep93xx: Use...
148
149
  	int port = ep93xx_gpio_port(gc);
  	int port_mask = BIT(d->irq & 7);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
150

d1735a2eb   Thomas Gleixner   arm: ep93xx: Use ...
151
  	if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
152
  		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
153
  		ep93xx_gpio_update_int_params(epg, port);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
154
  	}
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
155
  	writeb(port_mask, epg->base + eoi_register_offset[port]);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
156
  }
c0afc9160   Lennert Buytenhek   ARM: ep93xx: irq_...
157
  static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
158
  {
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
159
160
  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
  	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
51ba88e32   Linus Walleij   gpio: ep93xx: Use...
161
162
  	int port = ep93xx_gpio_port(gc);
  	int port_mask = BIT(d->irq & 7);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
163

d1735a2eb   Thomas Gleixner   arm: ep93xx: Use ...
164
  	if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
165
166
167
  		gpio_int_type2[port] ^= port_mask; /* switch edge direction */
  
  	gpio_int_unmasked[port] &= ~port_mask;
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
168
  	ep93xx_gpio_update_int_params(epg, port);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
169

991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
170
  	writeb(port_mask, epg->base + eoi_register_offset[port]);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
171
  }
c0afc9160   Lennert Buytenhek   ARM: ep93xx: irq_...
172
  static void ep93xx_gpio_irq_mask(struct irq_data *d)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
173
  {
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
174
175
  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
  	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
51ba88e32   Linus Walleij   gpio: ep93xx: Use...
176
  	int port = ep93xx_gpio_port(gc);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
177

51ba88e32   Linus Walleij   gpio: ep93xx: Use...
178
  	gpio_int_unmasked[port] &= ~BIT(d->irq & 7);
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
179
  	ep93xx_gpio_update_int_params(epg, port);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
180
  }
c0afc9160   Lennert Buytenhek   ARM: ep93xx: irq_...
181
  static void ep93xx_gpio_irq_unmask(struct irq_data *d)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
182
  {
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
183
184
  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
  	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
51ba88e32   Linus Walleij   gpio: ep93xx: Use...
185
  	int port = ep93xx_gpio_port(gc);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
186

51ba88e32   Linus Walleij   gpio: ep93xx: Use...
187
  	gpio_int_unmasked[port] |= BIT(d->irq & 7);
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
188
  	ep93xx_gpio_update_int_params(epg, port);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
189
190
191
192
193
194
195
  }
  
  /*
   * gpio_int_type1 controls whether the interrupt is level (0) or
   * edge (1) triggered, while gpio_int_type2 controls whether it
   * triggers on low/falling (0) or high/rising (1).
   */
c0afc9160   Lennert Buytenhek   ARM: ep93xx: irq_...
196
  static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
197
  {
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
198
199
  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
  	struct ep93xx_gpio *epg = gpiochip_get_data(gc);
51ba88e32   Linus Walleij   gpio: ep93xx: Use...
200
201
202
  	int port = ep93xx_gpio_port(gc);
  	int offset = d->irq & 7;
  	int port_mask = BIT(offset);
d1735a2eb   Thomas Gleixner   arm: ep93xx: Use ...
203
  	irq_flow_handler_t handler;
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
204

51ba88e32   Linus Walleij   gpio: ep93xx: Use...
205
  	gc->direction_input(gc, offset);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
206
207
208
209
210
  
  	switch (type) {
  	case IRQ_TYPE_EDGE_RISING:
  		gpio_int_type1[port] |= port_mask;
  		gpio_int_type2[port] |= port_mask;
d1735a2eb   Thomas Gleixner   arm: ep93xx: Use ...
211
  		handler = handle_edge_irq;
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
212
213
214
215
  		break;
  	case IRQ_TYPE_EDGE_FALLING:
  		gpio_int_type1[port] |= port_mask;
  		gpio_int_type2[port] &= ~port_mask;
d1735a2eb   Thomas Gleixner   arm: ep93xx: Use ...
216
  		handler = handle_edge_irq;
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
217
218
219
220
  		break;
  	case IRQ_TYPE_LEVEL_HIGH:
  		gpio_int_type1[port] &= ~port_mask;
  		gpio_int_type2[port] |= port_mask;
d1735a2eb   Thomas Gleixner   arm: ep93xx: Use ...
221
  		handler = handle_level_irq;
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
222
223
224
225
  		break;
  	case IRQ_TYPE_LEVEL_LOW:
  		gpio_int_type1[port] &= ~port_mask;
  		gpio_int_type2[port] &= ~port_mask;
d1735a2eb   Thomas Gleixner   arm: ep93xx: Use ...
226
  		handler = handle_level_irq;
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
227
228
229
230
  		break;
  	case IRQ_TYPE_EDGE_BOTH:
  		gpio_int_type1[port] |= port_mask;
  		/* set initial polarity based on current input level */
51ba88e32   Linus Walleij   gpio: ep93xx: Use...
231
  		if (gc->get(gc, offset))
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
232
233
234
  			gpio_int_type2[port] &= ~port_mask; /* falling */
  		else
  			gpio_int_type2[port] |= port_mask; /* rising */
d1735a2eb   Thomas Gleixner   arm: ep93xx: Use ...
235
  		handler = handle_edge_irq;
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
236
237
  		break;
  	default:
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
238
239
  		return -EINVAL;
  	}
72b2a9ef9   Thomas Gleixner   gpio/ep93xx: Use ...
240
  	irq_set_handler_locked(d, handler);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
241

d1735a2eb   Thomas Gleixner   arm: ep93xx: Use ...
242
  	gpio_int_enabled[port] |= port_mask;
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
243

991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
244
  	ep93xx_gpio_update_int_params(epg, port);
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
245
246
247
248
249
250
  
  	return 0;
  }
  
  static struct irq_chip ep93xx_gpio_irq_chip = {
  	.name		= "GPIO",
c0afc9160   Lennert Buytenhek   ARM: ep93xx: irq_...
251
252
253
254
255
  	.irq_ack	= ep93xx_gpio_irq_ack,
  	.irq_mask_ack	= ep93xx_gpio_irq_mask_ack,
  	.irq_mask	= ep93xx_gpio_irq_mask,
  	.irq_unmask	= ep93xx_gpio_irq_unmask,
  	.irq_set_type	= ep93xx_gpio_irq_type,
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
256
  };
d056ab785   Hartley Sweeten   ARM: 5954/1: ep93...
257
258
259
  /*************************************************************************
   * gpiolib interface for EP93xx on-chip GPIOs
   *************************************************************************/
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
260
261
262
263
264
  struct ep93xx_gpio_bank {
  	const char	*label;
  	int		data;
  	int		dir;
  	int		base;
3c38b3a30   Linus Walleij   gpio: ep93xx: Ren...
265
  	bool		has_irq;
d2b091961   Linus Walleij   gpio: ep93xx: Pas...
266
267
  	bool		has_hierarchical_irq;
  	unsigned int	irq_base;
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
268
  };
d2b091961   Linus Walleij   gpio: ep93xx: Pas...
269
  #define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq, _has_hier, _irq_base) \
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
270
271
272
273
274
  	{							\
  		.label		= _label,			\
  		.data		= _data,			\
  		.dir		= _dir,				\
  		.base		= _base,			\
3c38b3a30   Linus Walleij   gpio: ep93xx: Ren...
275
  		.has_irq	= _has_irq,			\
d2b091961   Linus Walleij   gpio: ep93xx: Pas...
276
277
  		.has_hierarchical_irq = _has_hier,		\
  		.irq_base	= _irq_base,			\
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
278
  	}
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
279

1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
280
  static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
d2b091961   Linus Walleij   gpio: ep93xx: Pas...
281
282
283
284
285
286
287
288
289
290
291
  	/* Bank A has 8 IRQs */
  	EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true, false, 64),
  	/* Bank B has 8 IRQs */
  	EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true, false, 72),
  	EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false, false, 0),
  	EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false, false, 0),
  	EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false, false, 0),
  	/* Bank F has 8 IRQs */
  	EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, false, true, 0),
  	EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false, false, 0),
  	EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false, false, 0),
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
292
  };
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
293
  static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
2956b5d94   Mika Westerberg   pinctrl / gpio: I...
294
  				  unsigned long config)
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
295
  {
2956b5d94   Mika Westerberg   pinctrl / gpio: I...
296
297
298
299
  	u32 debounce;
  
  	if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
  		return -ENOTSUPP;
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
300

2956b5d94   Mika Westerberg   pinctrl / gpio: I...
301
  	debounce = pinconf_to_config_argument(config);
fd935fc42   Linus Walleij   gpio: ep93xx: Do ...
302
  	ep93xx_gpio_int_debounce(gc, offset, debounce ? true : false);
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
303
304
305
  
  	return 0;
  }
a419a3d92   Linus Walleij   gpio: ep93xx: Swi...
306
  static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset)
257af9f97   Linus Walleij   ARM: 7041/1: gpio...
307
  {
a419a3d92   Linus Walleij   gpio: ep93xx: Swi...
308
  	return EP93XX_GPIO_F_IRQ_BASE + offset;
257af9f97   Linus Walleij   ARM: 7041/1: gpio...
309
  }
d2b091961   Linus Walleij   gpio: ep93xx: Pas...
310
311
  static int ep93xx_gpio_add_bank(struct gpio_chip *gc,
  				struct platform_device *pdev,
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
312
313
  				struct ep93xx_gpio *epg,
  				struct ep93xx_gpio_bank *bank)
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
314
  {
991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
315
316
  	void __iomem *data = epg->base + bank->data;
  	void __iomem *dir = epg->base + bank->dir;
d2b091961   Linus Walleij   gpio: ep93xx: Pas...
317
318
  	struct device *dev = &pdev->dev;
  	struct gpio_irq_chip *girq;
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
319
  	int err;
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
320

0f4630f37   Linus Walleij   gpio: generic: fa...
321
  	err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
322
323
  	if (err)
  		return err;
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
324

0f4630f37   Linus Walleij   gpio: generic: fa...
325
326
  	gc->label = bank->label;
  	gc->base = bank->base;
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
327

d2b091961   Linus Walleij   gpio: ep93xx: Pas...
328
329
  	girq = &gc->irq;
  	if (bank->has_irq || bank->has_hierarchical_irq) {
2956b5d94   Mika Westerberg   pinctrl / gpio: I...
330
  		gc->set_config = ep93xx_gpio_set_config;
d2b091961   Linus Walleij   gpio: ep93xx: Pas...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  		girq->chip = &ep93xx_gpio_irq_chip;
  	}
  
  	if (bank->has_irq) {
  		int ab_parent_irq = platform_get_irq(pdev, 0);
  
  		girq->parent_handler = ep93xx_gpio_ab_irq_handler;
  		girq->num_parents = 1;
  		girq->parents = devm_kcalloc(dev, 1,
  					     sizeof(*girq->parents),
  					     GFP_KERNEL);
  		if (!girq->parents)
  			return -ENOMEM;
  		girq->default_type = IRQ_TYPE_NONE;
  		girq->handler = handle_level_irq;
  		girq->parents[0] = ab_parent_irq;
  		girq->first = bank->irq_base;
  	}
  
  	/* Only bank F has especially funky IRQ handling */
  	if (bank->has_hierarchical_irq) {
  		int gpio_irq;
  		int i;
  
  		/*
  		 * FIXME: convert this to use hierarchical IRQ support!
  		 * this requires fixing the root irqchip to be hierarchial.
  		 */
  		girq->parent_handler = ep93xx_gpio_f_irq_handler;
  		girq->num_parents = 8;
  		girq->parents = devm_kcalloc(dev, 8,
  					     sizeof(*girq->parents),
  					     GFP_KERNEL);
  		if (!girq->parents)
  			return -ENOMEM;
  		/* Pick resources 1..8 for these IRQs */
  		for (i = 1; i <= 8; i++)
  			girq->parents[i - 1] = platform_get_irq(pdev, i);
  		for (i = 0; i < 8; i++) {
  			gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
  			irq_set_chip_data(gpio_irq, &epg->gc[5]);
  			irq_set_chip_and_handler(gpio_irq,
  						 &ep93xx_gpio_irq_chip,
  						 handle_level_irq);
  			irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
  		}
  		girq->default_type = IRQ_TYPE_NONE;
  		girq->handler = handle_level_irq;
  		gc->to_irq = ep93xx_gpio_f_to_irq;
  	}
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
381

991ce74ee   Linus Walleij   gpio: ep93xx: Pas...
382
  	return devm_gpiochip_add_data(dev, gc, epg);
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
383
  }
3836309d9   Bill Pemberton   gpio: remove use ...
384
  static int ep93xx_gpio_probe(struct platform_device *pdev)
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
385
  {
1d2bb17aa   Linus Walleij   gpio: ep93xx: Cut...
386
  	struct ep93xx_gpio *epg;
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
387
  	int i;
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
388

6bdec6c77   Enrico Weigelt, metux IT consult   gpio: ep93xx: Use...
389
  	epg = devm_kzalloc(&pdev->dev, sizeof(*epg), GFP_KERNEL);
1d2bb17aa   Linus Walleij   gpio: ep93xx: Cut...
390
  	if (!epg)
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
391
  		return -ENOMEM;
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
392

6bdec6c77   Enrico Weigelt, metux IT consult   gpio: ep93xx: Use...
393
  	epg->base = devm_platform_ioremap_resource(pdev, 0);
1d2bb17aa   Linus Walleij   gpio: ep93xx: Cut...
394
395
  	if (IS_ERR(epg->base))
  		return PTR_ERR(epg->base);
5d046af0e   Hartley Sweeten   ARM: 6641/1: ep93...
396

1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
397
  	for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
1d2bb17aa   Linus Walleij   gpio: ep93xx: Cut...
398
  		struct gpio_chip *gc = &epg->gc[i];
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
399
  		struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
5d046af0e   Hartley Sweeten   ARM: 6641/1: ep93...
400

d2b091961   Linus Walleij   gpio: ep93xx: Pas...
401
  		if (ep93xx_gpio_add_bank(gc, pdev, epg, bank))
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
402
403
  			dev_warn(&pdev->dev, "Unable to add gpio bank %s
  ",
a419a3d92   Linus Walleij   gpio: ep93xx: Swi...
404
  				 bank->label);
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
405
  	}
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
406
  	return 0;
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
407
  }
fd015480c   Hartley Sweeten   ARM: 6636/1: ep93...
408

1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
409
410
411
  static struct platform_driver ep93xx_gpio_driver = {
  	.driver		= {
  		.name	= "gpio-ep93xx",
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
412
413
414
415
416
417
  	},
  	.probe		= ep93xx_gpio_probe,
  };
  
  static int __init ep93xx_gpio_init(void)
  {
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
418
  	return platform_driver_register(&ep93xx_gpio_driver);
b685004f8   Ryan Mallon   [ARM] 4988/1: Add...
419
  }
1e4c88420   H Hartley Sweeten   gpio/ep93xx: conv...
420
421
422
423
424
425
  postcore_initcall(ep93xx_gpio_init);
  
  MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com> "
  		"H Hartley Sweeten <hsweeten@visionengravers.com>");
  MODULE_DESCRIPTION("EP93XX GPIO driver");
  MODULE_LICENSE("GPL");