From patchwork Fri Jul 8 20:09:05 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Jarzmik X-Patchwork-Id: 9221765 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 55890607D9 for ; Fri, 8 Jul 2016 20:11:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 43BFA28494 for ; Fri, 8 Jul 2016 20:11:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 38D2328496; Fri, 8 Jul 2016 20:11:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E416628494 for ; Fri, 8 Jul 2016 20:11:17 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bLc6F-0005JD-07; Fri, 08 Jul 2016 20:10:11 +0000 Received: from smtp04.smtpout.orange.fr ([80.12.242.126] helo=smtp.smtpout.orange.fr) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bLc5r-0004Q6-JM for linux-arm-kernel@lists.infradead.org; Fri, 08 Jul 2016 20:09:49 +0000 Received: from belgarion.home ([109.214.23.92]) by mwinf5d60 with ME id GL9M1t0081zD51Z03L9MNU; Fri, 08 Jul 2016 22:09:25 +0200 X-ME-Helo: belgarion.home X-ME-Date: Fri, 08 Jul 2016 22:09:25 +0200 X-ME-IP: 109.214.23.92 From: Robert Jarzmik To: Daniel Mack , Haojian Zhuang , Robert Jarzmik , Felipe Balbi , Greg Kroah-Hartman Subject: [PATCH 1/3] usb: gadget: pxa27x: add phy notifier event handler Date: Fri, 8 Jul 2016 22:09:05 +0200 Message-Id: <1468008547-10925-1-git-send-email-robert.jarzmik@free.fr> X-Mailer: git-send-email 2.1.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160708_130948_107596_83B0985B X-CRM114-Status: GOOD ( 16.37 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP In the legacy behavior, and USB phy, upon detection a VBus signal, was calling usb_gadget_vbus_(dis)connect(). This model doesn't work if the phy is generic and doesn't have an adherence to the gadget API. Instead of relying on the phy to call the gadget API, hook up the phy notifier to report the VBus event, and upon it call the usb gadget API ourselves. This brings a new ordering problem, as before even if the usb_get_phy() was failing because the UDC was probed before the phy, the phy would call the gadget anyway, making the VBus connection event forwarded to the gadget. Now we rely on the notifier, we have to ensure the xxx_get_phy() does indeed work. In order to cope with this, it is assumed that : - for legacy platform_data machine, as the ordering cannot be ensured, the phy must call usb_gadget_vbus_(dis)connect, such as phy-gpio-vbus-usb.c - for new devicetree platforms, we'll rely on the probe deferral, and the phy can be gadget API agnostic. Signed-off-by: Robert Jarzmik --- drivers/usb/gadget/udc/pxa27x_udc.c | 51 +++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 001a3b74a993..79643e25a5bb 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "pxa27x_udc.h" @@ -1655,6 +1656,37 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) return -EOPNOTSUPP; } +/** + * pxa_udc_phy_event - Called by phy upon VBus event + * @nb: notifier block + * @action: phy action, is vbus connect or disconnect + * @data: the usb_gadget structure in pxa_udc + * + * Called by the USB Phy when a cable connect or disconnect is sensed. + * + * Returns 0 + */ +static int pxa_udc_phy_event(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct usb_gadget *gadget = data; + + switch (action) { + case USB_EVENT_VBUS: + usb_gadget_vbus_connect(gadget); + return NOTIFY_OK; + case USB_EVENT_NONE: + usb_gadget_vbus_disconnect(gadget); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } +} + +static struct notifier_block pxa27x_udc_phy = { + .notifier_call = pxa_udc_phy_event, +}; + static int pxa27x_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); static int pxa27x_udc_stop(struct usb_gadget *g); @@ -2435,7 +2467,14 @@ static int pxa_udc_probe(struct platform_device *pdev) return udc->irq; udc->dev = &pdev->dev; - udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); + if (of_have_populated_dt()) { + udc->transceiver = + devm_usb_get_phy_by_phandle(udc->dev, "phys", 0); + if (IS_ERR(udc->transceiver)) + return PTR_ERR(udc->transceiver); + } else { + udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); + } if (IS_ERR(udc->gpiod)) { dev_err(&pdev->dev, "Couldn't find or request D+ gpio : %ld\n", @@ -2468,14 +2507,20 @@ static int pxa_udc_probe(struct platform_device *pdev) goto err; } + if (!IS_ERR_OR_NULL(udc->transceiver)) + usb_register_notifier(udc->transceiver, &pxa27x_udc_phy); retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (retval) - goto err; + goto err_add_gadget; pxa_init_debugfs(udc); if (should_enable_udc(udc)) udc_enable(udc); return 0; + +err_add_gadget: + if (!IS_ERR_OR_NULL(udc->transceiver)) + usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy); err: clk_unprepare(udc->clk); return retval; @@ -2492,6 +2537,8 @@ static int pxa_udc_remove(struct platform_device *_dev) usb_del_gadget_udc(&udc->gadget); pxa_cleanup_debugfs(udc); + if (!IS_ERR_OR_NULL(udc->transceiver)) + usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy); usb_put_phy(udc->transceiver); udc->transceiver = NULL;