RE: [PATCH v4 2/6] phy: exynos5-usbdrd: support HS phy for ExynosAutov920
From: Pritam Manohar Sutar <hidden>
Date: 2025-07-10 07:54:48
Also in:
linux-arm-kernel, linux-phy, linux-samsung-soc, lkml
Hi Neil,
quoted hunk ↗ jump to hunk
-----Original Message----- From: Pritam Manohar Sutar <redacted> Sent: 01 July 2025 05:37 PM To: vkoul@kernel.org; kishon@kernel.org; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; alim.akhtar@samsung.com; andre.draszik@linaro.org; peter.griffin@linaro.org; neil.armstrong@linaro.org; kauschluss@disroot.org; ivo.ivanov.ivanov1@gmail.com; m.szyprowski@samsung.com; s.nawrocki@samsung.com; pritam.sutar@samsung.com Cc: linux-phy@lists.infradead.org; devicetree@vger.kernel.org; linux- kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-samsung- soc@vger.kernel.org; rosa.pila@samsung.com; dev.tailor@samsung.com; faraz.ata@samsung.com; muhammed.ali@samsung.com; selvarasu.g@samsung.com Subject: [PATCH v4 2/6] phy: exynos5-usbdrd: support HS phy for ExynosAutov920 This SoC has a single USB 3.1 DRD combo phy that supports both UTMI+ (HS) and PIPE3 (SS) and three USB2.0 DRD HS phy controllers those only support the UTMI+ (HS) interface. Support only UTMI+ port for this SoC which is very similar to what the existing Exynos850 supports. This SoC shares phy isol between USBs. Bypass PHY isol when first USB is powered on and enable it when all of then are powered off. Add required change in phy driver to support HS phy for this SoC. Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> Signed-off-by: Pritam Manohar Sutar <redacted> --- drivers/phy/samsung/phy-exynos5-usbdrd.c | 131 ++++++++++++++++++++ include/linux/soc/samsung/exynos-regs-pmu.h | 2 + 2 files changed, 133 insertions(+)diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.cb/drivers/phy/samsung/phy-exynos5-usbdrd.c index dd660ebe8045..64f3316f6ad4 100644--- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c@@ -480,6 +480,8 @@ struct exynos5_usbdrd_phy { enum typec_orientation orientation; }; +static atomic_t usage_count = ATOMIC_INIT(0); +
Added phy isolation for exynosautov920 support as per comments on v3 patch-set. Since phy isol is shared across usb ports, added usage counter to bypass and enable it. Can you please review the code? However, added "Reviewed-by" tag as per comments on v3 patch-set.
quoted hunk ↗ jump to hunk
static inline struct exynos5_usbdrd_phy *to_usbdrd_phy(struct phy_usb_instance *inst) {@@ -2054,6 +2056,132 @@ static const struct exynos5_usbdrd_phy_drvdataexynos990_usbdrd_phy = { .n_regulators = ARRAY_SIZE(exynos5_regulator_names), }; +static int exynosautov920_usbdrd_phy_init(struct phy *phy) { + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + int ret; + + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd-quoted
clks);+ if (ret) + return ret; + + if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) { + /* Bypass PHY isol when first USB is powered on */ + if ((atomic_inc_return(&usage_count) == 1)) + inst->phy_cfg->phy_isol(inst, false); + } + + /* UTMI or PIPE3 specific init */ + inst->phy_cfg->phy_init(phy_drd); + + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); + + return 0; +} + +static int exynosautov920_usbdrd_phy_exit(struct phy *phy) { + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + int ret = 0; + + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd-quoted
clks);+ if (ret) + return ret; + + if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) { + exynos850_usbdrd_phy_exit(phy); + + /* enable PHY isol when all USBs are powered off */ + if (atomic_dec_and_test(&usage_count)) + inst->phy_cfg->phy_isol(inst, true); + } + + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); + + return 0; +} + +static int exynosautov920_usbdrd_phy_power_on(struct phy *phy) { + int ret; + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n"); + + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_core_clks, + phy_drd->core_clks); + if (ret) + return ret; + + /* Enable supply */ + ret = regulator_bulk_enable(phy_drd->drv_data->n_regulators, + phy_drd->regulators); + if (ret) { + dev_err(phy_drd->dev, "Failed to enable PHY regulator(s)\n"); + goto fail_supply; + } + + return 0; + +fail_supply: + clk_bulk_disable_unprepare(phy_drd->drv_data->n_core_clks, + phy_drd->core_clks); + + return ret; +} + +static int exynosautov920_usbdrd_phy_power_off(struct phy *phy) { + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n"); + + /* Disable supply */ + regulator_bulk_disable(phy_drd->drv_data->n_regulators, + phy_drd->regulators); + + clk_bulk_disable_unprepare(phy_drd->drv_data->n_core_clks, + phy_drd->core_clks); + + return 0; +} + +static const char * const exynosautov920_regulator_names[] = { + "avdd075_usb", "avdd18_usb20", "avdd33_usb20", }; + +static const struct phy_ops exynosautov920_usbdrd_phy_ops = { + .init = exynosautov920_usbdrd_phy_init, + .exit = exynosautov920_usbdrd_phy_exit, + .power_on = exynosautov920_usbdrd_phy_power_on, + .power_off = exynosautov920_usbdrd_phy_power_off, + .owner = THIS_MODULE, +}; + +static const struct exynos5_usbdrd_phy_config phy_cfg_exynosautov920[] = { + { + .id = EXYNOS5_DRDPHY_UTMI, + .phy_isol = exynos5_usbdrd_phy_isol, + .phy_init = exynos850_usbdrd_utmi_init, + }, +}; + +static const struct exynos5_usbdrd_phy_drvdata exynosautov920_usbdrd_phy = { + .phy_cfg = phy_cfg_exynosautov920, + .phy_ops = &exynosautov920_usbdrd_phy_ops, + .pmu_offset_usbdrd0_phy = EXYNOSAUTOV920_PHY_CTRL_USB20, + .clk_names = exynos5_clk_names, + .n_clks = ARRAY_SIZE(exynos5_clk_names), + .core_clk_names = exynos5_core_clk_names, + .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names), + .regulator_names = exynosautov920_regulator_names, + .n_regulators = ARRAY_SIZE(exynosautov920_regulator_names), +}; + static const struct exynos5_usbdrd_phy_config phy_cfg_gs101[] = { { .id = EXYNOS5_DRDPHY_UTMI,@@ -2260,6 +2388,9 @@ static const struct of_device_idexynos5_usbdrd_phy_of_match[] = { }, { .compatible = "samsung,exynos990-usbdrd-phy", .data = &exynos990_usbdrd_phy + }, { + .compatible = "samsung,exynosautov920-usbdrd-phy", + .data = &exynosautov920_usbdrd_phy }, { }, };diff --git a/include/linux/soc/samsung/exynos-regs-pmu.hb/include/linux/soc/samsung/exynos-regs-pmu.h index 71e0c09a49eb..4923f9be3d1f 100644--- a/include/linux/soc/samsung/exynos-regs-pmu.h +++ b/include/linux/soc/samsung/exynos-regs-pmu.h@@ -688,4 +688,6 @@ #define GS101_GRP2_INTR_BID_UPEND(0x0208) #define GS101_GRP2_INTR_BID_CLEAR (0x020c) +/* exynosautov920 */ +#define EXYNOSAUTOV920_PHY_CTRL_USB20 (0x0710) #endif /* __LINUX_SOC_EXYNOS_REGS_PMU_H */ -- 2.34.1
Thank you. Regards, Pritam