blob: 5c15dd12172db3cf38945dc347f9c1e71ac81971 [file] [log] [blame]
Rabin Vincentd3425712015-06-06 22:30:40 +02001#include <linux/kernel.h>
2#include <linux/init.h>
3#include <linux/gpio.h>
Rabin Vincent29b53572015-07-31 14:48:57 +02004#include <linux/gpio/driver.h>
Rabin Vincentd3425712015-06-06 22:30:40 +02005#include <linux/of_gpio.h>
6#include <linux/io.h>
Rabin Vincent29b53572015-07-31 14:48:57 +02007#include <linux/interrupt.h>
Rabin Vincentd3425712015-06-06 22:30:40 +02008#include <linux/platform_device.h>
9#include <linux/basic_mmio_gpio.h>
10
11#define ETRAX_FS_rw_pa_dout 0
12#define ETRAX_FS_r_pa_din 4
13#define ETRAX_FS_rw_pa_oe 8
14#define ETRAX_FS_rw_intr_cfg 12
15#define ETRAX_FS_rw_intr_mask 16
16#define ETRAX_FS_rw_ack_intr 20
17#define ETRAX_FS_r_intr 24
Rabin Vincent29b53572015-07-31 14:48:57 +020018#define ETRAX_FS_r_masked_intr 28
Rabin Vincentd3425712015-06-06 22:30:40 +020019#define ETRAX_FS_rw_pb_dout 32
20#define ETRAX_FS_r_pb_din 36
21#define ETRAX_FS_rw_pb_oe 40
22#define ETRAX_FS_rw_pc_dout 48
23#define ETRAX_FS_r_pc_din 52
24#define ETRAX_FS_rw_pc_oe 56
25#define ETRAX_FS_rw_pd_dout 64
26#define ETRAX_FS_r_pd_din 68
27#define ETRAX_FS_rw_pd_oe 72
28#define ETRAX_FS_rw_pe_dout 80
29#define ETRAX_FS_r_pe_din 84
30#define ETRAX_FS_rw_pe_oe 88
31
Rabin Vincentd7050732015-07-22 15:05:19 +020032#define ARTPEC3_r_pa_din 0
33#define ARTPEC3_rw_pa_dout 4
34#define ARTPEC3_rw_pa_oe 8
35#define ARTPEC3_r_pb_din 44
36#define ARTPEC3_rw_pb_dout 48
37#define ARTPEC3_rw_pb_oe 52
38#define ARTPEC3_r_pc_din 88
39#define ARTPEC3_rw_pc_dout 92
40#define ARTPEC3_rw_pc_oe 96
41#define ARTPEC3_r_pd_din 116
Rabin Vincent29b53572015-07-31 14:48:57 +020042#define ARTPEC3_rw_intr_cfg 120
43#define ARTPEC3_rw_intr_pins 124
44#define ARTPEC3_rw_intr_mask 128
45#define ARTPEC3_rw_ack_intr 132
46#define ARTPEC3_r_masked_intr 140
47
48#define GIO_CFG_OFF 0
49#define GIO_CFG_HI 1
50#define GIO_CFG_LO 2
51#define GIO_CFG_SET 3
52#define GIO_CFG_POSEDGE 5
53#define GIO_CFG_NEGEDGE 6
54#define GIO_CFG_ANYEDGE 7
55
56struct etraxfs_gpio_info;
57
58struct etraxfs_gpio_block {
59 spinlock_t lock;
60 u32 mask;
61 u32 cfg;
62 u32 pins;
63 unsigned int group[8];
64
65 void __iomem *regs;
66 const struct etraxfs_gpio_info *info;
67};
68
69struct etraxfs_gpio_chip {
70 struct bgpio_chip bgc;
71 struct etraxfs_gpio_block *block;
72};
Rabin Vincentd7050732015-07-22 15:05:19 +020073
Rabin Vincentd3425712015-06-06 22:30:40 +020074struct etraxfs_gpio_port {
75 const char *label;
76 unsigned int oe;
77 unsigned int dout;
78 unsigned int din;
79 unsigned int ngpio;
80};
81
82struct etraxfs_gpio_info {
83 unsigned int num_ports;
84 const struct etraxfs_gpio_port *ports;
Rabin Vincent29b53572015-07-31 14:48:57 +020085
86 unsigned int rw_ack_intr;
87 unsigned int rw_intr_mask;
88 unsigned int rw_intr_cfg;
89 unsigned int rw_intr_pins;
90 unsigned int r_masked_intr;
Rabin Vincentd3425712015-06-06 22:30:40 +020091};
92
93static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = {
94 {
95 .label = "A",
96 .ngpio = 8,
97 .oe = ETRAX_FS_rw_pa_oe,
98 .dout = ETRAX_FS_rw_pa_dout,
99 .din = ETRAX_FS_r_pa_din,
100 },
101 {
102 .label = "B",
103 .ngpio = 18,
104 .oe = ETRAX_FS_rw_pb_oe,
105 .dout = ETRAX_FS_rw_pb_dout,
106 .din = ETRAX_FS_r_pb_din,
107 },
108 {
109 .label = "C",
110 .ngpio = 18,
111 .oe = ETRAX_FS_rw_pc_oe,
112 .dout = ETRAX_FS_rw_pc_dout,
113 .din = ETRAX_FS_r_pc_din,
114 },
115 {
116 .label = "D",
117 .ngpio = 18,
118 .oe = ETRAX_FS_rw_pd_oe,
119 .dout = ETRAX_FS_rw_pd_dout,
120 .din = ETRAX_FS_r_pd_din,
121 },
122 {
123 .label = "E",
124 .ngpio = 18,
125 .oe = ETRAX_FS_rw_pe_oe,
126 .dout = ETRAX_FS_rw_pe_dout,
127 .din = ETRAX_FS_r_pe_din,
128 },
129};
130
131static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = {
132 .num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports),
133 .ports = etraxfs_gpio_etraxfs_ports,
Rabin Vincent29b53572015-07-31 14:48:57 +0200134 .rw_ack_intr = ETRAX_FS_rw_ack_intr,
135 .rw_intr_mask = ETRAX_FS_rw_intr_mask,
136 .rw_intr_cfg = ETRAX_FS_rw_intr_cfg,
137 .r_masked_intr = ETRAX_FS_r_masked_intr,
Rabin Vincentd3425712015-06-06 22:30:40 +0200138};
139
Rabin Vincentd7050732015-07-22 15:05:19 +0200140static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = {
141 {
142 .label = "A",
143 .ngpio = 32,
144 .oe = ARTPEC3_rw_pa_oe,
145 .dout = ARTPEC3_rw_pa_dout,
146 .din = ARTPEC3_r_pa_din,
147 },
148 {
149 .label = "B",
150 .ngpio = 32,
151 .oe = ARTPEC3_rw_pb_oe,
152 .dout = ARTPEC3_rw_pb_dout,
153 .din = ARTPEC3_r_pb_din,
154 },
155 {
156 .label = "C",
157 .ngpio = 16,
158 .oe = ARTPEC3_rw_pc_oe,
159 .dout = ARTPEC3_rw_pc_dout,
160 .din = ARTPEC3_r_pc_din,
161 },
162 {
163 .label = "D",
164 .ngpio = 32,
165 .din = ARTPEC3_r_pd_din,
166 },
167};
168
169static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = {
170 .num_ports = ARRAY_SIZE(etraxfs_gpio_artpec3_ports),
171 .ports = etraxfs_gpio_artpec3_ports,
Rabin Vincent29b53572015-07-31 14:48:57 +0200172 .rw_ack_intr = ARTPEC3_rw_ack_intr,
173 .rw_intr_mask = ARTPEC3_rw_intr_mask,
174 .rw_intr_cfg = ARTPEC3_rw_intr_cfg,
175 .r_masked_intr = ARTPEC3_r_masked_intr,
176 .rw_intr_pins = ARTPEC3_rw_intr_pins,
Rabin Vincentd7050732015-07-22 15:05:19 +0200177};
178
Linus Walleij48432892015-08-25 10:40:23 +0200179static struct etraxfs_gpio_chip *to_etraxfs(struct gpio_chip *gc)
180{
181 return container_of(gc, struct etraxfs_gpio_chip, bgc.gc);
182}
183
Rabin Vincent29b53572015-07-31 14:48:57 +0200184static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc)
185{
186 return gc->label[0] - 'A';
187}
188
Rabin Vincentd3425712015-06-06 22:30:40 +0200189static int etraxfs_gpio_of_xlate(struct gpio_chip *gc,
190 const struct of_phandle_args *gpiospec,
191 u32 *flags)
192{
193 /*
194 * Port numbers are A to E, and the properties are integers, so we
195 * specify them as 0xA - 0xE.
196 */
Rabin Vincent29b53572015-07-31 14:48:57 +0200197 if (etraxfs_gpio_chip_to_port(gc) + 0xA != gpiospec->args[2])
Rabin Vincentd3425712015-06-06 22:30:40 +0200198 return -EINVAL;
199
200 return of_gpio_simple_xlate(gc, gpiospec, flags);
201}
202
203static const struct of_device_id etraxfs_gpio_of_table[] = {
204 {
205 .compatible = "axis,etraxfs-gio",
206 .data = &etraxfs_gpio_etraxfs,
207 },
Rabin Vincentd7050732015-07-22 15:05:19 +0200208 {
209 .compatible = "axis,artpec3-gio",
210 .data = &etraxfs_gpio_artpec3,
211 },
Rabin Vincentd3425712015-06-06 22:30:40 +0200212 {},
213};
214
Rabin Vincent29b53572015-07-31 14:48:57 +0200215static unsigned int etraxfs_gpio_to_group_irq(unsigned int gpio)
216{
217 return gpio % 8;
218}
219
220static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip,
221 unsigned int gpio)
222{
223 return 4 * etraxfs_gpio_chip_to_port(&chip->bgc.gc) + gpio / 8;
224}
225
226static void etraxfs_gpio_irq_ack(struct irq_data *d)
227{
Linus Walleij48432892015-08-25 10:40:23 +0200228 struct etraxfs_gpio_chip *chip =
229 to_etraxfs(irq_data_get_irq_chip_data(d));
Rabin Vincent29b53572015-07-31 14:48:57 +0200230 struct etraxfs_gpio_block *block = chip->block;
231 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
232
233 writel(BIT(grpirq), block->regs + block->info->rw_ack_intr);
234}
235
236static void etraxfs_gpio_irq_mask(struct irq_data *d)
237{
Linus Walleij48432892015-08-25 10:40:23 +0200238 struct etraxfs_gpio_chip *chip =
239 to_etraxfs(irq_data_get_irq_chip_data(d));
Rabin Vincent29b53572015-07-31 14:48:57 +0200240 struct etraxfs_gpio_block *block = chip->block;
241 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
242
243 spin_lock(&block->lock);
244 block->mask &= ~BIT(grpirq);
245 writel(block->mask, block->regs + block->info->rw_intr_mask);
246 spin_unlock(&block->lock);
247}
248
249static void etraxfs_gpio_irq_unmask(struct irq_data *d)
250{
Linus Walleij48432892015-08-25 10:40:23 +0200251 struct etraxfs_gpio_chip *chip =
252 to_etraxfs(irq_data_get_irq_chip_data(d));
Rabin Vincent29b53572015-07-31 14:48:57 +0200253 struct etraxfs_gpio_block *block = chip->block;
254 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
255
256 spin_lock(&block->lock);
257 block->mask |= BIT(grpirq);
258 writel(block->mask, block->regs + block->info->rw_intr_mask);
259 spin_unlock(&block->lock);
260}
261
262static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
263{
Linus Walleij48432892015-08-25 10:40:23 +0200264 struct etraxfs_gpio_chip *chip =
265 to_etraxfs(irq_data_get_irq_chip_data(d));
Rabin Vincent29b53572015-07-31 14:48:57 +0200266 struct etraxfs_gpio_block *block = chip->block;
267 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
268 u32 cfg;
269
270 switch (type) {
271 case IRQ_TYPE_EDGE_RISING:
272 cfg = GIO_CFG_POSEDGE;
273 break;
274 case IRQ_TYPE_EDGE_FALLING:
275 cfg = GIO_CFG_NEGEDGE;
276 break;
277 case IRQ_TYPE_EDGE_BOTH:
278 cfg = GIO_CFG_ANYEDGE;
279 break;
280 case IRQ_TYPE_LEVEL_LOW:
281 cfg = GIO_CFG_LO;
282 break;
283 case IRQ_TYPE_LEVEL_HIGH:
284 cfg = GIO_CFG_HI;
285 break;
286 default:
287 return -EINVAL;
288 }
289
290 spin_lock(&block->lock);
291 block->cfg &= ~(0x7 << (grpirq * 3));
292 block->cfg |= (cfg << (grpirq * 3));
293 writel(block->cfg, block->regs + block->info->rw_intr_cfg);
294 spin_unlock(&block->lock);
295
296 return 0;
297}
298
299static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
300{
Linus Walleij48432892015-08-25 10:40:23 +0200301 struct etraxfs_gpio_chip *chip =
302 to_etraxfs(irq_data_get_irq_chip_data(d));
Rabin Vincent29b53572015-07-31 14:48:57 +0200303 struct etraxfs_gpio_block *block = chip->block;
304 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
Linus Walleij01e2dae2015-08-31 08:56:04 +0200305 int ret = -EBUSY;
Rabin Vincent29b53572015-07-31 14:48:57 +0200306
307 spin_lock(&block->lock);
308 if (block->group[grpirq])
309 goto out;
310
311 ret = gpiochip_lock_as_irq(&chip->bgc.gc, d->hwirq);
312 if (ret)
313 goto out;
314
315 block->group[grpirq] = d->irq;
316 if (block->info->rw_intr_pins) {
317 unsigned int pin = etraxfs_gpio_to_group_pin(chip, d->hwirq);
318
319 block->pins &= ~(0xf << (grpirq * 4));
320 block->pins |= (pin << (grpirq * 4));
321
322 writel(block->pins, block->regs + block->info->rw_intr_pins);
323 }
324
325out:
326 spin_unlock(&block->lock);
Linus Walleij01e2dae2015-08-31 08:56:04 +0200327 return ret;
Rabin Vincent29b53572015-07-31 14:48:57 +0200328}
329
330static void etraxfs_gpio_irq_release_resources(struct irq_data *d)
331{
Linus Walleij48432892015-08-25 10:40:23 +0200332 struct etraxfs_gpio_chip *chip =
333 to_etraxfs(irq_data_get_irq_chip_data(d));
Rabin Vincent29b53572015-07-31 14:48:57 +0200334 struct etraxfs_gpio_block *block = chip->block;
335 unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
336
337 spin_lock(&block->lock);
338 block->group[grpirq] = 0;
339 gpiochip_unlock_as_irq(&chip->bgc.gc, d->hwirq);
340 spin_unlock(&block->lock);
341}
342
343static struct irq_chip etraxfs_gpio_irq_chip = {
344 .name = "gpio-etraxfs",
345 .irq_ack = etraxfs_gpio_irq_ack,
346 .irq_mask = etraxfs_gpio_irq_mask,
347 .irq_unmask = etraxfs_gpio_irq_unmask,
348 .irq_set_type = etraxfs_gpio_irq_set_type,
349 .irq_request_resources = etraxfs_gpio_irq_request_resources,
350 .irq_release_resources = etraxfs_gpio_irq_release_resources,
351};
352
353static irqreturn_t etraxfs_gpio_interrupt(int irq, void *dev_id)
354{
355 struct etraxfs_gpio_block *block = dev_id;
356 unsigned long intr = readl(block->regs + block->info->r_masked_intr);
357 int bit;
358
359 for_each_set_bit(bit, &intr, 8)
360 generic_handle_irq(block->group[bit]);
361
362 return IRQ_RETVAL(intr & 0xff);
363}
364
Rabin Vincentd3425712015-06-06 22:30:40 +0200365static int etraxfs_gpio_probe(struct platform_device *pdev)
366{
367 struct device *dev = &pdev->dev;
368 const struct etraxfs_gpio_info *info;
369 const struct of_device_id *match;
Rabin Vincent29b53572015-07-31 14:48:57 +0200370 struct etraxfs_gpio_block *block;
371 struct etraxfs_gpio_chip *chips;
372 struct resource *res, *irq;
373 bool allportsirq = false;
Rabin Vincentd3425712015-06-06 22:30:40 +0200374 void __iomem *regs;
375 int ret;
376 int i;
377
378 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
379 regs = devm_ioremap_resource(dev, res);
Krzysztof Kozlowski01540312015-07-09 22:19:53 +0900380 if (IS_ERR(regs))
381 return PTR_ERR(regs);
Rabin Vincentd3425712015-06-06 22:30:40 +0200382
383 match = of_match_node(etraxfs_gpio_of_table, dev->of_node);
384 if (!match)
385 return -EINVAL;
386
387 info = match->data;
388
389 chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL);
390 if (!chips)
391 return -ENOMEM;
392
Rabin Vincent29b53572015-07-31 14:48:57 +0200393 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
394 if (!irq)
395 return -EINVAL;
396
397 block = devm_kzalloc(dev, sizeof(*block), GFP_KERNEL);
398 if (!block)
399 return -ENOMEM;
400
401 spin_lock_init(&block->lock);
402
403 block->regs = regs;
404 block->info = info;
405
406 writel(0, block->regs + info->rw_intr_mask);
407 writel(0, block->regs + info->rw_intr_cfg);
408 if (info->rw_intr_pins) {
409 allportsirq = true;
410 writel(0, block->regs + info->rw_intr_pins);
411 }
412
413 ret = devm_request_irq(dev, irq->start, etraxfs_gpio_interrupt,
414 IRQF_SHARED, dev_name(dev), block);
415 if (ret) {
416 dev_err(dev, "Unable to request irq %d\n", ret);
417 return ret;
418 }
419
Rabin Vincentd3425712015-06-06 22:30:40 +0200420 for (i = 0; i < info->num_ports; i++) {
Rabin Vincent29b53572015-07-31 14:48:57 +0200421 struct etraxfs_gpio_chip *chip = &chips[i];
422 struct bgpio_chip *bgc = &chip->bgc;
Rabin Vincentd3425712015-06-06 22:30:40 +0200423 const struct etraxfs_gpio_port *port = &info->ports[i];
Rabin Vincentd7050732015-07-22 15:05:19 +0200424 unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET;
425 void __iomem *dat = regs + port->din;
426 void __iomem *set = regs + port->dout;
427 void __iomem *dirout = regs + port->oe;
428
Rabin Vincent29b53572015-07-31 14:48:57 +0200429 chip->block = block;
430
Rabin Vincentd7050732015-07-22 15:05:19 +0200431 if (dirout == set) {
432 dirout = set = NULL;
433 flags = BGPIOF_NO_OUTPUT;
434 }
Rabin Vincentd3425712015-06-06 22:30:40 +0200435
436 ret = bgpio_init(bgc, dev, 4,
Rabin Vincentd7050732015-07-22 15:05:19 +0200437 dat, set, NULL, dirout, NULL,
438 flags);
Rabin Vincent29b53572015-07-31 14:48:57 +0200439 if (ret) {
440 dev_err(dev, "Unable to init port %s\n",
441 port->label);
442 continue;
443 }
Rabin Vincentd3425712015-06-06 22:30:40 +0200444
445 bgc->gc.ngpio = port->ngpio;
446 bgc->gc.label = port->label;
447
448 bgc->gc.of_node = dev->of_node;
449 bgc->gc.of_gpio_n_cells = 3;
450 bgc->gc.of_xlate = etraxfs_gpio_of_xlate;
451
452 ret = gpiochip_add(&bgc->gc);
Rabin Vincent29b53572015-07-31 14:48:57 +0200453 if (ret) {
Rabin Vincentd3425712015-06-06 22:30:40 +0200454 dev_err(dev, "Unable to register port %s\n",
455 bgc->gc.label);
Rabin Vincent29b53572015-07-31 14:48:57 +0200456 continue;
457 }
458
459 if (i > 0 && !allportsirq)
460 continue;
461
462 ret = gpiochip_irqchip_add(&bgc->gc, &etraxfs_gpio_irq_chip, 0,
463 handle_level_irq, IRQ_TYPE_NONE);
464 if (ret) {
465 dev_err(dev, "Unable to add irqchip to port %s\n",
466 bgc->gc.label);
467 }
Rabin Vincentd3425712015-06-06 22:30:40 +0200468 }
469
470 return 0;
471}
472
473static struct platform_driver etraxfs_gpio_driver = {
474 .driver = {
475 .name = "etraxfs-gpio",
476 .of_match_table = of_match_ptr(etraxfs_gpio_of_table),
477 },
478 .probe = etraxfs_gpio_probe,
479};
480
481static int __init etraxfs_gpio_init(void)
482{
483 return platform_driver_register(&etraxfs_gpio_driver);
484}
485
486device_initcall(etraxfs_gpio_init);