[PATCH v4] usb: dwc3: use extcon fwrk to receive connect/disconnect
Kishon Vijay Abraham I
kishon at ti.com
Thu Jun 20 18:54:50 EST 2013
Hi,
On Monday 17 June 2013 09:39 AM, Chanwoo Choi wrote:
> On 06/14/2013 10:10 PM, Kishon Vijay Abraham I wrote:
>> Modified dwc3-omap to receive connect and disconnect notification using
>> extcon framework. Also did the necessary cleanups required after
>> adapting to extcon framework.
>>
>> Signed-off-by: Kishon Vijay Abraham I <kishon at ti.com>
>> Acked-by: Felipe Balbi <balbi at ti.com>
>> ---
>> This patch depends on
>> git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git commit:f7ae906
>>
>> It should also be applied on top of
>> usb: dwc3: omap: improve error handling of dwc3_omap_probe patch which is
>> merged in Felipe's tree.
>>
>> So I'm not sure on whose tree this patch should go in.
>>
>> Changes from v3:
>> * did #include of of_extcon.h after Chanwoo resent the patch separating
>> extcon-class.c from of_extcon.c
>> Changes from v2:
>> * updated the Documentation with dwc3 dt binding information.
>> * used of_extcon_get_extcon_dev to get extcon device from device tree data.
>> Changes from v1:
>> * regulator enable/disable is now done here instead of palmas-usb as some users
>> of palmas-usb wont need regulator.
>>
>> Documentation/devicetree/bindings/usb/omap-usb.txt | 5 +
>> drivers/usb/dwc3/dwc3-omap.c | 119 ++++++++++++++++----
>> include/linux/usb/dwc3-omap.h | 30 -----
>> 3 files changed, 105 insertions(+), 49 deletions(-)
>> delete mode 100644 include/linux/usb/dwc3-omap.h
>>
>> diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
>> index d4769f3..f1c15f3 100644
>> --- a/Documentation/devicetree/bindings/usb/omap-usb.txt
>> +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
>> @@ -53,6 +53,11 @@ OMAP DWC3 GLUE
>> It should be set to "1" for HW mode and "2" for SW mode.
>> - ranges: the child address space are mapped 1:1 onto the parent address space
>>
>> +Optional Properties:
>> + - extcon : phandle for the extcon device omap dwc3 uses to detect
>> + connect/disconnect events.
>> + - vbus-supply : phandle to the regulator device tree node if needed.
>> +
>> Sub-nodes:
>> The dwc3 core should be added as subnode to omap dwc3 glue.
>> - dwc3 :
>> diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
>> index f8f76e6..14c1f1b 100644
>> --- a/drivers/usb/dwc3/dwc3-omap.c
>> +++ b/drivers/usb/dwc3/dwc3-omap.c
>> @@ -43,13 +43,15 @@
>> #include <linux/spinlock.h>
>> #include <linux/platform_device.h>
>> #include <linux/platform_data/dwc3-omap.h>
>> -#include <linux/usb/dwc3-omap.h>
>> #include <linux/pm_runtime.h>
>> #include <linux/dma-mapping.h>
>> #include <linux/ioport.h>
>> #include <linux/io.h>
>> #include <linux/of.h>
>> #include <linux/of_platform.h>
>> +#include <linux/extcon.h>
>> +#include <linux/extcon/of_extcon.h>
>> +#include <linux/regulator/consumer.h>
>>
>> #include <linux/usb/otg.h>
>>
>> @@ -124,9 +126,21 @@ struct dwc3_omap {
>> u32 utmi_otg_status;
>>
>> u32 dma_status:1;
>> +
>> + struct extcon_specific_cable_nb extcon_vbus_dev;
>> + struct extcon_specific_cable_nb extcon_id_dev;
>> + struct notifier_block vbus_nb;
>> + struct notifier_block id_nb;
>> +
>> + struct regulator *vbus_reg;
>> };
>>
>> -static struct dwc3_omap *_omap;
>> +enum omap_dwc3_vbus_id_status {
>> + OMAP_DWC3_ID_FLOAT,
>> + OMAP_DWC3_ID_GROUND,
>> + OMAP_DWC3_VBUS_OFF,
>> + OMAP_DWC3_VBUS_VALID,
>> +};
>>
>> static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
>> {
>> @@ -138,18 +152,23 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
>> writel(value, base + offset);
>> }
>>
>> -int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
>> +static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
>> + enum omap_dwc3_vbus_id_status status)
>> {
>> - u32 val;
>> - struct dwc3_omap *omap = _omap;
>> -
>> - if (!omap)
>> - return -EPROBE_DEFER;
>> + int ret;
>> + u32 val;
>>
>> switch (status) {
>> case OMAP_DWC3_ID_GROUND:
>> dev_dbg(omap->dev, "ID GND\n");
>>
>> + if (omap->vbus_reg) {
>> + ret = regulator_enable(omap->vbus_reg);
>> + if (ret) {
>> + dev_dbg(omap->dev, "regulator enable failed\n");
>> + return;
>> + }
>> + }
>> val = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
>> val &= ~(USBOTGSS_UTMI_OTG_STATUS_IDDIG
>> | USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
>> @@ -172,6 +191,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
>> break;
>>
>> case OMAP_DWC3_ID_FLOAT:
>> + if (omap->vbus_reg)
>> + regulator_disable(omap->vbus_reg);
>> +
>> case OMAP_DWC3_VBUS_OFF:
>> dev_dbg(omap->dev, "VBUS Disconnect\n");
>>
>> @@ -185,12 +207,9 @@ int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
>> break;
>>
>> default:
>> - dev_dbg(omap->dev, "ID float\n");
>> + dev_dbg(omap->dev, "invalid state\n");
>> }
>> -
>> - return 0;
>> }
>> -EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
>>
>> static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
>> {
>> @@ -282,6 +301,32 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
>>
>> static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
>>
>> +static int dwc3_omap_id_notifier(struct notifier_block *nb,
>> + unsigned long event, void *ptr)
>> +{
>> + struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, id_nb);
>> +
>> + if (event)
>> + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
>> + else
>> + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT);
>> +
>> + return NOTIFY_DONE;
>> +}
>> +
>> +static int dwc3_omap_vbus_notifier(struct notifier_block *nb,
>> + unsigned long event, void *ptr)
>> +{
>> + struct dwc3_omap *omap = container_of(nb, struct dwc3_omap, vbus_nb);
>> +
>> + if (event)
>> + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
>> + else
>> + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF);
>> +
>> + return NOTIFY_DONE;
>> +}
>> +
>> static int dwc3_omap_probe(struct platform_device *pdev)
>> {
>> struct device_node *node = pdev->dev.of_node;
>> @@ -289,6 +334,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)
>> struct dwc3_omap *omap;
>> struct resource *res;
>> struct device *dev = &pdev->dev;
>> + struct extcon_dev *edev;
>> + struct regulator *vbus_reg = NULL;
>>
>> int ret = -ENOMEM;
>> int irq;
>> @@ -330,19 +377,22 @@ static int dwc3_omap_probe(struct platform_device *pdev)
>> return -ENOMEM;
>> }
>>
>> + if (of_property_read_bool(node, "vbus-supply")) {
>> + vbus_reg = devm_regulator_get(dev, "vbus");
>> + if (IS_ERR(vbus_reg)) {
>> + dev_err(dev, "vbus init failed\n");
>> + return PTR_ERR(vbus_reg);
>> + }
>> + }
>> +
>> spin_lock_init(&omap->lock);
>>
>> omap->dev = dev;
>> omap->irq = irq;
>> omap->base = base;
>> + omap->vbus_reg = vbus_reg;
>> dev->dma_mask = &dwc3_omap_dma_mask;
>>
>> - /*
>> - * REVISIT if we ever have two instances of the wrapper, we will be
>> - * in big trouble
>> - */
>> - _omap = omap;
>> -
>> pm_runtime_enable(dev);
>> ret = pm_runtime_get_sync(dev);
>> if (ret < 0) {
>> @@ -381,14 +431,41 @@ static int dwc3_omap_probe(struct platform_device *pdev)
>>
>> dwc3_omap_enable_irqs(omap);
>>
>> + if (of_property_read_bool(node, "extcon")) {
>> + edev = of_extcon_get_extcon_dev(dev, 0);
>> + if (IS_ERR(edev)) {
>> + dev_vdbg(dev, "couldn't get extcon device\n");
>> + ret = PTR_ERR(edev);
>> + goto err2;
>> + }
>> +
>> + omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
>> + extcon_register_interest(&omap->extcon_vbus_dev, edev->name,
>> + "USB", &omap->vbus_nb);
>> + omap->id_nb.notifier_call = dwc3_omap_id_notifier;
>> + extcon_register_interest(&omap->extcon_id_dev, edev->name,
>> + "USB-HOST", &omap->id_nb);
>
> I prefer adding exception handling code about return value of extcon_register_interest().
>
>> +
>> + if (extcon_get_cable_state(edev, "USB") == true)
>> + dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
>> + if (extcon_get_cable_state(edev, "USB-HOST") == true)
>> + dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
>> + }
>> +
>> ret = of_platform_populate(node, NULL, NULL, dev);
>> if (ret) {
>> dev_err(&pdev->dev, "failed to create dwc3 core\n");
>> - goto err2;
>> + goto err3;
>> }
>>
>> return 0;
>>
>> +err3:
>> + if (omap->extcon_vbus_dev.edev)
>> + extcon_unregister_interest(&omap->extcon_vbus_dev);
>> + if (omap->extcon_id_dev.edev)
>> + extcon_unregister_interest(&omap->extcon_id_dev);
>> +
>> err2:
>> dwc3_omap_disable_irqs(omap);
>>
>> @@ -405,6 +482,10 @@ static int dwc3_omap_remove(struct platform_device *pdev)
>> {
>> struct dwc3_omap *omap = platform_get_drvdata(pdev);
>>
>> + if (omap->extcon_vbus_dev.edev)
>> + extcon_unregister_interest(&omap->extcon_vbus_dev);
>> + if (omap->extcon_id_dev.edev)
>> + extcon_unregister_interest(&omap->extcon_id_dev);
>> dwc3_omap_disable_irqs(omap);
>> pm_runtime_put_sync(&pdev->dev);
>> pm_runtime_disable(&pdev->dev);
>> diff --git a/include/linux/usb/dwc3-omap.h b/include/linux/usb/dwc3-omap.h
>> deleted file mode 100644
>> index 5615f4d..0000000
>>
>
> It looks good if you add exception handler about return value of extcon_register_interest().
Ok. I'll fix exception handler and also add depend on of EXTCON here.
Thanks
Kishon
More information about the devicetree-discuss
mailing list