162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * STMicroelectronics STM32 USB PHY Controller driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2018 STMicroelectronics 662306a36Sopenharmony_ci * Author(s): Amelie Delaunay <amelie.delaunay@st.com>. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/bitfield.h> 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/clk-provider.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/iopoll.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/phy/phy.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/reset.h> 1962306a36Sopenharmony_ci#include <linux/units.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define STM32_USBPHYC_PLL 0x0 2262306a36Sopenharmony_ci#define STM32_USBPHYC_MISC 0x8 2362306a36Sopenharmony_ci#define STM32_USBPHYC_MONITOR(X) (0x108 + ((X) * 0x100)) 2462306a36Sopenharmony_ci#define STM32_USBPHYC_TUNE(X) (0x10C + ((X) * 0x100)) 2562306a36Sopenharmony_ci#define STM32_USBPHYC_VERSION 0x3F4 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* STM32_USBPHYC_PLL bit fields */ 2862306a36Sopenharmony_ci#define PLLNDIV GENMASK(6, 0) 2962306a36Sopenharmony_ci#define PLLFRACIN GENMASK(25, 10) 3062306a36Sopenharmony_ci#define PLLEN BIT(26) 3162306a36Sopenharmony_ci#define PLLSTRB BIT(27) 3262306a36Sopenharmony_ci#define PLLSTRBYP BIT(28) 3362306a36Sopenharmony_ci#define PLLFRACCTL BIT(29) 3462306a36Sopenharmony_ci#define PLLDITHEN0 BIT(30) 3562306a36Sopenharmony_ci#define PLLDITHEN1 BIT(31) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* STM32_USBPHYC_MISC bit fields */ 3862306a36Sopenharmony_ci#define SWITHOST BIT(0) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* STM32_USBPHYC_MONITOR bit fields */ 4162306a36Sopenharmony_ci#define STM32_USBPHYC_MON_OUT GENMASK(3, 0) 4262306a36Sopenharmony_ci#define STM32_USBPHYC_MON_SEL GENMASK(8, 4) 4362306a36Sopenharmony_ci#define STM32_USBPHYC_MON_SEL_LOCKP 0x1F 4462306a36Sopenharmony_ci#define STM32_USBPHYC_MON_OUT_LOCKP BIT(3) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* STM32_USBPHYC_TUNE bit fields */ 4762306a36Sopenharmony_ci#define INCURREN BIT(0) 4862306a36Sopenharmony_ci#define INCURRINT BIT(1) 4962306a36Sopenharmony_ci#define LFSCAPEN BIT(2) 5062306a36Sopenharmony_ci#define HSDRVSLEW BIT(3) 5162306a36Sopenharmony_ci#define HSDRVDCCUR BIT(4) 5262306a36Sopenharmony_ci#define HSDRVDCLEV BIT(5) 5362306a36Sopenharmony_ci#define HSDRVCURINCR BIT(6) 5462306a36Sopenharmony_ci#define FSDRVRFADJ BIT(7) 5562306a36Sopenharmony_ci#define HSDRVRFRED BIT(8) 5662306a36Sopenharmony_ci#define HSDRVCHKITRM GENMASK(12, 9) 5762306a36Sopenharmony_ci#define HSDRVCHKZTRM GENMASK(14, 13) 5862306a36Sopenharmony_ci#define OTPCOMP GENMASK(19, 15) 5962306a36Sopenharmony_ci#define SQLCHCTL GENMASK(21, 20) 6062306a36Sopenharmony_ci#define HDRXGNEQEN BIT(22) 6162306a36Sopenharmony_ci#define HSRXOFF GENMASK(24, 23) 6262306a36Sopenharmony_ci#define HSFALLPREEM BIT(25) 6362306a36Sopenharmony_ci#define SHTCCTCTLPROT BIT(26) 6462306a36Sopenharmony_ci#define STAGSEL BIT(27) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cienum boosting_vals { 6762306a36Sopenharmony_ci BOOST_1000_UA = 1000, 6862306a36Sopenharmony_ci BOOST_2000_UA = 2000, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cienum dc_level_vals { 7262306a36Sopenharmony_ci DC_NOMINAL, 7362306a36Sopenharmony_ci DC_PLUS_5_TO_7_MV, 7462306a36Sopenharmony_ci DC_PLUS_10_TO_14_MV, 7562306a36Sopenharmony_ci DC_MINUS_5_TO_7_MV, 7662306a36Sopenharmony_ci DC_MAX, 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cienum current_trim { 8062306a36Sopenharmony_ci CUR_NOMINAL, 8162306a36Sopenharmony_ci CUR_PLUS_1_56_PCT, 8262306a36Sopenharmony_ci CUR_PLUS_3_12_PCT, 8362306a36Sopenharmony_ci CUR_PLUS_4_68_PCT, 8462306a36Sopenharmony_ci CUR_PLUS_6_24_PCT, 8562306a36Sopenharmony_ci CUR_PLUS_7_8_PCT, 8662306a36Sopenharmony_ci CUR_PLUS_9_36_PCT, 8762306a36Sopenharmony_ci CUR_PLUS_10_92_PCT, 8862306a36Sopenharmony_ci CUR_PLUS_12_48_PCT, 8962306a36Sopenharmony_ci CUR_PLUS_14_04_PCT, 9062306a36Sopenharmony_ci CUR_PLUS_15_6_PCT, 9162306a36Sopenharmony_ci CUR_PLUS_17_16_PCT, 9262306a36Sopenharmony_ci CUR_PLUS_19_01_PCT, 9362306a36Sopenharmony_ci CUR_PLUS_20_58_PCT, 9462306a36Sopenharmony_ci CUR_PLUS_22_16_PCT, 9562306a36Sopenharmony_ci CUR_PLUS_23_73_PCT, 9662306a36Sopenharmony_ci CUR_MAX, 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cienum impedance_trim { 10062306a36Sopenharmony_ci IMP_NOMINAL, 10162306a36Sopenharmony_ci IMP_MINUS_2_OHMS, 10262306a36Sopenharmony_ci IMP_MINUS_4_OMHS, 10362306a36Sopenharmony_ci IMP_MINUS_6_OHMS, 10462306a36Sopenharmony_ci IMP_MAX, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cienum squelch_level { 10862306a36Sopenharmony_ci SQLCH_NOMINAL, 10962306a36Sopenharmony_ci SQLCH_PLUS_7_MV, 11062306a36Sopenharmony_ci SQLCH_MINUS_5_MV, 11162306a36Sopenharmony_ci SQLCH_PLUS_14_MV, 11262306a36Sopenharmony_ci SQLCH_MAX, 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cienum rx_offset { 11662306a36Sopenharmony_ci NO_RX_OFFSET, 11762306a36Sopenharmony_ci RX_OFFSET_PLUS_5_MV, 11862306a36Sopenharmony_ci RX_OFFSET_PLUS_10_MV, 11962306a36Sopenharmony_ci RX_OFFSET_MINUS_5_MV, 12062306a36Sopenharmony_ci RX_OFFSET_MAX, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* STM32_USBPHYC_VERSION bit fields */ 12462306a36Sopenharmony_ci#define MINREV GENMASK(3, 0) 12562306a36Sopenharmony_ci#define MAJREV GENMASK(7, 4) 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define PLL_FVCO_MHZ 2880 12862306a36Sopenharmony_ci#define PLL_INFF_MIN_RATE_HZ 19200000 12962306a36Sopenharmony_ci#define PLL_INFF_MAX_RATE_HZ 38400000 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct pll_params { 13262306a36Sopenharmony_ci u8 ndiv; 13362306a36Sopenharmony_ci u16 frac; 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistruct stm32_usbphyc_phy { 13762306a36Sopenharmony_ci struct phy *phy; 13862306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc; 13962306a36Sopenharmony_ci struct regulator *vbus; 14062306a36Sopenharmony_ci u32 index; 14162306a36Sopenharmony_ci bool active; 14262306a36Sopenharmony_ci u32 tune; 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistruct stm32_usbphyc { 14662306a36Sopenharmony_ci struct device *dev; 14762306a36Sopenharmony_ci void __iomem *base; 14862306a36Sopenharmony_ci struct clk *clk; 14962306a36Sopenharmony_ci struct reset_control *rst; 15062306a36Sopenharmony_ci struct stm32_usbphyc_phy **phys; 15162306a36Sopenharmony_ci int nphys; 15262306a36Sopenharmony_ci struct regulator *vdda1v1; 15362306a36Sopenharmony_ci struct regulator *vdda1v8; 15462306a36Sopenharmony_ci atomic_t n_pll_cons; 15562306a36Sopenharmony_ci struct clk_hw clk48_hw; 15662306a36Sopenharmony_ci int switch_setup; 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic inline void stm32_usbphyc_set_bits(void __iomem *reg, u32 bits) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci writel_relaxed(readl_relaxed(reg) | bits, reg); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci writel_relaxed(readl_relaxed(reg) & ~bits, reg); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int stm32_usbphyc_regulators_enable(struct stm32_usbphyc *usbphyc) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci int ret; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci ret = regulator_enable(usbphyc->vdda1v1); 17462306a36Sopenharmony_ci if (ret) 17562306a36Sopenharmony_ci return ret; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci ret = regulator_enable(usbphyc->vdda1v8); 17862306a36Sopenharmony_ci if (ret) 17962306a36Sopenharmony_ci goto vdda1v1_disable; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return 0; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_civdda1v1_disable: 18462306a36Sopenharmony_ci regulator_disable(usbphyc->vdda1v1); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return ret; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int stm32_usbphyc_regulators_disable(struct stm32_usbphyc *usbphyc) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci int ret; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci ret = regulator_disable(usbphyc->vdda1v8); 19462306a36Sopenharmony_ci if (ret) 19562306a36Sopenharmony_ci return ret; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ret = regulator_disable(usbphyc->vdda1v1); 19862306a36Sopenharmony_ci if (ret) 19962306a36Sopenharmony_ci return ret; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void stm32_usbphyc_get_pll_params(u32 clk_rate, 20562306a36Sopenharmony_ci struct pll_params *pll_params) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci unsigned long long fvco, ndiv, frac; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* _ 21062306a36Sopenharmony_ci * | FVCO = INFF*2*(NDIV + FRACT/2^16) when DITHER_DISABLE[1] = 1 21162306a36Sopenharmony_ci * | FVCO = 2880MHz 21262306a36Sopenharmony_ci * < 21362306a36Sopenharmony_ci * | NDIV = integer part of input bits to set the LDF 21462306a36Sopenharmony_ci * |_FRACT = fractional part of input bits to set the LDF 21562306a36Sopenharmony_ci * => PLLNDIV = integer part of (FVCO / (INFF*2)) 21662306a36Sopenharmony_ci * => PLLFRACIN = fractional part of(FVCO / INFF*2) * 2^16 21762306a36Sopenharmony_ci * <=> PLLFRACIN = ((FVCO / (INFF*2)) - PLLNDIV) * 2^16 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci fvco = (unsigned long long)PLL_FVCO_MHZ * HZ_PER_MHZ; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ndiv = fvco; 22262306a36Sopenharmony_ci do_div(ndiv, (clk_rate * 2)); 22362306a36Sopenharmony_ci pll_params->ndiv = (u8)ndiv; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci frac = fvco * (1 << 16); 22662306a36Sopenharmony_ci do_div(frac, (clk_rate * 2)); 22762306a36Sopenharmony_ci frac = frac - (ndiv * (1 << 16)); 22862306a36Sopenharmony_ci pll_params->frac = (u16)frac; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct pll_params pll_params; 23462306a36Sopenharmony_ci u32 clk_rate = clk_get_rate(usbphyc->clk); 23562306a36Sopenharmony_ci u32 ndiv, frac; 23662306a36Sopenharmony_ci u32 usbphyc_pll; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if ((clk_rate < PLL_INFF_MIN_RATE_HZ) || 23962306a36Sopenharmony_ci (clk_rate > PLL_INFF_MAX_RATE_HZ)) { 24062306a36Sopenharmony_ci dev_err(usbphyc->dev, "input clk freq (%dHz) out of range\n", 24162306a36Sopenharmony_ci clk_rate); 24262306a36Sopenharmony_ci return -EINVAL; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci stm32_usbphyc_get_pll_params(clk_rate, &pll_params); 24662306a36Sopenharmony_ci ndiv = FIELD_PREP(PLLNDIV, pll_params.ndiv); 24762306a36Sopenharmony_ci frac = FIELD_PREP(PLLFRACIN, pll_params.frac); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci usbphyc_pll = PLLDITHEN1 | PLLDITHEN0 | PLLSTRBYP | ndiv; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (pll_params.frac) 25262306a36Sopenharmony_ci usbphyc_pll |= PLLFRACCTL | frac; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci writel_relaxed(usbphyc_pll, usbphyc->base + STM32_USBPHYC_PLL); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci dev_dbg(usbphyc->dev, "input clk freq=%dHz, ndiv=%lu, frac=%lu\n", 25762306a36Sopenharmony_ci clk_rate, FIELD_GET(PLLNDIV, usbphyc_pll), 25862306a36Sopenharmony_ci FIELD_GET(PLLFRACIN, usbphyc_pll)); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int __stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; 26662306a36Sopenharmony_ci u32 pllen; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci stm32_usbphyc_clr_bits(pll_reg, PLLEN); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ 27162306a36Sopenharmony_ci if (readl_relaxed_poll_timeout(pll_reg, pllen, !(pllen & PLLEN), 5, 50)) 27262306a36Sopenharmony_ci dev_err(usbphyc->dev, "PLL not reset\n"); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return stm32_usbphyc_regulators_disable(usbphyc); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci /* Check if a phy port is still active or clk48 in use */ 28062306a36Sopenharmony_ci if (atomic_dec_return(&usbphyc->n_pll_cons) > 0) 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return __stm32_usbphyc_pll_disable(usbphyc); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; 28962306a36Sopenharmony_ci bool pllen = readl_relaxed(pll_reg) & PLLEN; 29062306a36Sopenharmony_ci int ret; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* 29362306a36Sopenharmony_ci * Check if a phy port or clk48 prepare has configured the pll 29462306a36Sopenharmony_ci * and ensure the PLL is enabled 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ci if (atomic_inc_return(&usbphyc->n_pll_cons) > 1 && pllen) 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (pllen) { 30062306a36Sopenharmony_ci /* 30162306a36Sopenharmony_ci * PLL shouldn't be enabled without known consumer, 30262306a36Sopenharmony_ci * disable it and reinit n_pll_cons 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_ci dev_warn(usbphyc->dev, "PLL enabled without known consumers\n"); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci ret = __stm32_usbphyc_pll_disable(usbphyc); 30762306a36Sopenharmony_ci if (ret) 30862306a36Sopenharmony_ci goto dec_n_pll_cons; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci ret = stm32_usbphyc_regulators_enable(usbphyc); 31262306a36Sopenharmony_ci if (ret) 31362306a36Sopenharmony_ci goto dec_n_pll_cons; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci ret = stm32_usbphyc_pll_init(usbphyc); 31662306a36Sopenharmony_ci if (ret) 31762306a36Sopenharmony_ci goto reg_disable; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci stm32_usbphyc_set_bits(pll_reg, PLLEN); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Wait for maximum lock time */ 32262306a36Sopenharmony_ci usleep_range(200, 300); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cireg_disable: 32762306a36Sopenharmony_ci stm32_usbphyc_regulators_disable(usbphyc); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cidec_n_pll_cons: 33062306a36Sopenharmony_ci atomic_dec(&usbphyc->n_pll_cons); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return ret; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int stm32_usbphyc_phy_init(struct phy *phy) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); 33862306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc = usbphyc_phy->usbphyc; 33962306a36Sopenharmony_ci u32 reg_mon = STM32_USBPHYC_MONITOR(usbphyc_phy->index); 34062306a36Sopenharmony_ci u32 monsel = FIELD_PREP(STM32_USBPHYC_MON_SEL, 34162306a36Sopenharmony_ci STM32_USBPHYC_MON_SEL_LOCKP); 34262306a36Sopenharmony_ci u32 monout; 34362306a36Sopenharmony_ci int ret; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci ret = stm32_usbphyc_pll_enable(usbphyc); 34662306a36Sopenharmony_ci if (ret) 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Check that PLL Lock input to PHY is High */ 35062306a36Sopenharmony_ci writel_relaxed(monsel, usbphyc->base + reg_mon); 35162306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout(usbphyc->base + reg_mon, monout, 35262306a36Sopenharmony_ci (monout & STM32_USBPHYC_MON_OUT_LOCKP), 35362306a36Sopenharmony_ci 100, 1000); 35462306a36Sopenharmony_ci if (ret) { 35562306a36Sopenharmony_ci dev_err(usbphyc->dev, "PLL Lock input to PHY is Low (val=%x)\n", 35662306a36Sopenharmony_ci (u32)(monout & STM32_USBPHYC_MON_OUT)); 35762306a36Sopenharmony_ci goto pll_disable; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci usbphyc_phy->active = true; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cipll_disable: 36562306a36Sopenharmony_ci stm32_usbphyc_pll_disable(usbphyc); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int stm32_usbphyc_phy_exit(struct phy *phy) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); 37362306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc = usbphyc_phy->usbphyc; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci usbphyc_phy->active = false; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return stm32_usbphyc_pll_disable(usbphyc); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int stm32_usbphyc_phy_power_on(struct phy *phy) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (usbphyc_phy->vbus) 38562306a36Sopenharmony_ci return regulator_enable(usbphyc_phy->vbus); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci return 0; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int stm32_usbphyc_phy_power_off(struct phy *phy) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (usbphyc_phy->vbus) 39562306a36Sopenharmony_ci return regulator_disable(usbphyc_phy->vbus); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic const struct phy_ops stm32_usbphyc_phy_ops = { 40162306a36Sopenharmony_ci .init = stm32_usbphyc_phy_init, 40262306a36Sopenharmony_ci .exit = stm32_usbphyc_phy_exit, 40362306a36Sopenharmony_ci .power_on = stm32_usbphyc_phy_power_on, 40462306a36Sopenharmony_ci .power_off = stm32_usbphyc_phy_power_off, 40562306a36Sopenharmony_ci .owner = THIS_MODULE, 40662306a36Sopenharmony_ci}; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int stm32_usbphyc_clk48_prepare(struct clk_hw *hw) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return stm32_usbphyc_pll_enable(usbphyc); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, clk48_hw); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci stm32_usbphyc_pll_disable(usbphyc); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic unsigned long stm32_usbphyc_clk48_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci return 48000000; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic const struct clk_ops usbphyc_clk48_ops = { 42862306a36Sopenharmony_ci .prepare = stm32_usbphyc_clk48_prepare, 42962306a36Sopenharmony_ci .unprepare = stm32_usbphyc_clk48_unprepare, 43062306a36Sopenharmony_ci .recalc_rate = stm32_usbphyc_clk48_recalc_rate, 43162306a36Sopenharmony_ci}; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void stm32_usbphyc_clk48_unregister(void *data) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc = data; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci of_clk_del_provider(usbphyc->dev->of_node); 43862306a36Sopenharmony_ci clk_hw_unregister(&usbphyc->clk48_hw); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int stm32_usbphyc_clk48_register(struct stm32_usbphyc *usbphyc) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct device_node *node = usbphyc->dev->of_node; 44462306a36Sopenharmony_ci struct clk_init_data init = { }; 44562306a36Sopenharmony_ci int ret = 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci init.name = "ck_usbo_48m"; 44862306a36Sopenharmony_ci init.ops = &usbphyc_clk48_ops; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci usbphyc->clk48_hw.init = &init; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci ret = clk_hw_register(usbphyc->dev, &usbphyc->clk48_hw); 45362306a36Sopenharmony_ci if (ret) 45462306a36Sopenharmony_ci return ret; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &usbphyc->clk48_hw); 45762306a36Sopenharmony_ci if (ret) 45862306a36Sopenharmony_ci clk_hw_unregister(&usbphyc->clk48_hw); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return ret; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic void stm32_usbphyc_phy_tuning(struct stm32_usbphyc *usbphyc, 46462306a36Sopenharmony_ci struct device_node *np, u32 index) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys[index]; 46762306a36Sopenharmony_ci u32 reg = STM32_USBPHYC_TUNE(index); 46862306a36Sopenharmony_ci u32 otpcomp, val; 46962306a36Sopenharmony_ci int ret; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* Backup OTP compensation code */ 47262306a36Sopenharmony_ci otpcomp = FIELD_GET(OTPCOMP, readl_relaxed(usbphyc->base + reg)); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci ret = of_property_read_u32(np, "st,current-boost-microamp", &val); 47562306a36Sopenharmony_ci if (ret != -EINVAL) { 47662306a36Sopenharmony_ci if (!ret && (val == BOOST_1000_UA || val == BOOST_2000_UA)) { 47762306a36Sopenharmony_ci val = (val == BOOST_2000_UA) ? 1 : 0; 47862306a36Sopenharmony_ci usbphyc_phy->tune |= INCURREN | FIELD_PREP(INCURRINT, val); 47962306a36Sopenharmony_ci } else { 48062306a36Sopenharmony_ci dev_warn(usbphyc->dev, "phy%d: invalid st,current-boost-microamp\n", index); 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (!of_property_read_bool(np, "st,no-lsfs-fb-cap")) 48562306a36Sopenharmony_ci usbphyc_phy->tune |= LFSCAPEN; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (of_property_read_bool(np, "st,decrease-hs-slew-rate")) 48862306a36Sopenharmony_ci usbphyc_phy->tune |= HSDRVSLEW; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci ret = of_property_read_u32(np, "st,tune-hs-dc-level", &val); 49162306a36Sopenharmony_ci if (ret != -EINVAL) { 49262306a36Sopenharmony_ci if (!ret && val < DC_MAX) { 49362306a36Sopenharmony_ci if (val == DC_MINUS_5_TO_7_MV) {/* Decreases HS driver DC level */ 49462306a36Sopenharmony_ci usbphyc_phy->tune |= HSDRVDCCUR; 49562306a36Sopenharmony_ci } else if (val > 0) { /* Increases HS driver DC level */ 49662306a36Sopenharmony_ci val = (val == DC_PLUS_10_TO_14_MV) ? 1 : 0; 49762306a36Sopenharmony_ci usbphyc_phy->tune |= HSDRVCURINCR | FIELD_PREP(HSDRVDCLEV, val); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci } else { 50062306a36Sopenharmony_ci dev_warn(usbphyc->dev, "phy%d: invalid st,tune-hs-dc-level\n", index); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (of_property_read_bool(np, "st,enable-fs-rftime-tuning")) 50562306a36Sopenharmony_ci usbphyc_phy->tune |= FSDRVRFADJ; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (of_property_read_bool(np, "st,enable-hs-rftime-reduction")) 50862306a36Sopenharmony_ci usbphyc_phy->tune |= HSDRVRFRED; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ret = of_property_read_u32(np, "st,trim-hs-current", &val); 51162306a36Sopenharmony_ci if (ret != -EINVAL) { 51262306a36Sopenharmony_ci if (!ret && val < CUR_MAX) 51362306a36Sopenharmony_ci usbphyc_phy->tune |= FIELD_PREP(HSDRVCHKITRM, val); 51462306a36Sopenharmony_ci else 51562306a36Sopenharmony_ci dev_warn(usbphyc->dev, "phy%d: invalid st,trim-hs-current\n", index); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci ret = of_property_read_u32(np, "st,trim-hs-impedance", &val); 51962306a36Sopenharmony_ci if (ret != -EINVAL) { 52062306a36Sopenharmony_ci if (!ret && val < IMP_MAX) 52162306a36Sopenharmony_ci usbphyc_phy->tune |= FIELD_PREP(HSDRVCHKZTRM, val); 52262306a36Sopenharmony_ci else 52362306a36Sopenharmony_ci dev_warn(usbphyc->dev, "phy%d: invalid st,trim-hs-impedance\n", index); 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci ret = of_property_read_u32(np, "st,tune-squelch-level", &val); 52762306a36Sopenharmony_ci if (ret != -EINVAL) { 52862306a36Sopenharmony_ci if (!ret && val < SQLCH_MAX) 52962306a36Sopenharmony_ci usbphyc_phy->tune |= FIELD_PREP(SQLCHCTL, val); 53062306a36Sopenharmony_ci else 53162306a36Sopenharmony_ci dev_warn(usbphyc->dev, "phy%d: invalid st,tune-squelch\n", index); 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (of_property_read_bool(np, "st,enable-hs-rx-gain-eq")) 53562306a36Sopenharmony_ci usbphyc_phy->tune |= HDRXGNEQEN; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci ret = of_property_read_u32(np, "st,tune-hs-rx-offset", &val); 53862306a36Sopenharmony_ci if (ret != -EINVAL) { 53962306a36Sopenharmony_ci if (!ret && val < RX_OFFSET_MAX) 54062306a36Sopenharmony_ci usbphyc_phy->tune |= FIELD_PREP(HSRXOFF, val); 54162306a36Sopenharmony_ci else 54262306a36Sopenharmony_ci dev_warn(usbphyc->dev, "phy%d: invalid st,tune-hs-rx-offset\n", index); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (of_property_read_bool(np, "st,no-hs-ftime-ctrl")) 54662306a36Sopenharmony_ci usbphyc_phy->tune |= HSFALLPREEM; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (!of_property_read_bool(np, "st,no-lsfs-sc")) 54962306a36Sopenharmony_ci usbphyc_phy->tune |= SHTCCTCTLPROT; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (of_property_read_bool(np, "st,enable-hs-tx-staggering")) 55262306a36Sopenharmony_ci usbphyc_phy->tune |= STAGSEL; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* Restore OTP compensation code */ 55562306a36Sopenharmony_ci usbphyc_phy->tune |= FIELD_PREP(OTPCOMP, otpcomp); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* 55862306a36Sopenharmony_ci * By default, if no st,xxx tuning property is used, usbphyc_phy->tune is equal to 55962306a36Sopenharmony_ci * STM32_USBPHYC_TUNE reset value (LFSCAPEN | SHTCCTCTLPROT | OTPCOMP). 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci writel_relaxed(usbphyc_phy->tune, usbphyc->base + reg); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, 56562306a36Sopenharmony_ci u32 utmi_switch) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci if (!utmi_switch) 56862306a36Sopenharmony_ci stm32_usbphyc_clr_bits(usbphyc->base + STM32_USBPHYC_MISC, 56962306a36Sopenharmony_ci SWITHOST); 57062306a36Sopenharmony_ci else 57162306a36Sopenharmony_ci stm32_usbphyc_set_bits(usbphyc->base + STM32_USBPHYC_MISC, 57262306a36Sopenharmony_ci SWITHOST); 57362306a36Sopenharmony_ci usbphyc->switch_setup = utmi_switch; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic struct phy *stm32_usbphyc_of_xlate(struct device *dev, 57762306a36Sopenharmony_ci struct of_phandle_args *args) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev); 58062306a36Sopenharmony_ci struct stm32_usbphyc_phy *usbphyc_phy = NULL; 58162306a36Sopenharmony_ci struct device_node *phynode = args->np; 58262306a36Sopenharmony_ci int port = 0; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci for (port = 0; port < usbphyc->nphys; port++) { 58562306a36Sopenharmony_ci if (phynode == usbphyc->phys[port]->phy->dev.of_node) { 58662306a36Sopenharmony_ci usbphyc_phy = usbphyc->phys[port]; 58762306a36Sopenharmony_ci break; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci if (!usbphyc_phy) { 59162306a36Sopenharmony_ci dev_err(dev, "failed to find phy\n"); 59262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (((usbphyc_phy->index == 0) && (args->args_count != 0)) || 59662306a36Sopenharmony_ci ((usbphyc_phy->index == 1) && (args->args_count != 1))) { 59762306a36Sopenharmony_ci dev_err(dev, "invalid number of cells for phy port%d\n", 59862306a36Sopenharmony_ci usbphyc_phy->index); 59962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* Configure the UTMI switch for PHY port#2 */ 60362306a36Sopenharmony_ci if (usbphyc_phy->index == 1) { 60462306a36Sopenharmony_ci if (usbphyc->switch_setup < 0) { 60562306a36Sopenharmony_ci stm32_usbphyc_switch_setup(usbphyc, args->args[0]); 60662306a36Sopenharmony_ci } else { 60762306a36Sopenharmony_ci if (args->args[0] != usbphyc->switch_setup) { 60862306a36Sopenharmony_ci dev_err(dev, "phy port1 already used\n"); 60962306a36Sopenharmony_ci return ERR_PTR(-EBUSY); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return usbphyc_phy->phy; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int stm32_usbphyc_probe(struct platform_device *pdev) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc; 62062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 62162306a36Sopenharmony_ci struct device_node *child, *np = dev->of_node; 62262306a36Sopenharmony_ci struct phy_provider *phy_provider; 62362306a36Sopenharmony_ci u32 pllen, version; 62462306a36Sopenharmony_ci int ret, port = 0; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci usbphyc = devm_kzalloc(dev, sizeof(*usbphyc), GFP_KERNEL); 62762306a36Sopenharmony_ci if (!usbphyc) 62862306a36Sopenharmony_ci return -ENOMEM; 62962306a36Sopenharmony_ci usbphyc->dev = dev; 63062306a36Sopenharmony_ci dev_set_drvdata(dev, usbphyc); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci usbphyc->base = devm_platform_ioremap_resource(pdev, 0); 63362306a36Sopenharmony_ci if (IS_ERR(usbphyc->base)) 63462306a36Sopenharmony_ci return PTR_ERR(usbphyc->base); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci usbphyc->clk = devm_clk_get(dev, NULL); 63762306a36Sopenharmony_ci if (IS_ERR(usbphyc->clk)) 63862306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(usbphyc->clk), "clk get_failed\n"); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ret = clk_prepare_enable(usbphyc->clk); 64162306a36Sopenharmony_ci if (ret) { 64262306a36Sopenharmony_ci dev_err(dev, "clk enable failed: %d\n", ret); 64362306a36Sopenharmony_ci return ret; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci usbphyc->rst = devm_reset_control_get(dev, NULL); 64762306a36Sopenharmony_ci if (!IS_ERR(usbphyc->rst)) { 64862306a36Sopenharmony_ci reset_control_assert(usbphyc->rst); 64962306a36Sopenharmony_ci udelay(2); 65062306a36Sopenharmony_ci reset_control_deassert(usbphyc->rst); 65162306a36Sopenharmony_ci } else { 65262306a36Sopenharmony_ci ret = PTR_ERR(usbphyc->rst); 65362306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 65462306a36Sopenharmony_ci goto clk_disable; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci stm32_usbphyc_clr_bits(usbphyc->base + STM32_USBPHYC_PLL, PLLEN); 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* 66062306a36Sopenharmony_ci * Wait for minimum width of powerdown pulse (ENABLE = Low): 66162306a36Sopenharmony_ci * we have to ensure the PLL is disabled before phys initialization. 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_ci if (readl_relaxed_poll_timeout(usbphyc->base + STM32_USBPHYC_PLL, 66462306a36Sopenharmony_ci pllen, !(pllen & PLLEN), 5, 50)) { 66562306a36Sopenharmony_ci dev_warn(usbphyc->dev, "PLL not reset\n"); 66662306a36Sopenharmony_ci ret = -EPROBE_DEFER; 66762306a36Sopenharmony_ci goto clk_disable; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci usbphyc->switch_setup = -EINVAL; 67162306a36Sopenharmony_ci usbphyc->nphys = of_get_child_count(np); 67262306a36Sopenharmony_ci usbphyc->phys = devm_kcalloc(dev, usbphyc->nphys, 67362306a36Sopenharmony_ci sizeof(*usbphyc->phys), GFP_KERNEL); 67462306a36Sopenharmony_ci if (!usbphyc->phys) { 67562306a36Sopenharmony_ci ret = -ENOMEM; 67662306a36Sopenharmony_ci goto clk_disable; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci usbphyc->vdda1v1 = devm_regulator_get(dev, "vdda1v1"); 68062306a36Sopenharmony_ci if (IS_ERR(usbphyc->vdda1v1)) { 68162306a36Sopenharmony_ci ret = dev_err_probe(dev, PTR_ERR(usbphyc->vdda1v1), 68262306a36Sopenharmony_ci "failed to get vdda1v1 supply\n"); 68362306a36Sopenharmony_ci goto clk_disable; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci usbphyc->vdda1v8 = devm_regulator_get(dev, "vdda1v8"); 68762306a36Sopenharmony_ci if (IS_ERR(usbphyc->vdda1v8)) { 68862306a36Sopenharmony_ci ret = dev_err_probe(dev, PTR_ERR(usbphyc->vdda1v8), 68962306a36Sopenharmony_ci "failed to get vdda1v8 supply\n"); 69062306a36Sopenharmony_ci goto clk_disable; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci for_each_child_of_node(np, child) { 69462306a36Sopenharmony_ci struct stm32_usbphyc_phy *usbphyc_phy; 69562306a36Sopenharmony_ci struct phy *phy; 69662306a36Sopenharmony_ci u32 index; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci phy = devm_phy_create(dev, child, &stm32_usbphyc_phy_ops); 69962306a36Sopenharmony_ci if (IS_ERR(phy)) { 70062306a36Sopenharmony_ci ret = PTR_ERR(phy); 70162306a36Sopenharmony_ci if (ret != -EPROBE_DEFER) 70262306a36Sopenharmony_ci dev_err(dev, "failed to create phy%d: %d\n", 70362306a36Sopenharmony_ci port, ret); 70462306a36Sopenharmony_ci goto put_child; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci usbphyc_phy = devm_kzalloc(dev, sizeof(*usbphyc_phy), 70862306a36Sopenharmony_ci GFP_KERNEL); 70962306a36Sopenharmony_ci if (!usbphyc_phy) { 71062306a36Sopenharmony_ci ret = -ENOMEM; 71162306a36Sopenharmony_ci goto put_child; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci ret = of_property_read_u32(child, "reg", &index); 71562306a36Sopenharmony_ci if (ret || index > usbphyc->nphys) { 71662306a36Sopenharmony_ci dev_err(&phy->dev, "invalid reg property: %d\n", ret); 71762306a36Sopenharmony_ci if (!ret) 71862306a36Sopenharmony_ci ret = -EINVAL; 71962306a36Sopenharmony_ci goto put_child; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci usbphyc->phys[port] = usbphyc_phy; 72362306a36Sopenharmony_ci phy_set_bus_width(phy, 8); 72462306a36Sopenharmony_ci phy_set_drvdata(phy, usbphyc_phy); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci usbphyc->phys[port]->phy = phy; 72762306a36Sopenharmony_ci usbphyc->phys[port]->usbphyc = usbphyc; 72862306a36Sopenharmony_ci usbphyc->phys[port]->index = index; 72962306a36Sopenharmony_ci usbphyc->phys[port]->active = false; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci usbphyc->phys[port]->vbus = devm_regulator_get_optional(&phy->dev, "vbus"); 73262306a36Sopenharmony_ci if (IS_ERR(usbphyc->phys[port]->vbus)) { 73362306a36Sopenharmony_ci ret = PTR_ERR(usbphyc->phys[port]->vbus); 73462306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 73562306a36Sopenharmony_ci goto put_child; 73662306a36Sopenharmony_ci usbphyc->phys[port]->vbus = NULL; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* Configure phy tuning */ 74062306a36Sopenharmony_ci stm32_usbphyc_phy_tuning(usbphyc, child, index); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci port++; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, 74662306a36Sopenharmony_ci stm32_usbphyc_of_xlate); 74762306a36Sopenharmony_ci if (IS_ERR(phy_provider)) { 74862306a36Sopenharmony_ci ret = PTR_ERR(phy_provider); 74962306a36Sopenharmony_ci dev_err(dev, "failed to register phy provider: %d\n", ret); 75062306a36Sopenharmony_ci goto clk_disable; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci ret = stm32_usbphyc_clk48_register(usbphyc); 75462306a36Sopenharmony_ci if (ret) { 75562306a36Sopenharmony_ci dev_err(dev, "failed to register ck_usbo_48m clock: %d\n", ret); 75662306a36Sopenharmony_ci goto clk_disable; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION); 76062306a36Sopenharmony_ci dev_info(dev, "registered rev:%lu.%lu\n", 76162306a36Sopenharmony_ci FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version)); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci return 0; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ciput_child: 76662306a36Sopenharmony_ci of_node_put(child); 76762306a36Sopenharmony_ciclk_disable: 76862306a36Sopenharmony_ci clk_disable_unprepare(usbphyc->clk); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return ret; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic void stm32_usbphyc_remove(struct platform_device *pdev) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc = dev_get_drvdata(&pdev->dev); 77662306a36Sopenharmony_ci int port; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* Ensure PHYs are not active, to allow PLL disabling */ 77962306a36Sopenharmony_ci for (port = 0; port < usbphyc->nphys; port++) 78062306a36Sopenharmony_ci if (usbphyc->phys[port]->active) 78162306a36Sopenharmony_ci stm32_usbphyc_phy_exit(usbphyc->phys[port]->phy); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci stm32_usbphyc_clk48_unregister(usbphyc); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci clk_disable_unprepare(usbphyc->clk); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic int __maybe_unused stm32_usbphyc_resume(struct device *dev) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev); 79162306a36Sopenharmony_ci struct stm32_usbphyc_phy *usbphyc_phy; 79262306a36Sopenharmony_ci int port; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (usbphyc->switch_setup >= 0) 79562306a36Sopenharmony_ci stm32_usbphyc_switch_setup(usbphyc, usbphyc->switch_setup); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci for (port = 0; port < usbphyc->nphys; port++) { 79862306a36Sopenharmony_ci usbphyc_phy = usbphyc->phys[port]; 79962306a36Sopenharmony_ci writel_relaxed(usbphyc_phy->tune, usbphyc->base + STM32_USBPHYC_TUNE(port)); 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return 0; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(stm32_usbphyc_pm_ops, NULL, stm32_usbphyc_resume); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic const struct of_device_id stm32_usbphyc_of_match[] = { 80862306a36Sopenharmony_ci { .compatible = "st,stm32mp1-usbphyc", }, 80962306a36Sopenharmony_ci { }, 81062306a36Sopenharmony_ci}; 81162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_usbphyc_of_match); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic struct platform_driver stm32_usbphyc_driver = { 81462306a36Sopenharmony_ci .probe = stm32_usbphyc_probe, 81562306a36Sopenharmony_ci .remove_new = stm32_usbphyc_remove, 81662306a36Sopenharmony_ci .driver = { 81762306a36Sopenharmony_ci .of_match_table = stm32_usbphyc_of_match, 81862306a36Sopenharmony_ci .name = "stm32-usbphyc", 81962306a36Sopenharmony_ci .pm = &stm32_usbphyc_pm_ops, 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci}; 82262306a36Sopenharmony_cimodule_platform_driver(stm32_usbphyc_driver); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32 USBPHYC driver"); 82562306a36Sopenharmony_ciMODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>"); 82662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 827