From patchwork Fri Jan 17 00:21:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanjie Lin X-Patchwork-Id: 205599 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 61530C33CAF for ; Fri, 17 Jan 2020 00:22:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 362A82467A for ; Fri, 17 Jan 2020 00:22:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733124AbgAQAWL (ORCPT ); Thu, 16 Jan 2020 19:22:11 -0500 Received: from mail-sh.amlogic.com ([58.32.228.43]:52681 "EHLO mail-sh.amlogic.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733080AbgAQAWJ (ORCPT ); Thu, 16 Jan 2020 19:22:09 -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; Fri, 17 Jan 2020 08:22:31 +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 v6 1/6] dt-bindings: phy: Add Amlogic A1 USB2 PHY Bindings Date: Fri, 17 Jan 2020 08:21:39 +0800 Message-ID: <1579220504-110067-2-git-send-email-hanjie.lin@amlogic.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1579220504-110067-1-git-send-email-hanjie.lin@amlogic.com> References: <1579220504-110067-1-git-send-email-hanjie.lin@amlogic.com> MIME-Version: 1.0 X-Originating-IP: [10.18.11.213] Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Add the Amlogic A1 Family USB2 PHY Bindings It supports Host mode only. Signed-off-by: Yue Wang Signed-off-by: Hanjie Lin --- .../bindings/phy/amlogic,meson-g12a-usb2-phy.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml index 57d8603..3b7e763 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml @@ -14,6 +14,7 @@ properties: compatible: enum: - amlogic,meson-g12a-usb2-phy + - amlogic,meson-a1-usb2-phy reg: maxItems: 1 @@ -49,6 +50,20 @@ required: - reset-names - "#phy-cells" +allOf: + - if: + properties: + compatible: + enum: + - amlogic,meson-a1-usb-ctrl + + then: + properties: + power-domains: + maxItems: 1 + required: + - power-domains + examples: - | phy@36000 { From patchwork Fri Jan 17 00:21:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanjie Lin X-Patchwork-Id: 205598 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E4F17C33CAF for ; Fri, 17 Jan 2020 00:22:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B6A8E2073A for ; Fri, 17 Jan 2020 00:22:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729413AbgAQAWN (ORCPT ); Thu, 16 Jan 2020 19:22:13 -0500 Received: from mail-sh.amlogic.com ([58.32.228.43]:52681 "EHLO mail-sh.amlogic.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733100AbgAQAWN (ORCPT ); Thu, 16 Jan 2020 19:22:13 -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; Fri, 17 Jan 2020 08:22:32 +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 v6 3/6] phy: amlogic: Add Amlogic A1 USB2 PHY Driver Date: Fri, 17 Jan 2020 08:21:41 +0800 Message-ID: <1579220504-110067-4-git-send-email-hanjie.lin@amlogic.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1579220504-110067-1-git-send-email-hanjie.lin@amlogic.com> References: <1579220504-110067-1-git-send-email-hanjie.lin@amlogic.com> MIME-Version: 1.0 X-Originating-IP: [10.18.11.213] Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org This adds support for the USB2 PHY found in the Amlogic A1 SoC Family. It supports host mode only. Signed-off-by: Yue Wang Signed-off-by: Hanjie Lin Reviewed-by: Martin Blumenstingl Reviewed-by: Neil Armstrong --- drivers/phy/amlogic/phy-meson-g12a-usb2.c | 85 +++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb2.c b/drivers/phy/amlogic/phy-meson-g12a-usb2.c index 9065ffc..33296f8 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-usb2.c +++ b/drivers/phy/amlogic/phy-meson-g12a-usb2.c @@ -146,11 +146,17 @@ #define RESET_COMPLETE_TIME 1000 #define PLL_RESET_COMPLETE_TIME 100 +enum meson_soc_id { + MESON_SOC_G12A = 0, + MESON_SOC_A1, +}; + struct phy_meson_g12a_usb2_priv { struct device *dev; struct regmap *regmap; struct clk *clk; struct reset_control *reset; + int soc_id; }; static const struct regmap_config phy_meson_g12a_usb2_regmap_conf = { @@ -164,6 +170,7 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) { struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy); int ret; + unsigned int value; ret = reset_control_reset(priv->reset); if (ret) @@ -192,18 +199,22 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9)); - regmap_write(priv->regmap, PHY_CTRL_R18, - FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | - FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | - FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | - FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | - FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) | - FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) | - FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) | - FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) | - FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) | - FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | - PHY_CTRL_R18_MPLL_ACG_RANGE); + value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | + FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | + FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | + FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | + FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) | + FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) | + FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) | + FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) | + FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) | + FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | + PHY_CTRL_R18_MPLL_ACG_RANGE; + + if (priv->soc_id == MESON_SOC_A1) + value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL; + + regmap_write(priv->regmap, PHY_CTRL_R18, value); udelay(PLL_RESET_COMPLETE_TIME); @@ -227,13 +238,24 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0)); - regmap_write(priv->regmap, PHY_CTRL_R4, - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | - PHY_CTRL_R4_TEST_BYPASS_MODE_EN | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + if (priv->soc_id == MESON_SOC_G12A) + regmap_write(priv->regmap, PHY_CTRL_R4, + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | + PHY_CTRL_R4_TEST_BYPASS_MODE_EN | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + else if (priv->soc_id == MESON_SOC_A1) { + regmap_write(priv->regmap, PHY_CTRL_R21, + PHY_CTRL_R21_USB2_CAL_ACK_EN | + PHY_CTRL_R21_USB2_TX_STRG_PD | + FIELD_PREP(PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0, 2)); + + /* Analog Settings */ + regmap_write(priv->regmap, PHY_CTRL_R13, + FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); + } /* Tuning Disconnect Threshold */ regmap_write(priv->regmap, PHY_CTRL_R3, @@ -241,11 +263,13 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) | FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3)); - /* Analog Settings */ - regmap_write(priv->regmap, PHY_CTRL_R14, 0); - regmap_write(priv->regmap, PHY_CTRL_R13, - PHY_CTRL_R13_UPDATE_PMA_SIGNALS | - FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); + if (priv->soc_id == MESON_SOC_G12A) { + /* Analog Settings */ + regmap_write(priv->regmap, PHY_CTRL_R14, 0); + regmap_write(priv->regmap, PHY_CTRL_R13, + PHY_CTRL_R13_UPDATE_PMA_SIGNALS | + FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); + } return 0; } @@ -286,6 +310,8 @@ static int phy_meson_g12a_usb2_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); + priv->soc_id = (enum meson_soc_id)of_device_get_match_data(&pdev->dev); + priv->regmap = devm_regmap_init_mmio(dev, base, &phy_meson_g12a_usb2_regmap_conf); if (IS_ERR(priv->regmap)) @@ -321,8 +347,15 @@ static int phy_meson_g12a_usb2_probe(struct platform_device *pdev) } static const struct of_device_id phy_meson_g12a_usb2_of_match[] = { - { .compatible = "amlogic,g12a-usb2-phy", }, - { }, + { + .compatible = "amlogic,g12a-usb2-phy", + .data = (void *)MESON_SOC_G12A, + }, + { + .compatible = "amlogic,a1-usb2-phy", + .data = (void *)MESON_SOC_A1, + }, + { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, phy_meson_g12a_usb2_of_match); From patchwork Fri Jan 17 00:21:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hanjie Lin X-Patchwork-Id: 205597 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 05557C33CAF for ; Fri, 17 Jan 2020 00:22:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CFB6B2073A for ; Fri, 17 Jan 2020 00:22:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733151AbgAQAWP (ORCPT ); Thu, 16 Jan 2020 19:22:15 -0500 Received: from mail-sh.amlogic.com ([58.32.228.43]:52681 "EHLO mail-sh.amlogic.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728963AbgAQAWO (ORCPT ); Thu, 16 Jan 2020 19:22:14 -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; Fri, 17 Jan 2020 08:22:32 +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 v6 4/6] usb: dwc3: Add Amlogic A1 DWC3 glue Date: Fri, 17 Jan 2020 08:21:42 +0800 Message-ID: <1579220504-110067-5-git-send-email-hanjie.lin@amlogic.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1579220504-110067-1-git-send-email-hanjie.lin@amlogic.com> References: <1579220504-110067-1-git-send-email-hanjie.lin@amlogic.com> MIME-Version: 1.0 X-Originating-IP: [10.18.11.213] Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@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: Yue Wang Signed-off-by: Hanjie Lin --- drivers/usb/dwc3/dwc3-meson-g12a.c | 172 +++++++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 56 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 8a3ec1a..70d24b9 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -107,10 +107,37 @@ static const char *phy_names[PHY_COUNT] = { "usb2-phy0", "usb2-phy1", "usb3-phy0", }; +static struct clk_bulk_data meson_g12a_clocks[] = { + { .id = NULL }, +}; + +static struct clk_bulk_data meson_a1_clocks[] = { + { .id = "usb_ctrl" }, + { .id = "usb_bus" }, + { .id = "xtal_usb_ctrl" }, +}; + +struct dwc3_meson_g12a_drvdata { + bool otg_switch_supported; + struct clk_bulk_data *clks; + int num_clks; +}; + +static struct dwc3_meson_g12a_drvdata g12a_drvdata = { + .otg_switch_supported = true, + .clks = meson_g12a_clocks, + .num_clks = ARRAY_SIZE(meson_g12a_clocks), +}; + +static struct dwc3_meson_g12a_drvdata a1_drvdata = { + .otg_switch_supported = false, + .clks = meson_a1_clocks, + .num_clks = ARRAY_SIZE(meson_a1_clocks), +}; + struct dwc3_meson_g12a { struct device *dev; struct regmap *regmap; - struct clk *clk; struct reset_control *reset; struct phy *phys[PHY_COUNT]; enum usb_dr_mode otg_mode; @@ -120,6 +147,7 @@ struct dwc3_meson_g12a { struct regulator *vbus; struct usb_role_switch_desc switch_desc; struct usb_role_switch *role_switch; + const struct dwc3_meson_g12a_drvdata *drvdata; }; static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv, @@ -151,7 +179,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 (priv->drvdata->otg_switch_supported && i == USB2_OTG_PHY) { regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS, @@ -295,7 +323,7 @@ static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv, { int ret; - if (!priv->phys[USB2_OTG_PHY]) + if (!priv->drvdata->otg_switch_supported || !priv->phys[USB2_OTG_PHY]) return -EINVAL; if (mode == PHY_MODE_USB_HOST) @@ -380,14 +408,60 @@ static struct device *dwc3_meson_g12_find_child(struct device *dev, return &pdev->dev; } +static int dwc3_meson_g12a_otg_init(struct platform_device *pdev, + struct dwc3_meson_g12a *priv) +{ + enum phy_mode otg_id; + int ret, irq; + struct device *dev = &pdev->dev; + + if (!priv->drvdata->otg_switch_supported) + return 0; + + if (priv->otg_mode == USB_DR_MODE_OTG) { + /* Ack irq before registering */ + regmap_update_bits(priv->regmap, USB_R5, + USB_R5_ID_DIG_IRQ, 0); + + irq = platform_get_irq(pdev, 0); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + dwc3_meson_g12a_irq_thread, + IRQF_ONESHOT, pdev->name, priv); + if (ret) + return ret; + } + + /* Setup OTG mode corresponding to the ID pin */ + if (priv->otg_mode == USB_DR_MODE_OTG) { + otg_id = dwc3_meson_g12a_get_id(priv); + if (otg_id != priv->otg_phy_mode) { + if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) + dev_warn(dev, "Failed to switch OTG mode\n"); + } + } + + /* Setup role switcher */ + priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev, + "snps,dwc3"); + priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2"); + priv->switch_desc.allow_userspace_control = true; + priv->switch_desc.set = dwc3_meson_g12a_role_set; + priv->switch_desc.get = dwc3_meson_g12a_role_get; + + priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc); + if (IS_ERR(priv->role_switch)) + dev_warn(dev, "Unable to register Role Switch\n"); + + return ret; +} + static int dwc3_meson_g12a_probe(struct platform_device *pdev) { struct dwc3_meson_g12a *priv; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; void __iomem *base; - enum phy_mode otg_id; - int ret, i, irq; + int ret, i; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -409,17 +483,18 @@ 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->drvdata = of_device_get_match_data(&pdev->dev); - ret = clk_prepare_enable(priv->clk); + ret = devm_clk_bulk_get(dev, + priv->drvdata->num_clks, + priv->drvdata->clks); if (ret) return ret; - devm_add_action_or_reset(dev, - (void(*)(void *))clk_disable_unprepare, - priv->clk); + ret = clk_bulk_prepare_enable(priv->drvdata->num_clks, + priv->drvdata->clks); + if (ret) + return ret; platform_set_drvdata(pdev, priv); priv->dev = dev; @@ -433,41 +508,28 @@ 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 */ priv->otg_mode = usb_get_dr_mode(dev); - if (priv->otg_mode == USB_DR_MODE_OTG) { - /* Ack irq before registering */ - regmap_update_bits(priv->regmap, USB_R5, - USB_R5_ID_DIG_IRQ, 0); - - irq = platform_get_irq(pdev, 0); - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, - dwc3_meson_g12a_irq_thread, - IRQF_ONESHOT, pdev->name, priv); - if (ret) - return ret; - } - dwc3_meson_g12a_usb_init(priv); /* Init PHYs */ 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,31 +540,12 @@ 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) { - otg_id = dwc3_meson_g12a_get_id(priv); - if (otg_id != priv->otg_phy_mode) { - if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) - dev_warn(dev, "Failed to switch OTG mode\n"); - } - } - /* Setup role switcher */ - priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev, - "snps,dwc3"); - priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2"); - priv->switch_desc.allow_userspace_control = true; - priv->switch_desc.set = dwc3_meson_g12a_role_set; - priv->switch_desc.get = dwc3_meson_g12a_role_get; - - priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc); - if (IS_ERR(priv->role_switch)) - dev_warn(dev, "Unable to register Role Switch\n"); + ret = dwc3_meson_g12a_otg_init(pdev, priv); + if (ret) + goto err_phys_power; pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -518,6 +561,10 @@ 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->drvdata->num_clks, + priv->drvdata->clks); + return ret; } @@ -527,7 +574,8 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; int i; - usb_role_switch_unregister(priv->role_switch); + if (priv->drvdata->otg_switch_supported) + usb_role_switch_unregister(priv->role_switch); of_platform_depopulate(dev); @@ -540,6 +588,9 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev) pm_runtime_put_noidle(dev); pm_runtime_set_suspended(dev); + clk_bulk_disable_unprepare(priv->drvdata->num_clks, + priv->drvdata->clks); + return 0; } @@ -547,7 +598,8 @@ 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->drvdata->num_clks, + priv->drvdata->clks); return 0; } @@ -556,7 +608,8 @@ 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->drvdata->num_clks, + priv->drvdata->clks); } static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) @@ -619,7 +672,14 @@ 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-g12a-usb-ctrl", + .data = &g12a_drvdata, + }, + { + .compatible = "amlogic,meson-a1-usb-ctrl", + .data = &a1_drvdata, + }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match);