From patchwork Tue Oct 25 04:11:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Icenowy Zheng X-Patchwork-Id: 9393945 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 7F5BA6077A for ; Tue, 25 Oct 2016 04:14:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6D91728F02 for ; Tue, 25 Oct 2016 04:14:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 600D628F51; Tue, 25 Oct 2016 04:14:29 +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.1 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=ham 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 C7CA828F02 for ; Tue, 25 Oct 2016 04:14:28 +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 1byt6w-0006n7-OG; Tue, 25 Oct 2016 04:13:14 +0000 Received: from forward13j.cmail.yandex.net ([2a02:6b8:0:1630::b3]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1byt6p-0006ek-UU for linux-arm-kernel@lists.infradead.org; Tue, 25 Oct 2016 04:13:10 +0000 Received: from smtp1p.mail.yandex.net (smtp1p.mail.yandex.net [IPv6:2a02:6b8:0:1472:2741:0:8b6:6]) by forward13j.cmail.yandex.net (Yandex) with ESMTP id D90D521703; Tue, 25 Oct 2016 07:12:44 +0300 (MSK) Received: from smtp1p.mail.yandex.net (localhost.localdomain [127.0.0.1]) by smtp1p.mail.yandex.net (Yandex) with ESMTP id BD83617804D6; Tue, 25 Oct 2016 07:12:36 +0300 (MSK) Received: by smtp1p.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id GI0C6IUsTh-CSvSjiHx; Tue, 25 Oct 2016 07:12:31 +0300 (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client certificate not present) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=aosc.xyz; s=mail; t=1477368755; bh=kmhaUtSL6Z1mX5YhEnOCD1CesUuzbvw76OFQf+QgC5A=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=J8mEyajClJWzRiQjy5ufY4vd5oh/LZMkHdsF4c7pILHvkDkCZHF2NrR7Kya+BltkK J98LHTH/3Q3xf35wPsp7cs3ZEXJ8qCEziTq39yhz3cxmRW/YCXmF6VOXnVIgSM4POW 57pcz3MugAJ1IP6DXpmvzmffiXXkJROOW7Kzbo/c= Authentication-Results: smtp1p.mail.yandex.net; dkim=pass header.i=@aosc.xyz X-Yandex-ForeignMX: FR X-Yandex-Suid-Status: 1 0, 1 0, 1 0, 1 0, 1 0, 1 0, 1 0, 1 0, 1 0, 1 0, 1 0, 1 1130000036118848 From: Icenowy Zheng To: Rob Herring , Maxime Ripard , Chen-Yu Tsai , Kishon Vijay Abraham I , Hans de Goede Subject: [PATCH RESEND 2/2] phy-sun4i-usb: add support for host mode of phy0 on A64 SoC Date: Tue, 25 Oct 2016 12:11:39 +0800 Message-Id: <20161025041139.46454-2-icenowy@aosc.xyz> X-Mailer: git-send-email 2.10.1 In-Reply-To: <20161025041139.46454-1-icenowy@aosc.xyz> References: <20161025041139.46454-1-icenowy@aosc.xyz> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161024_211308_482108_EA79C81D X-CRM114-Status: GOOD ( 18.15 ) 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: Mark Rutland , devicetree@vger.kernel.org, Reinder de Haan , linux-kernel@vger.kernel.org, linux-sunxi@googlegroups.com, Icenowy Zheng , 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 The OTG phy of A64 can be put into the host mode with an OHCI/EHCI pair, just like the H3 SoC. Some A64 boards (such as Pine64 series) use the USB OTG port as a generic USB-A port, and thus can be fully support by the driver now. The register's name is changed to PHY_OTG_CFG, as it's described in the A64 downstream BSP kernel source, at drivers/usb/host/sunxi_hci.h . Signed-off-by: Icenowy Zheng --- drivers/phy/phy-sun4i-usb.c | 46 +++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index a4db658..9287247 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -47,7 +47,7 @@ #define REG_PHYBIST 0x08 #define REG_PHYTUNE 0x0c #define REG_PHYCTL_A33 0x10 -#define REG_PHY_UNK_H3 0x20 +#define REG_PHY_OTG_CFG 0x20 #define REG_PMU_UNK1 0x10 @@ -107,6 +107,7 @@ struct sun4i_usb_phy_cfg { u8 phyctl_offset; bool dedicated_clocks; bool enable_pmu_unk1; + bool route_otg; }; struct sun4i_usb_phy_data { @@ -135,6 +136,7 @@ struct sun4i_usb_phy_data { int id_det; int vbus_det; struct delayed_work detect; + bool otg_routed; }; #define to_sun4i_usb_phy_data(phy) \ @@ -263,10 +265,11 @@ static int sun4i_usb_phy_init(struct phy *_phy) writel(val & ~2, phy->pmu + REG_PMU_UNK1); } - if (data->cfg->type == sun8i_h3_phy) { - if (phy->index == 0) { - val = readl(data->base + REG_PHY_UNK_H3); - writel(val & ~1, data->base + REG_PHY_UNK_H3); + if (data->cfg->route_otg) { + if (phy->index == 0 && data->otg_routed) { + /* Route the OTG PHY to HCI */ + val = readl(data->base + REG_PHY_OTG_CFG); + writel(val & ~1, data->base + REG_PHY_OTG_CFG); } } else { /* Enable USB 45 Ohm resistor calibration */ @@ -283,7 +286,7 @@ static int sun4i_usb_phy_init(struct phy *_phy) sun4i_usb_phy_passby(phy, 1); - if (phy->index == 0) { + if (phy->index == 0 && !data->otg_routed) { data->phy0_init = true; /* Enable pull-ups */ @@ -310,7 +313,7 @@ static int sun4i_usb_phy_exit(struct phy *_phy) struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); - if (phy->index == 0) { + if (phy->index == 0 && !data->otg_routed) { /* Disable pull-ups */ sun4i_usb_phy0_update_iscr(_phy, ISCR_DPDM_PULLUP_EN, 0); sun4i_usb_phy0_update_iscr(_phy, ISCR_ID_PULLUP_EN, 0); @@ -377,7 +380,7 @@ static int sun4i_usb_phy_power_on(struct phy *_phy) /* For phy0 only turn on Vbus if we don't have an ext. Vbus */ if (phy->index == 0 && sun4i_usb_phy0_have_vbus_det(data) && - data->vbus_det) + data->vbus_det && !data->otg_routed) return 0; ret = regulator_enable(phy->vbus); @@ -387,7 +390,7 @@ static int sun4i_usb_phy_power_on(struct phy *_phy) phy->regulator_on = true; /* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */ - if (phy->index == 0 && sun4i_usb_phy0_poll(data)) + if (phy->index == 0 && sun4i_usb_phy0_poll(data) && !data->otg_routed) mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); return 0; @@ -408,7 +411,7 @@ static int sun4i_usb_phy_power_off(struct phy *_phy) * phy0 vbus typically slowly discharges, sometimes this causes the * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan. */ - if (phy->index == 0 && !sun4i_usb_phy0_poll(data)) + if (phy->index == 0 && !sun4i_usb_phy0_poll(data) && !data->otg_routed) mod_delayed_work(system_wq, &data->detect, POLL_TIME); return 0; @@ -567,7 +570,17 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return -ENOMEM; mutex_init(&data->mutex); - INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); + if (device_property_read_bool(dev, "allwinner,otg-routed")) { + /* + * PHY0 is routed to HCI rather than OTG Controller. + * In this situation, the port can only be used as a host port. + */ + data->otg_routed = true; + } else { + /* ID/Vbus detection is only meaningful when it's really OTG */ + INIT_DELAYED_WORK(&data->detect, + sun4i_usb_phy0_id_vbus_det_scan); + } dev_set_drvdata(dev, data); data->cfg = of_device_get_match_data(dev); if (!data->cfg) @@ -647,7 +660,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(phy->reset); } - if (i) { /* No pmu for usbc0 */ + /* PMU is only valid on PHYs in HCI mode */ + if (i || data->otg_routed) { snprintf(name, sizeof(name), "pmu%d", i); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); @@ -719,6 +733,7 @@ static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = { .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, .enable_pmu_unk1 = false, + .route_otg = false, }; static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = { @@ -728,6 +743,7 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = { .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, .enable_pmu_unk1 = false, + .route_otg = false, }; static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { @@ -737,6 +753,7 @@ static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, .enable_pmu_unk1 = false, + .route_otg = false, }; static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = { @@ -746,6 +763,7 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = { .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, .enable_pmu_unk1 = false, + .route_otg = false, }; static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { @@ -755,6 +773,7 @@ static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, .enable_pmu_unk1 = false, + .route_otg = false, }; static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = { @@ -764,6 +783,7 @@ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = { .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, .enable_pmu_unk1 = false, + .route_otg = false, }; static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { @@ -772,6 +792,7 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { .disc_thresh = 3, .dedicated_clocks = true, .enable_pmu_unk1 = true, + .route_otg = true, }; static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { @@ -781,6 +802,7 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, .enable_pmu_unk1 = true, + .route_otg = true, }; static const struct of_device_id sun4i_usb_phy_of_match[] = {