From patchwork Tue Dec 6 08:06:20 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 86704 Delivered-To: patches@linaro.org Received: by 10.140.20.101 with SMTP id 92csp1894882qgi; Tue, 6 Dec 2016 00:06:29 -0800 (PST) X-Received: by 10.84.218.6 with SMTP id q6mr133744140pli.139.1481011589811; Tue, 06 Dec 2016 00:06:29 -0800 (PST) Return-Path: Received: from mail-pf0-x235.google.com (mail-pf0-x235.google.com. [2607:f8b0:400e:c00::235]) by mx.google.com with ESMTPS id d4si18508886pfb.185.2016.12.06.00.06.29 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 06 Dec 2016 00:06:29 -0800 (PST) Received-SPF: pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c00::235 as permitted sender) client-ip=2607:f8b0:400e:c00::235; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c00::235 as permitted sender) smtp.mailfrom=john.stultz@linaro.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: by mail-pf0-x235.google.com with SMTP id 189so69277408pfz.3 for ; Tue, 06 Dec 2016 00:06:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=JOIRGyqGAodzVCIHfaHun7PsaPMRJp9gpGjIShof5ik=; b=OwEqasfBHS9ZncA3UoFJXDM66/DxnJWQk3WnfHMU47AWhZX+wpPrQEded4Vi/dikgd DMi7zzOC45adt6YlgFkzMoHMEmujvOAiRZef6W1CIdVxHPdaAIVMAoDuDhAsmUO8KNPD 0yHWBmCYsSDiAezmbgrn3s+vpZxheM+A0koYw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=JOIRGyqGAodzVCIHfaHun7PsaPMRJp9gpGjIShof5ik=; b=LgvV8SK9DVedfvYwDmV5t0e6krKWH2ZUVQoM5qNlCtuoDPx3XPSR9nuPlG/6Pnj2TD 1nXTnovj+qNOJAsyzYV67oY+qXkfRTtBGCE3e6MU9Ry+pQ2BDkWZQOin021wf4SFAF1h 2wJlMfHWaxj04m7P32f3cu8xtt9S29mYcd9Fu5uQAHPPnS/PKeYTPOyvHqdc1EbenPVe 0gIKonKOnVB+MATh4ygAA13A9CDsqjY7T5tFiq7FNcSJ+Ru1mu0xkjfwhV+lKfJ8qito fhMDB4/aiUDPw2NgxLQdMUakHNXKfocg+GVqDnuPFfMkxLHzLAefCGMDctk9GK5AzWVP xsjQ== X-Gm-Message-State: AKaTC02yvCPVVCFz4xNFWroGP4VgrrFhLcAK96JirL/O8+UX8Sq1hTkL06Xt9QXj6GIILqV3Puo= X-Received: by 10.84.209.136 with SMTP id y8mr135532518plh.114.1481011589456; Tue, 06 Dec 2016 00:06:29 -0800 (PST) Return-Path: Received: from localhost.localdomain ([2601:1c2:1002:83f0:4e72:b9ff:fe99:466a]) by smtp.gmail.com with ESMTPSA id q145sm32546834pfq.22.2016.12.06.00.06.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 06 Dec 2016 00:06:28 -0800 (PST) From: John Stultz To: lkml Cc: John Stultz , Wei Xu , Guodong Xu , Amit Pundir , Rob Herring , John Youn , Douglas Anderson , Chen Yu , Kishon Vijay Abraham I , Felipe Balbi , Greg Kroah-Hartman , linux-usb@vger.kernel.org Subject: [RFC][PATCH 1/3 v2] usb: dwc2: Add extcon support to dwc2 driver Date: Tue, 6 Dec 2016 00:06:20 -0800 Message-Id: <1481011582-7162-2-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1481011582-7162-1-git-send-email-john.stultz@linaro.org> References: <1481011582-7162-1-git-send-email-john.stultz@linaro.org> This patch wires up extcon support to the dwc2 driver so that devices that use a modern generic phy driver and don't use the usb-phy infrastructure can still signal connect/disconnect events. Cc: Wei Xu Cc: Guodong Xu Cc: Amit Pundir Cc: Rob Herring Cc: John Youn Cc: Douglas Anderson Cc: Chen Yu Cc: Kishon Vijay Abraham I Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Signed-off-by: John Stultz --- v2: * Move extcon logic from generic phy to dwc2 driver, as suggested by Kishon. --- arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 11 +++++++++ drivers/usb/dwc2/core.h | 16 ++++++++++++ drivers/usb/dwc2/core_intr.c | 25 +++++++++++++++++++ drivers/usb/dwc2/hcd.c | 23 +++++++++++++++++ drivers/usb/dwc2/platform.c | 41 +++++++++++++++++++++++++++++++ 5 files changed, 116 insertions(+) -- 2.7.4 diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi index 17839db..8a86a11 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi @@ -732,6 +732,16 @@ regulator-always-on; }; + usb_vbus: usb-vbus { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&gpio2 6 1>; + }; + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&gpio2 5 1>; + }; + usb_phy: usbphy { compatible = "hisilicon,hi6220-usb-phy"; #phy-cells = <0>; @@ -745,6 +755,7 @@ phys = <&usb_phy>; phy-names = "usb2-phy"; clocks = <&sys_ctrl HI6220_USBOTG_HCLK>; + extcon = <&usb_vbus>, <&usb_id>; clock-names = "otg"; dr_mode = "otg"; g-use-dma; diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 2a21a04..4cfce62 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -623,6 +623,13 @@ struct dwc2_hregs_backup { bool valid; }; +struct dwc2_extcon { + struct notifier_block nb; + struct extcon_dev *extcon; + int state; +}; + + /* * Constants related to high speed periodic scheduling * @@ -996,6 +1003,10 @@ struct dwc2_hsotg { u32 g_np_g_tx_fifo_sz; u32 g_tx_fifo_sz[MAX_EPS_CHANNELS]; #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ + + struct dwc2_extcon extcon_vbus; + struct dwc2_extcon extcon_id; + struct delayed_work extcon_work; }; /* Reasons for halting a host channel */ @@ -1041,6 +1052,11 @@ extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg); extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd); extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); +extern int dwc2_extcon_vbus_notifier(struct notifier_block *nb, + unsigned long event, void *ptr); +extern int dwc2_extcon_id_notifier(struct notifier_block *nb, + unsigned long event, void *ptr); + /* This function should be called on every hardware interrupt. */ extern irqreturn_t dwc2_handle_common_intr(int irq, void *dev); diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index d85c5c9..d4fa938 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -479,6 +479,31 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) } } + + +int dwc2_extcon_vbus_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct dwc2_extcon *vbus = container_of(nb, struct dwc2_extcon, nb); + struct dwc2_hsotg *hsotg = container_of(vbus, struct dwc2_hsotg, + extcon_vbus); + + schedule_delayed_work(&hsotg->extcon_work, msecs_to_jiffies(100)); + return NOTIFY_DONE; +} + +int dwc2_extcon_id_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct dwc2_extcon *id = container_of(nb, struct dwc2_extcon, nb); + struct dwc2_hsotg *hsotg = container_of(id, struct dwc2_hsotg, + extcon_id); + schedule_delayed_work(&hsotg->extcon_work, msecs_to_jiffies(100)); + + return NOTIFY_DONE; +} + + #define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \ GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT | \ GINTSTS_MODEMIS | GINTSTS_DISCONNINT | \ diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index df5a065..61eea70 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -3246,6 +3247,26 @@ static void dwc2_conn_id_status_change(struct work_struct *work) } } +static void dwc2_hcd_extcon_func(struct work_struct *work) +{ + struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg, + extcon_work.work); + + if (!IS_ERR(hsotg->extcon_vbus.extcon)) + hsotg->extcon_vbus.state = + extcon_get_cable_state_(hsotg->extcon_vbus.extcon, + EXTCON_USB); + if (!IS_ERR(hsotg->extcon_id.extcon)) + hsotg->extcon_id.state = + extcon_get_cable_state_(hsotg->extcon_id.extcon, + EXTCON_USB_HOST); + + if (hsotg->extcon_id.state) + usb_gadget_vbus_connect(&hsotg->gadget); + else + usb_gadget_vbus_disconnect(&hsotg->gadget); +} + static void dwc2_wakeup_detected(unsigned long data) { struct dwc2_hsotg *hsotg = (struct dwc2_hsotg *)data; @@ -5085,6 +5106,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) /* Initialize port reset work */ INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func); + INIT_DELAYED_WORK(&hsotg->extcon_work, dwc2_hcd_extcon_func); + /* * Allocate space for storing data on status transactions. Normally no * data is sent, but this space acts as a bit bucket. This must be diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 8e1728b..2e4545f 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -543,6 +544,7 @@ static int dwc2_driver_probe(struct platform_device *dev) struct dwc2_core_params defparams; struct dwc2_hsotg *hsotg; struct resource *res; + struct extcon_dev *ext_id, *ext_vbus; int retval; match = of_match_device(dwc2_of_match_table, &dev->dev); @@ -620,6 +622,45 @@ static int dwc2_driver_probe(struct platform_device *dev) if (retval) goto error; + ext_id = ERR_PTR(-ENODEV); + ext_vbus = ERR_PTR(-ENODEV); + if (of_property_read_bool(dev->dev.of_node, "extcon")) { + /* Each one of them is not mandatory */ + ext_vbus = extcon_get_edev_by_phandle(&dev->dev, 0); + if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV) + return PTR_ERR(ext_vbus); + + ext_id = extcon_get_edev_by_phandle(&dev->dev, 1); + if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV) + return PTR_ERR(ext_id); + } + + hsotg->extcon_vbus.extcon = ext_vbus; + if (!IS_ERR(ext_vbus)) { + hsotg->extcon_vbus.nb.notifier_call = dwc2_extcon_vbus_notifier; + retval = extcon_register_notifier(ext_vbus, EXTCON_USB, + &hsotg->extcon_vbus.nb); + if (retval < 0) { + dev_err(&dev->dev, "register VBUS notifier failed\n"); + return retval; + } + hsotg->extcon_vbus.state = extcon_get_cable_state_(ext_vbus, + EXTCON_USB); + } + + hsotg->extcon_id.extcon = ext_id; + if (!IS_ERR(ext_id)) { + hsotg->extcon_id.nb.notifier_call = dwc2_extcon_id_notifier; + retval = extcon_register_notifier(ext_id, EXTCON_USB_HOST, + &hsotg->extcon_id.nb); + if (retval < 0) { + dev_err(&dev->dev, "register ID notifier failed\n"); + return retval; + } + hsotg->extcon_id.state = extcon_get_cable_state_(ext_id, + EXTCON_USB_HOST); + } + /* * Reset before dwc2_get_hwparams() then it could get power-on real * reset value form registers.