diff options
author | Weike Chen <alvin.chen@intel.com> | 2014-09-17 12:18:39 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2014-09-23 11:51:37 -0400 |
commit | 3d2613c4289ff22de3aa24d2d0a29e33937f023a (patch) | |
tree | 30e95e5c3f8db19249743f1de2e493dc3fd58f27 /drivers/gpio | |
parent | e1db1706c86ee455f25eeaeadeda827e1e02310f (diff) |
GPIO: gpio-dwapb: Enable platform driver binding to MFD driver
The Synopsys DesignWare APB GPIO driver only supports open firmware devices.
But, like Intel Quark X1000 SOC, which has a single PCI function exporting
a GPIO and an I2C controller, it is a Multifunction device. This patch is
to enable the current Synopsys DesignWare APB GPIO driver to support the
Multifunction device which exports the designware GPIO controller.
Reviewed-by: Hock Leong Kweh <hock.leong.kweh@intel.com>
Signed-off-by: Weike Chen <alvin.chen@intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-dwapb.c | 224 |
2 files changed, 167 insertions, 58 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ec398bee7c60..d9ffb6dfa54b 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -136,7 +136,6 @@ config GPIO_DWAPB | |||
136 | tristate "Synopsys DesignWare APB GPIO driver" | 136 | tristate "Synopsys DesignWare APB GPIO driver" |
137 | select GPIO_GENERIC | 137 | select GPIO_GENERIC |
138 | select GENERIC_IRQ_CHIP | 138 | select GENERIC_IRQ_CHIP |
139 | depends on OF_GPIO | ||
140 | help | 139 | help |
141 | Say Y or M here to build support for the Synopsys DesignWare APB | 140 | Say Y or M here to build support for the Synopsys DesignWare APB |
142 | GPIO block. | 141 | GPIO block. |
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index d6618a6e2399..27466b5af5e8 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/of_irq.h> | 21 | #include <linux/of_irq.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <linux/platform_data/gpio-dwapb.h> | ||
25 | #include <linux/slab.h> | ||
24 | 26 | ||
25 | #define GPIO_SWPORTA_DR 0x00 | 27 | #define GPIO_SWPORTA_DR 0x00 |
26 | #define GPIO_SWPORTA_DDR 0x04 | 28 | #define GPIO_SWPORTA_DDR 0x04 |
@@ -84,11 +86,10 @@ static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs) | |||
84 | writel(v, gpio->regs + GPIO_INT_POLARITY); | 86 | writel(v, gpio->regs + GPIO_INT_POLARITY); |
85 | } | 87 | } |
86 | 88 | ||
87 | static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) | 89 | static u32 dwapb_do_irq(struct dwapb_gpio *gpio) |
88 | { | 90 | { |
89 | struct dwapb_gpio *gpio = irq_get_handler_data(irq); | ||
90 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
91 | u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS); | 91 | u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS); |
92 | u32 ret = irq_status; | ||
92 | 93 | ||
93 | while (irq_status) { | 94 | while (irq_status) { |
94 | int hwirq = fls(irq_status) - 1; | 95 | int hwirq = fls(irq_status) - 1; |
@@ -102,6 +103,16 @@ static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) | |||
102 | dwapb_toggle_trigger(gpio, hwirq); | 103 | dwapb_toggle_trigger(gpio, hwirq); |
103 | } | 104 | } |
104 | 105 | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) | ||
110 | { | ||
111 | struct dwapb_gpio *gpio = irq_get_handler_data(irq); | ||
112 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
113 | |||
114 | dwapb_do_irq(gpio); | ||
115 | |||
105 | if (chip->irq_eoi) | 116 | if (chip->irq_eoi) |
106 | chip->irq_eoi(irq_desc_get_irq_data(desc)); | 117 | chip->irq_eoi(irq_desc_get_irq_data(desc)); |
107 | } | 118 | } |
@@ -207,22 +218,26 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type) | |||
207 | return 0; | 218 | return 0; |
208 | } | 219 | } |
209 | 220 | ||
221 | static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id) | ||
222 | { | ||
223 | u32 worked; | ||
224 | struct dwapb_gpio *gpio = dev_id; | ||
225 | |||
226 | worked = dwapb_do_irq(gpio); | ||
227 | |||
228 | return worked ? IRQ_HANDLED : IRQ_NONE; | ||
229 | } | ||
230 | |||
210 | static void dwapb_configure_irqs(struct dwapb_gpio *gpio, | 231 | static void dwapb_configure_irqs(struct dwapb_gpio *gpio, |
211 | struct dwapb_gpio_port *port) | 232 | struct dwapb_gpio_port *port, |
233 | struct dwapb_port_property *pp) | ||
212 | { | 234 | { |
213 | struct gpio_chip *gc = &port->bgc.gc; | 235 | struct gpio_chip *gc = &port->bgc.gc; |
214 | struct device_node *node = gc->of_node; | 236 | struct device_node *node = pp->node; |
215 | struct irq_chip_generic *irq_gc; | 237 | struct irq_chip_generic *irq_gc = NULL; |
216 | unsigned int hwirq, ngpio = gc->ngpio; | 238 | unsigned int hwirq, ngpio = gc->ngpio; |
217 | struct irq_chip_type *ct; | 239 | struct irq_chip_type *ct; |
218 | int err, irq, i; | 240 | int err, i; |
219 | |||
220 | irq = irq_of_parse_and_map(node, 0); | ||
221 | if (!irq) { | ||
222 | dev_warn(gpio->dev, "no irq for bank %s\n", | ||
223 | port->bgc.gc.of_node->full_name); | ||
224 | return; | ||
225 | } | ||
226 | 241 | ||
227 | gpio->domain = irq_domain_add_linear(node, ngpio, | 242 | gpio->domain = irq_domain_add_linear(node, ngpio, |
228 | &irq_generic_chip_ops, gpio); | 243 | &irq_generic_chip_ops, gpio); |
@@ -269,8 +284,24 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio, | |||
269 | irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; | 284 | irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH; |
270 | irq_gc->chip_types[1].handler = handle_edge_irq; | 285 | irq_gc->chip_types[1].handler = handle_edge_irq; |
271 | 286 | ||
272 | irq_set_chained_handler(irq, dwapb_irq_handler); | 287 | if (!pp->irq_shared) { |
273 | irq_set_handler_data(irq, gpio); | 288 | irq_set_chained_handler(pp->irq, dwapb_irq_handler); |
289 | irq_set_handler_data(pp->irq, gpio); | ||
290 | } else { | ||
291 | /* | ||
292 | * Request a shared IRQ since where MFD would have devices | ||
293 | * using the same irq pin | ||
294 | */ | ||
295 | err = devm_request_irq(gpio->dev, pp->irq, | ||
296 | dwapb_irq_handler_mfd, | ||
297 | IRQF_SHARED, "gpio-dwapb-mfd", gpio); | ||
298 | if (err) { | ||
299 | dev_err(gpio->dev, "error requesting IRQ\n"); | ||
300 | irq_domain_remove(gpio->domain); | ||
301 | gpio->domain = NULL; | ||
302 | return; | ||
303 | } | ||
304 | } | ||
274 | 305 | ||
275 | for (hwirq = 0 ; hwirq < ngpio ; hwirq++) | 306 | for (hwirq = 0 ; hwirq < ngpio ; hwirq++) |
276 | irq_create_mapping(gpio->domain, hwirq); | 307 | irq_create_mapping(gpio->domain, hwirq); |
@@ -296,57 +327,42 @@ static void dwapb_irq_teardown(struct dwapb_gpio *gpio) | |||
296 | } | 327 | } |
297 | 328 | ||
298 | static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, | 329 | static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, |
299 | struct device_node *port_np, | 330 | struct dwapb_port_property *pp, |
300 | unsigned int offs) | 331 | unsigned int offs) |
301 | { | 332 | { |
302 | struct dwapb_gpio_port *port; | 333 | struct dwapb_gpio_port *port; |
303 | u32 port_idx, ngpio; | ||
304 | void __iomem *dat, *set, *dirout; | 334 | void __iomem *dat, *set, *dirout; |
305 | int err; | 335 | int err; |
306 | 336 | ||
307 | if (of_property_read_u32(port_np, "reg", &port_idx) || | ||
308 | port_idx >= DWAPB_MAX_PORTS) { | ||
309 | dev_err(gpio->dev, "missing/invalid port index for %s\n", | ||
310 | port_np->full_name); | ||
311 | return -EINVAL; | ||
312 | } | ||
313 | |||
314 | port = &gpio->ports[offs]; | 337 | port = &gpio->ports[offs]; |
315 | port->gpio = gpio; | 338 | port->gpio = gpio; |
316 | 339 | ||
317 | if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) { | 340 | dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_SIZE); |
318 | dev_info(gpio->dev, "failed to get number of gpios for %s\n", | 341 | set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_SIZE); |
319 | port_np->full_name); | ||
320 | ngpio = 32; | ||
321 | } | ||
322 | |||
323 | dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE); | ||
324 | set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE); | ||
325 | dirout = gpio->regs + GPIO_SWPORTA_DDR + | 342 | dirout = gpio->regs + GPIO_SWPORTA_DDR + |
326 | (port_idx * GPIO_SWPORT_DDR_SIZE); | 343 | (pp->idx * GPIO_SWPORT_DDR_SIZE); |
327 | 344 | ||
328 | err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout, | 345 | err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout, |
329 | NULL, false); | 346 | NULL, false); |
330 | if (err) { | 347 | if (err) { |
331 | dev_err(gpio->dev, "failed to init gpio chip for %s\n", | 348 | dev_err(gpio->dev, "failed to init gpio chip for %s\n", |
332 | port_np->full_name); | 349 | pp->name); |
333 | return err; | 350 | return err; |
334 | } | 351 | } |
335 | 352 | ||
336 | port->bgc.gc.ngpio = ngpio; | 353 | #ifdef CONFIG_OF_GPIO |
337 | port->bgc.gc.of_node = port_np; | 354 | port->bgc.gc.of_node = pp->node; |
355 | #endif | ||
356 | port->bgc.gc.ngpio = pp->ngpio; | ||
357 | port->bgc.gc.base = pp->gpio_base; | ||
338 | 358 | ||
339 | /* | 359 | if (pp->irq) |
340 | * Only port A can provide interrupts in all configurations of the IP. | 360 | dwapb_configure_irqs(gpio, port, pp); |
341 | */ | ||
342 | if (port_idx == 0 && | ||
343 | of_property_read_bool(port_np, "interrupt-controller")) | ||
344 | dwapb_configure_irqs(gpio, port); | ||
345 | 361 | ||
346 | err = gpiochip_add(&port->bgc.gc); | 362 | err = gpiochip_add(&port->bgc.gc); |
347 | if (err) | 363 | if (err) |
348 | dev_err(gpio->dev, "failed to register gpiochip for %s\n", | 364 | dev_err(gpio->dev, "failed to register gpiochip for %s\n", |
349 | port_np->full_name); | 365 | pp->name); |
350 | else | 366 | else |
351 | port->is_registered = true; | 367 | port->is_registered = true; |
352 | 368 | ||
@@ -362,25 +378,116 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio) | |||
362 | gpiochip_remove(&gpio->ports[m].bgc.gc); | 378 | gpiochip_remove(&gpio->ports[m].bgc.gc); |
363 | } | 379 | } |
364 | 380 | ||
381 | static struct dwapb_platform_data * | ||
382 | dwapb_gpio_get_pdata_of(struct device *dev) | ||
383 | { | ||
384 | struct device_node *node, *port_np; | ||
385 | struct dwapb_platform_data *pdata; | ||
386 | struct dwapb_port_property *pp; | ||
387 | int nports; | ||
388 | int i; | ||
389 | |||
390 | node = dev->of_node; | ||
391 | if (!IS_ENABLED(CONFIG_OF_GPIO) || !node) | ||
392 | return ERR_PTR(-ENODEV); | ||
393 | |||
394 | nports = of_get_child_count(node); | ||
395 | if (nports == 0) | ||
396 | return ERR_PTR(-ENODEV); | ||
397 | |||
398 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
399 | if (!pdata) | ||
400 | return ERR_PTR(-ENOMEM); | ||
401 | |||
402 | pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL); | ||
403 | if (!pdata->properties) { | ||
404 | kfree(pdata); | ||
405 | return ERR_PTR(-ENOMEM); | ||
406 | } | ||
407 | |||
408 | pdata->nports = nports; | ||
409 | |||
410 | i = 0; | ||
411 | for_each_child_of_node(node, port_np) { | ||
412 | pp = &pdata->properties[i++]; | ||
413 | pp->node = port_np; | ||
414 | |||
415 | if (of_property_read_u32(port_np, "reg", &pp->idx) || | ||
416 | pp->idx >= DWAPB_MAX_PORTS) { | ||
417 | dev_err(dev, "missing/invalid port index for %s\n", | ||
418 | port_np->full_name); | ||
419 | kfree(pdata->properties); | ||
420 | kfree(pdata); | ||
421 | return ERR_PTR(-EINVAL); | ||
422 | } | ||
423 | |||
424 | if (of_property_read_u32(port_np, "snps,nr-gpios", | ||
425 | &pp->ngpio)) { | ||
426 | dev_info(dev, "failed to get number of gpios for %s\n", | ||
427 | port_np->full_name); | ||
428 | pp->ngpio = 32; | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | * Only port A can provide interrupts in all configurations of | ||
433 | * the IP. | ||
434 | */ | ||
435 | if (pp->idx == 0 && | ||
436 | of_property_read_bool(port_np, "interrupt-controller")) { | ||
437 | pp->irq = irq_of_parse_and_map(port_np, 0); | ||
438 | if (!pp->irq) { | ||
439 | dev_warn(dev, "no irq for bank %s\n", | ||
440 | port_np->full_name); | ||
441 | } | ||
442 | } | ||
443 | |||
444 | pp->irq_shared = false; | ||
445 | pp->gpio_base = -1; | ||
446 | pp->name = port_np->full_name; | ||
447 | } | ||
448 | |||
449 | return pdata; | ||
450 | } | ||
451 | |||
452 | static inline void dwapb_free_pdata_of(struct dwapb_platform_data *pdata) | ||
453 | { | ||
454 | if (!IS_ENABLED(CONFIG_OF_GPIO) || !pdata) | ||
455 | return; | ||
456 | |||
457 | kfree(pdata->properties); | ||
458 | kfree(pdata); | ||
459 | } | ||
460 | |||
365 | static int dwapb_gpio_probe(struct platform_device *pdev) | 461 | static int dwapb_gpio_probe(struct platform_device *pdev) |
366 | { | 462 | { |
463 | unsigned int i; | ||
367 | struct resource *res; | 464 | struct resource *res; |
368 | struct dwapb_gpio *gpio; | 465 | struct dwapb_gpio *gpio; |
369 | struct device_node *np; | ||
370 | int err; | 466 | int err; |
371 | unsigned int offs = 0; | 467 | struct device *dev = &pdev->dev; |
468 | struct dwapb_platform_data *pdata = dev_get_platdata(dev); | ||
469 | bool is_pdata_alloc = !pdata; | ||
470 | |||
471 | if (is_pdata_alloc) { | ||
472 | pdata = dwapb_gpio_get_pdata_of(dev); | ||
473 | if (IS_ERR(pdata)) | ||
474 | return PTR_ERR(pdata); | ||
475 | } | ||
372 | 476 | ||
373 | gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); | 477 | if (!pdata->nports) { |
374 | if (!gpio) | 478 | err = -ENODEV; |
375 | return -ENOMEM; | 479 | goto out_err; |
376 | gpio->dev = &pdev->dev; | 480 | } |
377 | 481 | ||
378 | gpio->nr_ports = of_get_child_count(pdev->dev.of_node); | 482 | gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); |
379 | if (!gpio->nr_ports) { | 483 | if (!gpio) { |
380 | err = -EINVAL; | 484 | err = -ENOMEM; |
381 | goto out_err; | 485 | goto out_err; |
382 | } | 486 | } |
383 | gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports * | 487 | gpio->dev = &pdev->dev; |
488 | gpio->nr_ports = pdata->nports; | ||
489 | |||
490 | gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports, | ||
384 | sizeof(*gpio->ports), GFP_KERNEL); | 491 | sizeof(*gpio->ports), GFP_KERNEL); |
385 | if (!gpio->ports) { | 492 | if (!gpio->ports) { |
386 | err = -ENOMEM; | 493 | err = -ENOMEM; |
@@ -394,20 +501,23 @@ static int dwapb_gpio_probe(struct platform_device *pdev) | |||
394 | goto out_err; | 501 | goto out_err; |
395 | } | 502 | } |
396 | 503 | ||
397 | for_each_child_of_node(pdev->dev.of_node, np) { | 504 | for (i = 0; i < gpio->nr_ports; i++) { |
398 | err = dwapb_gpio_add_port(gpio, np, offs++); | 505 | err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i); |
399 | if (err) | 506 | if (err) |
400 | goto out_unregister; | 507 | goto out_unregister; |
401 | } | 508 | } |
402 | platform_set_drvdata(pdev, gpio); | 509 | platform_set_drvdata(pdev, gpio); |
403 | 510 | ||
404 | return 0; | 511 | goto out_err; |
405 | 512 | ||
406 | out_unregister: | 513 | out_unregister: |
407 | dwapb_gpio_unregister(gpio); | 514 | dwapb_gpio_unregister(gpio); |
408 | dwapb_irq_teardown(gpio); | 515 | dwapb_irq_teardown(gpio); |
409 | 516 | ||
410 | out_err: | 517 | out_err: |
518 | if (is_pdata_alloc) | ||
519 | dwapb_free_pdata_of(pdata); | ||
520 | |||
411 | return err; | 521 | return err; |
412 | } | 522 | } |
413 | 523 | ||