From patchwork Wed Dec 18 02:42:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanjie Lin X-Patchwork-Id: 11299371 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 39DA013B6 for ; Wed, 18 Dec 2019 02:42:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2230A218AC for ; Wed, 18 Dec 2019 02:42:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726652AbfLRCm6 (ORCPT ); Tue, 17 Dec 2019 21:42:58 -0500 Received: from mail-sh.amlogic.com ([58.32.228.43]:34131 "EHLO mail-sh.amlogic.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726387AbfLRCm5 (ORCPT ); Tue, 17 Dec 2019 21:42:57 -0500 Received: from droid10.amlogic.com (10.18.11.213) by mail-sh.amlogic.com (10.18.11.5) with Microsoft SMTP Server id 15.1.1591.10; Wed, 18 Dec 2019 10:43:24 +0800 From: Hanjie Lin To: Jerome Brunet , Neil Armstrong , Rob Herring , Greg Kroah-Hartman , Felipe Balbi , Kevin Hilman CC: Hanjie Lin , Yue Wang , , , , , Carlo Caione , Michael Turquette , Stephen Boyd , Martin Blumenstingl , Liang Yang , Jianxin Pan , Qiufang Dai , Jian Hu , Victor Wan , Xingyu Chen Subject: [PATCH v2 4/6] usb: dwc3: Add Amlogic A1 DWC3 glue Date: Wed, 18 Dec 2019 10:42:22 +0800 Message-ID: <1576636944-196192-5-git-send-email-hanjie.lin@amlogic.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1576636944-196192-1-git-send-email-hanjie.lin@amlogic.com> References: <1576636944-196192-1-git-send-email-hanjie.lin@amlogic.com> MIME-Version: 1.0 X-Originating-IP: [10.18.11.213] Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Adds support for Amlogic A1 USB Control Glue HW. The Amlogic A1 SoC Family embeds 1 USB Controllers: - a DWC3 IP configured as Host for USB2 and USB3 A glue connects the controllers to the USB2 PHY of A1 SoC. Signed-off-by: Hanjie Lin Signed-off-by: Yue Wang --- drivers/usb/dwc3/dwc3-meson-g12a.c | 69 +++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 8a3ec1a..3817daf 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -107,10 +107,22 @@ static const char *phy_names[PHY_COUNT] = { "usb2-phy0", "usb2-phy1", "usb3-phy0", }; +static const struct clk_bulk_data meson_g12a_clocks[] = { + { .id = NULL}, +}; + +static const struct clk_bulk_data meson_a1_clocks[] = { + { .id = "usb_ctrl"}, + { .id = "usb_bus"}, + { .id = "xtal_usb_phy"}, + { .id = "xtal_usb_ctrl"}, +}; + struct dwc3_meson_g12a { struct device *dev; struct regmap *regmap; - struct clk *clk; + struct clk_bulk_data *clks; + int num_clks; struct reset_control *reset; struct phy *phys[PHY_COUNT]; enum usb_dr_mode otg_mode; @@ -151,7 +163,7 @@ static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv) U2P_R0_POWER_ON_RESET, U2P_R0_POWER_ON_RESET); - if (i == USB2_OTG_PHY) { + if (i == USB2_OTG_PHY && priv->otg_mode != USB_DR_MODE_HOST) { regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS, @@ -295,7 +307,7 @@ static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv, { int ret; - if (!priv->phys[USB2_OTG_PHY]) + if (!priv->phys[USB2_OTG_PHY] || priv->otg_mode == USB_DR_MODE_HOST) return -EINVAL; if (mode == PHY_MODE_USB_HOST) @@ -409,17 +421,32 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) priv->vbus = NULL; } - priv->clk = devm_clk_get(dev, NULL); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); + priv->dev = dev; + + if (of_device_is_compatible(np, "amlogic,meson-g12a-usb-ctrl")) { + priv->clks = devm_kmemdup(dev, meson_g12a_clocks, + sizeof(meson_g12a_clocks), + GFP_KERNEL); + priv->num_clks = ARRAY_SIZE(meson_g12a_clocks); + } else if (of_device_is_compatible(np, "amlogic,meson-a1-usb-ctrl")) { + priv->clks = devm_kmemdup(dev, meson_a1_clocks, + sizeof(meson_a1_clocks), + GFP_KERNEL); + priv->num_clks = ARRAY_SIZE(meson_a1_clocks); + } else { + return -EINVAL; + } + + if (!priv->clks) + return -ENOMEM; - ret = clk_prepare_enable(priv->clk); + ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks); if (ret) return ret; - devm_add_action_or_reset(dev, - (void(*)(void *))clk_disable_unprepare, - priv->clk); + ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks); + if (ret) + return ret; platform_set_drvdata(pdev, priv); priv->dev = dev; @@ -433,16 +460,16 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) ret = reset_control_reset(priv->reset); if (ret) - return ret; + goto err_disable_clks; ret = dwc3_meson_g12a_get_phys(priv); if (ret) - return ret; + goto err_disable_clks; if (priv->vbus) { ret = regulator_enable(priv->vbus); if (ret) - return ret; + goto err_disable_clks; } /* Get dr_mode */ @@ -458,7 +485,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) dwc3_meson_g12a_irq_thread, IRQF_ONESHOT, pdev->name, priv); if (ret) - return ret; + goto err_disable_clks; } dwc3_meson_g12a_usb_init(priv); @@ -467,7 +494,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) for (i = 0 ; i < PHY_COUNT ; ++i) { ret = phy_init(priv->phys[i]); if (ret) - return ret; + goto err_disable_clks; } /* Set PHY Power */ @@ -478,10 +505,8 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) } ret = of_platform_populate(np, NULL, NULL, dev); - if (ret) { - clk_disable_unprepare(priv->clk); + if (ret) goto err_phys_power; - } /* Setup OTG mode corresponding to the ID pin */ if (priv->otg_mode == USB_DR_MODE_OTG) { @@ -518,6 +543,9 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) for (i = 0 ; i < PHY_COUNT ; ++i) phy_exit(priv->phys[i]); +err_disable_clks: + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); + return ret; } @@ -547,7 +575,7 @@ static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev) { struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); - clk_disable(priv->clk); + clk_bulk_disable_unprepare(priv->num_clks, priv->clks); return 0; } @@ -556,7 +584,7 @@ static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev) { struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); - return clk_enable(priv->clk); + return clk_bulk_prepare_enable(priv->num_clks, priv->clks); } static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) @@ -620,6 +648,7 @@ static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = { static const struct of_device_id dwc3_meson_g12a_match[] = { { .compatible = "amlogic,meson-g12a-usb-ctrl" }, + { .compatible = "amlogic,meson-a1-usb-ctrl" }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match);