From 3950c95e2c39b998abcc9702005b5ba7c7f70d32 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Mon, 3 Jul 2017 18:37:10 +0200 Subject: [PATCH 1/2] power: supply: twl4030-charger: move irq allocation to just before irqs are enabled And initialize workers and notifiers as soon as possible. This avoids a potential race if irqs are enabled and triggered too early before the worker is properly set up. Suggested-by: Grygorii Strashko Signed-off-by: H. Nikolaus Schaller Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_charger.c | 29 +++++++++++++------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index 3de802f169a1..9fad387e5081 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -980,12 +980,27 @@ static int twl4030_bci_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bci); + INIT_WORK(&bci->work, twl4030_bci_usb_work); + INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker); + bci->channel_vac = devm_iio_channel_get(&pdev->dev, "vac"); if (IS_ERR(bci->channel_vac)) { bci->channel_vac = NULL; dev_warn(&pdev->dev, "could not request vac iio channel"); } + if (bci->dev->of_node) { + struct device_node *phynode; + + phynode = of_find_compatible_node(bci->dev->of_node->parent, + NULL, "ti,twl4030-usb"); + if (phynode) { + bci->usb_nb.notifier_call = twl4030_bci_usb_ncb; + bci->transceiver = devm_usb_get_phy_by_node( + bci->dev, phynode, &bci->usb_nb); + } + } + bci->ac = devm_power_supply_register(&pdev->dev, &twl4030_bci_ac_desc, NULL); if (IS_ERR(bci->ac)) { @@ -1019,20 +1034,6 @@ static int twl4030_bci_probe(struct platform_device *pdev) return ret; } - INIT_WORK(&bci->work, twl4030_bci_usb_work); - INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker); - - bci->usb_nb.notifier_call = twl4030_bci_usb_ncb; - if (bci->dev->of_node) { - struct device_node *phynode; - - phynode = of_find_compatible_node(bci->dev->of_node->parent, - NULL, "ti,twl4030-usb"); - if (phynode) - bci->transceiver = devm_usb_get_phy_by_node( - bci->dev, phynode, &bci->usb_nb); - } - /* Enable interrupts now. */ reg = ~(u32)(TWL4030_ICHGLOW | TWL4030_ICHGEOC | TWL4030_TBATOR2 | TWL4030_TBATOR1 | TWL4030_BATSTS); From 7bb5a650f3471e4052e1692b29b0f3d3ca099c47 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Mon, 3 Jul 2017 18:37:11 +0200 Subject: [PATCH 2/2] power: supply: twl4030-charger: add deferred probing for phy and iio This fixes an issue if both this twl4030_charger driver and phy-twl4030-usb are compiled as modules and loaded in random order. It has been observed on GTA04 and OpenPandora devices that in worst case the boot process hangs and in best case the AC detection fails with a warning. Therefore we add deferred probing checks for the usb_phy and the iio channel for AC detection. Signed-off-by: H. Nikolaus Schaller Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_charger.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index 9fad387e5081..9dff1b4b85fc 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -985,8 +985,12 @@ static int twl4030_bci_probe(struct platform_device *pdev) bci->channel_vac = devm_iio_channel_get(&pdev->dev, "vac"); if (IS_ERR(bci->channel_vac)) { + ret = PTR_ERR(bci->channel_vac); + if (ret == -EPROBE_DEFER) + return ret; /* iio not ready */ + dev_warn(&pdev->dev, "could not request vac iio channel (%d)", + ret); bci->channel_vac = NULL; - dev_warn(&pdev->dev, "could not request vac iio channel"); } if (bci->dev->of_node) { @@ -998,6 +1002,14 @@ static int twl4030_bci_probe(struct platform_device *pdev) bci->usb_nb.notifier_call = twl4030_bci_usb_ncb; bci->transceiver = devm_usb_get_phy_by_node( bci->dev, phynode, &bci->usb_nb); + if (IS_ERR(bci->transceiver)) { + ret = PTR_ERR(bci->transceiver); + if (ret == -EPROBE_DEFER) + return ret; /* phy not ready */ + dev_warn(&pdev->dev, "could not request transceiver (%d)", + ret); + bci->transceiver = NULL; + } } }