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

ARM/gpio: Push OMAP2 quirk down into TWL4030 driver

The TWL4030 GPIO driver has a custom platform data .set_up()
callback to call back into the platform and do misc stuff such
as hog and export a GPIO for WLAN PWR on a specific OMAP3 board.

Avoid all the kludgery in the platform data and the boardfile
and just put the quirks right into the driver. Make it
conditional on OMAP3.

I think the exported GPIO is used by some kind of userspace
so ordinary DTS hogs will probably not work.

Fixes: 92bf78b33b0b ("gpio: omap: use dynamic allocation of base")
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

+37 -60
-1
arch/arm/mach-omap2/omap_device.c
··· 244 244 case BUS_NOTIFY_ADD_DEVICE: 245 245 if (pdev->dev.of_node) 246 246 omap_device_build_from_dt(pdev); 247 - omap_auxdata_legacy_init(dev); 248 247 fallthrough; 249 248 default: 250 249 od = to_omap_device(pdev);
+1 -40
arch/arm/mach-omap2/pdata-quirks.c
··· 6 6 */ 7 7 #include <linux/clk.h> 8 8 #include <linux/davinci_emac.h> 9 + #include <linux/gpio/machine.h> 9 10 #include <linux/gpio/consumer.h> 10 11 #include <linux/gpio.h> 11 12 #include <linux/init.h> ··· 42 41 }; 43 42 44 43 static struct of_dev_auxdata omap_auxdata_lookup[]; 45 - static struct twl4030_gpio_platform_data twl_gpio_auxdata; 46 44 47 45 #ifdef CONFIG_MACH_NOKIA_N8X0 48 46 static void __init omap2420_n8x0_legacy_init(void) ··· 98 98 }; 99 99 #endif 100 100 101 - static int omap3_sbc_t3730_twl_callback(struct device *dev, 102 - unsigned gpio, 103 - unsigned ngpio) 104 - { 105 - int res; 106 - 107 - res = gpio_request_one(gpio + 2, GPIOF_OUT_INIT_HIGH, 108 - "wlan pwr"); 109 - if (res) 110 - return res; 111 - 112 - gpiod_export(gpio_to_desc(gpio), 0); 113 - 114 - return 0; 115 - } 116 - 117 101 static void __init omap3_sbc_t3x_usb_hub_init(int gpio, char *hub_name) 118 102 { 119 103 int err = gpio_request_one(gpio, GPIOF_OUT_INIT_LOW, hub_name); ··· 113 129 udelay(10); 114 130 gpio_set_value(gpio, 1); 115 131 msleep(1); 116 - } 117 - 118 - static void __init omap3_sbc_t3730_twl_init(void) 119 - { 120 - twl_gpio_auxdata.setup = omap3_sbc_t3730_twl_callback; 121 132 } 122 133 123 134 static void __init omap3_sbc_t3730_legacy_init(void) ··· 372 393 .clkdm_lookup = clkdm_lookup, 373 394 }; 374 395 375 - /* 376 - * GPIOs for TWL are initialized by the I2C bus and need custom 377 - * handing until DSS has device tree bindings. 378 - */ 379 - void omap_auxdata_legacy_init(struct device *dev) 380 - { 381 - if (dev->platform_data) 382 - return; 383 - 384 - if (strcmp("twl4030-gpio", dev_name(dev))) 385 - return; 386 - 387 - dev->platform_data = &twl_gpio_auxdata; 388 - } 389 - 390 396 #if defined(CONFIG_ARCH_OMAP3) && IS_ENABLED(CONFIG_SND_SOC_OMAP_MCBSP) 391 397 static struct omap_mcbsp_platform_data mcbsp_pdata; 392 398 static void __init omap3_mcbsp_init(void) ··· 391 427 { "nokia,n800", omap2420_n8x0_legacy_init, }, 392 428 { "nokia,n810", omap2420_n8x0_legacy_init, }, 393 429 { "nokia,n810-wimax", omap2420_n8x0_legacy_init, }, 394 - #endif 395 - #ifdef CONFIG_ARCH_OMAP3 396 - { "compulab,omap3-sbc-t3730", omap3_sbc_t3730_twl_init, }, 397 430 #endif 398 431 { /* sentinel */ }, 399 432 };
+36 -16
drivers/gpio/gpio-twl4030.c
··· 17 17 #include <linux/interrupt.h> 18 18 #include <linux/kthread.h> 19 19 #include <linux/irq.h> 20 + #include <linux/gpio/machine.h> 20 21 #include <linux/gpio/driver.h> 22 + #include <linux/gpio/consumer.h> 21 23 #include <linux/platform_device.h> 22 24 #include <linux/of.h> 23 25 #include <linux/irqdomain.h> ··· 467 465 REG_GPIO_DEBEN1, 3); 468 466 } 469 467 470 - static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev, 471 - struct twl4030_gpio_platform_data *pdata) 468 + static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) 472 469 { 473 470 struct twl4030_gpio_platform_data *omap_twl_info; 474 471 475 472 omap_twl_info = devm_kzalloc(dev, sizeof(*omap_twl_info), GFP_KERNEL); 476 473 if (!omap_twl_info) 477 474 return NULL; 478 - 479 - if (pdata) 480 - *omap_twl_info = *pdata; 481 475 482 476 omap_twl_info->use_leds = of_property_read_bool(dev->of_node, 483 477 "ti,use-leds"); ··· 502 504 return 0; 503 505 } 504 506 507 + /* Called from the registered devm action */ 508 + static void gpio_twl4030_power_off_action(void *data) 509 + { 510 + struct gpio_desc *d = data; 511 + 512 + gpiod_unexport(d); 513 + gpiochip_free_own_desc(d); 514 + } 515 + 505 516 static int gpio_twl4030_probe(struct platform_device *pdev) 506 517 { 507 - struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); 518 + struct twl4030_gpio_platform_data *pdata; 508 519 struct device_node *node = pdev->dev.of_node; 509 520 struct gpio_twl4030_priv *priv; 510 521 int ret, irq_base; ··· 553 546 554 547 mutex_init(&priv->mutex); 555 548 556 - if (node) 557 - pdata = of_gpio_twl4030(&pdev->dev, pdata); 558 - 549 + pdata = of_gpio_twl4030(&pdev->dev); 559 550 if (pdata == NULL) { 560 551 dev_err(&pdev->dev, "Platform data is missing\n"); 561 552 return -ENXIO; ··· 590 585 goto out; 591 586 } 592 587 593 - platform_set_drvdata(pdev, priv); 588 + /* 589 + * Special quirk for the OMAP3 to hog and export a WLAN power 590 + * GPIO. 591 + */ 592 + if (IS_ENABLED(CONFIG_ARCH_OMAP3) && 593 + of_machine_is_compatible("compulab,omap3-sbc-t3730")) { 594 + struct gpio_desc *d; 594 595 595 - if (pdata->setup) { 596 - int status; 596 + d = gpiochip_request_own_desc(&priv->gpio_chip, 597 + 2, "wlan pwr", 598 + GPIO_ACTIVE_HIGH, 599 + GPIOD_OUT_HIGH); 600 + if (IS_ERR(d)) 601 + return dev_err_probe(&pdev->dev, PTR_ERR(d), 602 + "unable to hog wlan pwr GPIO\n"); 597 603 598 - status = pdata->setup(&pdev->dev, priv->gpio_chip.base, 599 - TWL4030_GPIO_MAX); 600 - if (status) 601 - dev_dbg(&pdev->dev, "setup --> %d\n", status); 604 + gpiod_export(d, 0); 605 + 606 + ret = devm_add_action_or_reset(&pdev->dev, gpio_twl4030_power_off_action, d); 607 + if (ret) 608 + return dev_err_probe(&pdev->dev, ret, 609 + "failed to install power off handler\n"); 610 + 602 611 } 603 612 613 + platform_set_drvdata(pdev, priv); 604 614 out: 605 615 return ret; 606 616 }
-3
include/linux/mfd/twl.h
··· 593 593 */ 594 594 u32 pullups; 595 595 u32 pulldowns; 596 - 597 - int (*setup)(struct device *dev, 598 - unsigned gpio, unsigned ngpio); 599 596 }; 600 597 601 598 struct twl4030_madc_platform_data {