Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: ixp4xx: Add OF probing support

This adds device tree probe and registration support for
the IXP4xx GPIO driver.

Cc: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

+56 -26
+56 -26
drivers/gpio/gpio-ixp4xx.c
··· 11 11 #include <linux/irq.h> 12 12 #include <linux/irqdomain.h> 13 13 #include <linux/irqchip.h> 14 + #include <linux/of_irq.h> 14 15 #include <linux/platform_device.h> 15 16 #include <linux/bitops.h> 16 17 /* Include that go away with DT transition */ ··· 307 306 { 308 307 unsigned long flags; 309 308 struct device *dev = &pdev->dev; 309 + struct device_node *np = dev->of_node; 310 310 struct irq_domain *parent; 311 311 struct resource *res; 312 312 struct ixp4xx_gpio *g; ··· 384 382 * from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get 385 383 * the fwnode. For now we need this boardfile style code. 386 384 */ 387 - parent = ixp4xx_get_irq_domain(); 388 - g->fwnode = irq_domain_alloc_fwnode(g->base); 389 - if (!g->fwnode) { 390 - dev_err(dev, "no domain base\n"); 391 - return -ENODEV; 385 + if (np) { 386 + struct device_node *irq_parent; 387 + 388 + irq_parent = of_irq_find_parent(np); 389 + if (!irq_parent) { 390 + dev_err(dev, "no IRQ parent node\n"); 391 + return -ENODEV; 392 + } 393 + parent = irq_find_host(irq_parent); 394 + if (!parent) { 395 + dev_err(dev, "no IRQ parent domain\n"); 396 + return -ENODEV; 397 + } 398 + g->fwnode = of_node_to_fwnode(np); 399 + } else { 400 + parent = ixp4xx_get_irq_domain(); 401 + g->fwnode = irq_domain_alloc_fwnode(g->base); 402 + if (!g->fwnode) { 403 + dev_err(dev, "no domain base\n"); 404 + return -ENODEV; 405 + } 392 406 } 393 407 g->domain = irq_domain_create_hierarchy(parent, 394 408 IRQ_DOMAIN_FLAG_HIERARCHY, ··· 422 404 * After adding OF support, this is no longer needed: irqs 423 405 * will be allocated for the respective fwnodes. 424 406 */ 425 - for (i = 0; i < ARRAY_SIZE(ixp4xx_gpiomap); i++) { 426 - const struct ixp4xx_gpio_map *map = &ixp4xx_gpiomap[i]; 427 - struct irq_fwspec fwspec; 407 + if (!np) { 408 + for (i = 0; i < ARRAY_SIZE(ixp4xx_gpiomap); i++) { 409 + const struct ixp4xx_gpio_map *map = &ixp4xx_gpiomap[i]; 410 + struct irq_fwspec fwspec; 428 411 429 - fwspec.fwnode = g->fwnode; 430 - /* This is the hwirq for the GPIO line side of things */ 431 - fwspec.param[0] = map->gpio_offset; 432 - fwspec.param[1] = IRQ_TYPE_EDGE_RISING; 433 - fwspec.param_count = 2; 434 - ret = __irq_domain_alloc_irqs(g->domain, 435 - -1, /* just pick something */ 436 - 1, 437 - NUMA_NO_NODE, 438 - &fwspec, 439 - false, 440 - NULL); 441 - if (ret < 0) { 442 - irq_domain_free_fwnode(g->fwnode); 443 - dev_err(dev, 444 - "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n", 445 - map->gpio_offset, map->parent_hwirq, ret); 446 - return ret; 412 + fwspec.fwnode = g->fwnode; 413 + /* This is the hwirq for the GPIO line side of things */ 414 + fwspec.param[0] = map->gpio_offset; 415 + fwspec.param[1] = IRQ_TYPE_EDGE_RISING; 416 + fwspec.param_count = 2; 417 + ret = __irq_domain_alloc_irqs(g->domain, 418 + -1, /* just pick something */ 419 + 1, 420 + NUMA_NO_NODE, 421 + &fwspec, 422 + false, 423 + NULL); 424 + if (ret < 0) { 425 + irq_domain_free_fwnode(g->fwnode); 426 + dev_err(dev, 427 + "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n", 428 + map->gpio_offset, map->parent_hwirq, 429 + ret); 430 + return ret; 431 + } 447 432 } 448 433 } 449 434 ··· 456 435 return 0; 457 436 } 458 437 438 + static const struct of_device_id ixp4xx_gpio_of_match[] = { 439 + { 440 + .compatible = "intel,ixp4xx-gpio", 441 + }, 442 + {}, 443 + }; 444 + 445 + 459 446 static struct platform_driver ixp4xx_gpio_driver = { 460 447 .driver = { 461 448 .name = "ixp4xx-gpio", 449 + .of_match_table = of_match_ptr(ixp4xx_gpio_of_match), 462 450 }, 463 451 .probe = ixp4xx_gpio_probe, 464 452 };