1109 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved.4 */5 6#include <linux/clk.h>7#include <linux/delay.h>8#include <linux/err.h>9#include <linux/io.h>10#include <linux/kernel.h>11#include <linux/mfd/syscon.h>12#include <linux/module.h>13#include <linux/nvmem-consumer.h>14#include <linux/of.h>15#include <linux/phy/phy.h>16#include <linux/platform_device.h>17#include <linux/regmap.h>18#include <linux/regulator/consumer.h>19#include <linux/reset.h>20#include <linux/slab.h>21 22#include <dt-bindings/phy/phy-qcom-qusb2.h>23 24#define QUSB2PHY_PLL 0x025#define QUSB2PHY_PLL_TEST 0x0426#define CLK_REF_SEL BIT(7)27 28#define QUSB2PHY_PLL_TUNE 0x0829#define QUSB2PHY_PLL_USER_CTL1 0x0c30#define QUSB2PHY_PLL_USER_CTL2 0x1031#define QUSB2PHY_PLL_AUTOPGM_CTL1 0x1c32#define QUSB2PHY_PLL_PWR_CTRL 0x1833 34/* QUSB2PHY_PLL_STATUS register bits */35#define PLL_LOCKED BIT(5)36 37/* QUSB2PHY_PLL_COMMON_STATUS_ONE register bits */38#define CORE_READY_STATUS BIT(0)39 40/* QUSB2PHY_PORT_POWERDOWN register bits */41#define CLAMP_N_EN BIT(5)42#define FREEZIO_N BIT(1)43#define POWER_DOWN BIT(0)44 45/* QUSB2PHY_PWR_CTRL1 register bits */46#define PWR_CTRL1_VREF_SUPPLY_TRIM BIT(5)47#define PWR_CTRL1_CLAMP_N_EN BIT(1)48 49#define QUSB2PHY_REFCLK_ENABLE BIT(0)50 51#define PHY_CLK_SCHEME_SEL BIT(0)52 53/* QUSB2PHY_INTR_CTRL register bits */54#define DMSE_INTR_HIGH_SEL BIT(4)55#define DPSE_INTR_HIGH_SEL BIT(3)56#define CHG_DET_INTR_EN BIT(2)57#define DMSE_INTR_EN BIT(1)58#define DPSE_INTR_EN BIT(0)59 60/* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE register bits */61#define CORE_PLL_EN_FROM_RESET BIT(4)62#define CORE_RESET BIT(5)63#define CORE_RESET_MUX BIT(6)64 65/* QUSB2PHY_IMP_CTRL1 register bits */66#define IMP_RES_OFFSET_MASK GENMASK(5, 0)67#define IMP_RES_OFFSET_SHIFT 0x068 69/* QUSB2PHY_PLL_BIAS_CONTROL_2 register bits */70#define BIAS_CTRL2_RES_OFFSET_MASK GENMASK(5, 0)71#define BIAS_CTRL2_RES_OFFSET_SHIFT 0x072 73/* QUSB2PHY_CHG_CONTROL_2 register bits */74#define CHG_CTRL2_OFFSET_MASK GENMASK(5, 4)75#define CHG_CTRL2_OFFSET_SHIFT 0x476 77/* QUSB2PHY_PORT_TUNE1 register bits */78#define HSTX_TRIM_MASK GENMASK(7, 4)79#define HSTX_TRIM_SHIFT 0x480#define PREEMPH_WIDTH_HALF_BIT BIT(2)81#define PREEMPHASIS_EN_MASK GENMASK(1, 0)82#define PREEMPHASIS_EN_SHIFT 0x083 84/* QUSB2PHY_PORT_TUNE2 register bits */85#define HSDISC_TRIM_MASK GENMASK(1, 0)86#define HSDISC_TRIM_SHIFT 0x087 88#define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x0489#define QUSB2PHY_PLL_CLOCK_INVERTERS 0x18c90#define QUSB2PHY_PLL_CMODE 0x2c91#define QUSB2PHY_PLL_LOCK_DELAY 0x18492#define QUSB2PHY_PLL_DIGITAL_TIMERS_TWO 0xb493#define QUSB2PHY_PLL_BIAS_CONTROL_1 0x19494#define QUSB2PHY_PLL_BIAS_CONTROL_2 0x19895#define QUSB2PHY_PWR_CTRL2 0x21496#define QUSB2PHY_IMP_CTRL1 0x22097#define QUSB2PHY_IMP_CTRL2 0x22498#define QUSB2PHY_CHG_CTRL2 0x23c99 100struct qusb2_phy_init_tbl {101 unsigned int offset;102 unsigned int val;103 /*104 * register part of layout ?105 * if yes, then offset gives index in the reg-layout106 */107 int in_layout;108};109 110#define QUSB2_PHY_INIT_CFG(o, v) \111 { \112 .offset = o, \113 .val = v, \114 }115 116#define QUSB2_PHY_INIT_CFG_L(o, v) \117 { \118 .offset = o, \119 .val = v, \120 .in_layout = 1, \121 }122 123/* set of registers with offsets different per-PHY */124enum qusb2phy_reg_layout {125 QUSB2PHY_PLL_CORE_INPUT_OVERRIDE,126 QUSB2PHY_PLL_STATUS,127 QUSB2PHY_PORT_TUNE1,128 QUSB2PHY_PORT_TUNE2,129 QUSB2PHY_PORT_TUNE3,130 QUSB2PHY_PORT_TUNE4,131 QUSB2PHY_PORT_TUNE5,132 QUSB2PHY_PORT_TEST1,133 QUSB2PHY_PORT_TEST2,134 QUSB2PHY_PORT_POWERDOWN,135 QUSB2PHY_INTR_CTRL,136};137 138static const struct qusb2_phy_init_tbl ipq6018_init_tbl[] = {139 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL, 0x14),140 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xF8),141 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xB3),142 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x83),143 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xC0),144 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),145 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),146 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),147 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE5, 0x00),148 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),149 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),150 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TEST, 0x80),151 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9F),152};153 154static const unsigned int ipq6018_regs_layout[] = {155 [QUSB2PHY_PLL_STATUS] = 0x38,156 [QUSB2PHY_PORT_TUNE1] = 0x80,157 [QUSB2PHY_PORT_TUNE2] = 0x84,158 [QUSB2PHY_PORT_TUNE3] = 0x88,159 [QUSB2PHY_PORT_TUNE4] = 0x8C,160 [QUSB2PHY_PORT_TUNE5] = 0x90,161 [QUSB2PHY_PORT_TEST1] = 0x98,162 [QUSB2PHY_PORT_TEST2] = 0x9C,163 [QUSB2PHY_PORT_POWERDOWN] = 0xB4,164 [QUSB2PHY_INTR_CTRL] = 0xBC,165};166 167static const unsigned int msm8996_regs_layout[] = {168 [QUSB2PHY_PLL_STATUS] = 0x38,169 [QUSB2PHY_PORT_TUNE1] = 0x80,170 [QUSB2PHY_PORT_TUNE2] = 0x84,171 [QUSB2PHY_PORT_TUNE3] = 0x88,172 [QUSB2PHY_PORT_TUNE4] = 0x8c,173 [QUSB2PHY_PORT_TUNE5] = 0x90,174 [QUSB2PHY_PORT_TEST1] = 0xb8,175 [QUSB2PHY_PORT_TEST2] = 0x9c,176 [QUSB2PHY_PORT_POWERDOWN] = 0xb4,177 [QUSB2PHY_INTR_CTRL] = 0xbc,178};179 180static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {181 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xf8),182 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xb3),183 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x83),184 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xc0),185 186 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),187 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),188 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),189 190 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),191 192 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),193 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),194};195 196static const unsigned int msm8998_regs_layout[] = {197 [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,198 [QUSB2PHY_PLL_STATUS] = 0x1a0,199 [QUSB2PHY_PORT_TUNE1] = 0x23c,200 [QUSB2PHY_PORT_TUNE2] = 0x240,201 [QUSB2PHY_PORT_TUNE3] = 0x244,202 [QUSB2PHY_PORT_TUNE4] = 0x248,203 [QUSB2PHY_PORT_TEST1] = 0x24c,204 [QUSB2PHY_PORT_TEST2] = 0x250,205 [QUSB2PHY_PORT_POWERDOWN] = 0x210,206 [QUSB2PHY_INTR_CTRL] = 0x22c,207};208 209static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = {210 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x13),211 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),212 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),213 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a),214 215 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xa5),216 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x09),217 218 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),219};220 221static const struct qusb2_phy_init_tbl sm6115_init_tbl[] = {222 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xf8),223 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x53),224 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x81),225 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0x17),226 227 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),228 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),229 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),230 231 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),232 233 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),234 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),235};236 237static const unsigned int qusb2_v2_regs_layout[] = {238 [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,239 [QUSB2PHY_PLL_STATUS] = 0x1a0,240 [QUSB2PHY_PORT_TUNE1] = 0x240,241 [QUSB2PHY_PORT_TUNE2] = 0x244,242 [QUSB2PHY_PORT_TUNE3] = 0x248,243 [QUSB2PHY_PORT_TUNE4] = 0x24c,244 [QUSB2PHY_PORT_TUNE5] = 0x250,245 [QUSB2PHY_PORT_TEST1] = 0x254,246 [QUSB2PHY_PORT_TEST2] = 0x258,247 [QUSB2PHY_PORT_POWERDOWN] = 0x210,248 [QUSB2PHY_INTR_CTRL] = 0x230,249};250 251static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {252 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),253 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),254 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),255 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a),256 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),257 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_1, 0x40),258 QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_BIAS_CONTROL_2, 0x20),259 QUSB2_PHY_INIT_CFG(QUSB2PHY_PWR_CTRL2, 0x21),260 QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL1, 0x0),261 QUSB2_PHY_INIT_CFG(QUSB2PHY_IMP_CTRL2, 0x58),262 263 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0x30),264 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x29),265 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0xca),266 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0x04),267 QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE5, 0x03),268 269 QUSB2_PHY_INIT_CFG(QUSB2PHY_CHG_CTRL2, 0x0),270};271 272struct qusb2_phy_cfg {273 const struct qusb2_phy_init_tbl *tbl;274 /* number of entries in the table */275 unsigned int tbl_num;276 /* offset to PHY_CLK_SCHEME register in TCSR map */277 unsigned int clk_scheme_offset;278 279 /* array of registers with different offsets */280 const unsigned int *regs;281 unsigned int mask_core_ready;282 unsigned int disable_ctrl;283 unsigned int autoresume_en;284 285 /* true if PHY has PLL_TEST register to select clk_scheme */286 bool has_pll_test;287 288 /* true if TUNE1 register must be updated by fused value, else TUNE2 */289 bool update_tune1_with_efuse;290 291 /* true if PHY has PLL_CORE_INPUT_OVERRIDE register to reset PLL */292 bool has_pll_override;293 294 /* true if PHY default clk scheme is single-ended */295 bool se_clk_scheme_default;296};297 298static const struct qusb2_phy_cfg msm8996_phy_cfg = {299 .tbl = msm8996_init_tbl,300 .tbl_num = ARRAY_SIZE(msm8996_init_tbl),301 .regs = msm8996_regs_layout,302 303 .has_pll_test = true,304 .se_clk_scheme_default = true,305 .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),306 .mask_core_ready = PLL_LOCKED,307 .autoresume_en = BIT(3),308};309 310static const struct qusb2_phy_cfg msm8998_phy_cfg = {311 .tbl = msm8998_init_tbl,312 .tbl_num = ARRAY_SIZE(msm8998_init_tbl),313 .regs = msm8998_regs_layout,314 315 .disable_ctrl = POWER_DOWN,316 .mask_core_ready = CORE_READY_STATUS,317 .has_pll_override = true,318 .se_clk_scheme_default = true,319 .autoresume_en = BIT(0),320 .update_tune1_with_efuse = true,321};322 323static const struct qusb2_phy_cfg ipq6018_phy_cfg = {324 .tbl = ipq6018_init_tbl,325 .tbl_num = ARRAY_SIZE(ipq6018_init_tbl),326 .regs = ipq6018_regs_layout,327 328 .disable_ctrl = POWER_DOWN,329 .mask_core_ready = PLL_LOCKED,330 /* autoresume not used */331 .autoresume_en = BIT(0),332};333 334static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {335 .tbl = qusb2_v2_init_tbl,336 .tbl_num = ARRAY_SIZE(qusb2_v2_init_tbl),337 .regs = qusb2_v2_regs_layout,338 339 .disable_ctrl = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |340 POWER_DOWN),341 .mask_core_ready = CORE_READY_STATUS,342 .has_pll_override = true,343 .se_clk_scheme_default = true,344 .autoresume_en = BIT(0),345 .update_tune1_with_efuse = true,346};347 348static const struct qusb2_phy_cfg sdm660_phy_cfg = {349 .tbl = msm8996_init_tbl,350 .tbl_num = ARRAY_SIZE(msm8996_init_tbl),351 .regs = msm8996_regs_layout,352 353 .has_pll_test = true,354 .se_clk_scheme_default = false,355 .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),356 .mask_core_ready = PLL_LOCKED,357 .autoresume_en = BIT(3),358};359 360static const struct qusb2_phy_cfg sm6115_phy_cfg = {361 .tbl = sm6115_init_tbl,362 .tbl_num = ARRAY_SIZE(sm6115_init_tbl),363 .regs = msm8996_regs_layout,364 365 .has_pll_test = true,366 .se_clk_scheme_default = true,367 .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),368 .mask_core_ready = PLL_LOCKED,369 .autoresume_en = BIT(3),370};371 372static const char * const qusb2_phy_vreg_names[] = {373 "vdd", "vdda-pll", "vdda-phy-dpdm",374};375 376#define QUSB2_NUM_VREGS ARRAY_SIZE(qusb2_phy_vreg_names)377 378/* struct override_param - structure holding qusb2 v2 phy overriding param379 * set override true if the device tree property exists and read and assign380 * to value381 */382struct override_param {383 bool override;384 u8 value;385};386 387/*struct override_params - structure holding qusb2 v2 phy overriding params388 * @imp_res_offset: rescode offset to be updated in IMP_CTRL1 register389 * @hstx_trim: HSTX_TRIM to be updated in TUNE1 register390 * @preemphasis: Amplitude Pre-Emphasis to be updated in TUNE1 register391 * @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1392 * @bias_ctrl: bias ctrl to be updated in BIAS_CONTROL_2 register393 * @charge_ctrl: charge ctrl to be updated in CHG_CTRL2 register394 * @hsdisc_trim: disconnect threshold to be updated in TUNE2 register395 */396struct override_params {397 struct override_param imp_res_offset;398 struct override_param hstx_trim;399 struct override_param preemphasis;400 struct override_param preemphasis_width;401 struct override_param bias_ctrl;402 struct override_param charge_ctrl;403 struct override_param hsdisc_trim;404};405 406/**407 * struct qusb2_phy - structure holding qusb2 phy attributes408 *409 * @phy: generic phy410 * @base: iomapped memory space for qubs2 phy411 *412 * @cfg_ahb_clk: AHB2PHY interface clock413 * @ref_clk: phy reference clock414 * @iface_clk: phy interface clock415 * @phy_reset: phy reset control416 * @vregs: regulator supplies bulk data417 *418 * @tcsr: TCSR syscon register map419 * @cell: nvmem cell containing phy tuning value420 *421 * @overrides: pointer to structure for all overriding tuning params422 *423 * @cfg: phy config data424 * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme425 * @phy_initialized: indicate if PHY has been initialized426 * @mode: current PHY mode427 */428struct qusb2_phy {429 struct phy *phy;430 void __iomem *base;431 432 struct clk *cfg_ahb_clk;433 struct clk *ref_clk;434 struct clk *iface_clk;435 struct reset_control *phy_reset;436 struct regulator_bulk_data vregs[QUSB2_NUM_VREGS];437 438 struct regmap *tcsr;439 struct nvmem_cell *cell;440 441 struct override_params overrides;442 443 const struct qusb2_phy_cfg *cfg;444 bool has_se_clk_scheme;445 bool phy_initialized;446 enum phy_mode mode;447};448 449static inline void qusb2_write_mask(void __iomem *base, u32 offset,450 u32 val, u32 mask)451{452 u32 reg;453 454 reg = readl(base + offset);455 reg &= ~mask;456 reg |= val & mask;457 writel(reg, base + offset);458 459 /* Ensure above write is completed */460 readl(base + offset);461}462 463static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val)464{465 u32 reg;466 467 reg = readl(base + offset);468 reg |= val;469 writel(reg, base + offset);470 471 /* Ensure above write is completed */472 readl(base + offset);473}474 475static inline void qusb2_clrbits(void __iomem *base, u32 offset, u32 val)476{477 u32 reg;478 479 reg = readl(base + offset);480 reg &= ~val;481 writel(reg, base + offset);482 483 /* Ensure above write is completed */484 readl(base + offset);485}486 487static inline488void qcom_qusb2_phy_configure(void __iomem *base,489 const unsigned int *regs,490 const struct qusb2_phy_init_tbl tbl[], int num)491{492 int i;493 494 for (i = 0; i < num; i++) {495 if (tbl[i].in_layout)496 writel(tbl[i].val, base + regs[tbl[i].offset]);497 else498 writel(tbl[i].val, base + tbl[i].offset);499 }500}501 502/*503 * Update board specific PHY tuning override values if specified from504 * device tree.505 */506static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy)507{508 const struct qusb2_phy_cfg *cfg = qphy->cfg;509 struct override_params *or = &qphy->overrides;510 511 if (or->imp_res_offset.override)512 qusb2_write_mask(qphy->base, QUSB2PHY_IMP_CTRL1,513 or->imp_res_offset.value << IMP_RES_OFFSET_SHIFT,514 IMP_RES_OFFSET_MASK);515 516 if (or->bias_ctrl.override)517 qusb2_write_mask(qphy->base, QUSB2PHY_PLL_BIAS_CONTROL_2,518 or->bias_ctrl.value << BIAS_CTRL2_RES_OFFSET_SHIFT,519 BIAS_CTRL2_RES_OFFSET_MASK);520 521 if (or->charge_ctrl.override)522 qusb2_write_mask(qphy->base, QUSB2PHY_CHG_CTRL2,523 or->charge_ctrl.value << CHG_CTRL2_OFFSET_SHIFT,524 CHG_CTRL2_OFFSET_MASK);525 526 if (or->hstx_trim.override)527 qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],528 or->hstx_trim.value << HSTX_TRIM_SHIFT,529 HSTX_TRIM_MASK);530 531 if (or->preemphasis.override)532 qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],533 or->preemphasis.value << PREEMPHASIS_EN_SHIFT,534 PREEMPHASIS_EN_MASK);535 536 if (or->preemphasis_width.override) {537 if (or->preemphasis_width.value ==538 QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT)539 qusb2_setbits(qphy->base,540 cfg->regs[QUSB2PHY_PORT_TUNE1],541 PREEMPH_WIDTH_HALF_BIT);542 else543 qusb2_clrbits(qphy->base,544 cfg->regs[QUSB2PHY_PORT_TUNE1],545 PREEMPH_WIDTH_HALF_BIT);546 }547 548 if (or->hsdisc_trim.override)549 qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE2],550 or->hsdisc_trim.value << HSDISC_TRIM_SHIFT,551 HSDISC_TRIM_MASK);552}553 554/*555 * Fetches HS Tx tuning value from nvmem and sets the556 * QUSB2PHY_PORT_TUNE1/2 register.557 * For error case, skip setting the value and use the default value.558 */559static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)560{561 struct device *dev = &qphy->phy->dev;562 const struct qusb2_phy_cfg *cfg = qphy->cfg;563 u8 *val, hstx_trim;564 565 /* efuse register is optional */566 if (!qphy->cell)567 return;568 569 /*570 * Read efuse register having TUNE2/1 parameter's high nibble.571 * If efuse register shows value as 0x0 (indicating value is not572 * fused), or if we fail to find a valid efuse register setting,573 * then use default value for high nibble that we have already574 * set while configuring the phy.575 */576 val = nvmem_cell_read(qphy->cell, NULL);577 if (IS_ERR(val)) {578 dev_dbg(dev, "failed to read a valid hs-tx trim value\n");579 return;580 }581 hstx_trim = val[0];582 kfree(val);583 if (!hstx_trim) {584 dev_dbg(dev, "failed to read a valid hs-tx trim value\n");585 return;586 }587 588 /* Fused TUNE1/2 value is the higher nibble only */589 if (cfg->update_tune1_with_efuse)590 qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],591 hstx_trim << HSTX_TRIM_SHIFT, HSTX_TRIM_MASK);592 else593 qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE2],594 hstx_trim << HSTX_TRIM_SHIFT, HSTX_TRIM_MASK);595}596 597static int qusb2_phy_set_mode(struct phy *phy,598 enum phy_mode mode, int submode)599{600 struct qusb2_phy *qphy = phy_get_drvdata(phy);601 602 qphy->mode = mode;603 604 return 0;605}606 607static int __maybe_unused qusb2_phy_runtime_suspend(struct device *dev)608{609 struct qusb2_phy *qphy = dev_get_drvdata(dev);610 const struct qusb2_phy_cfg *cfg = qphy->cfg;611 u32 intr_mask;612 613 dev_vdbg(dev, "Suspending QUSB2 Phy, mode:%d\n", qphy->mode);614 615 if (!qphy->phy_initialized) {616 dev_vdbg(dev, "PHY not initialized, bailing out\n");617 return 0;618 }619 620 /*621 * Enable DP/DM interrupts to detect line state changes based on current622 * speed. In other words, enable the triggers _opposite_ of what the623 * current D+/D- levels are e.g. if currently D+ high, D- low624 * (HS 'J'/Suspend), configure the mask to trigger on D+ low OR D- high625 */626 intr_mask = DPSE_INTR_EN | DMSE_INTR_EN;627 switch (qphy->mode) {628 case PHY_MODE_USB_HOST_HS:629 case PHY_MODE_USB_HOST_FS:630 case PHY_MODE_USB_DEVICE_HS:631 case PHY_MODE_USB_DEVICE_FS:632 intr_mask |= DMSE_INTR_HIGH_SEL;633 break;634 case PHY_MODE_USB_HOST_LS:635 case PHY_MODE_USB_DEVICE_LS:636 intr_mask |= DPSE_INTR_HIGH_SEL;637 break;638 default:639 /* No device connected, enable both DP/DM high interrupt */640 intr_mask |= DMSE_INTR_HIGH_SEL;641 intr_mask |= DPSE_INTR_HIGH_SEL;642 break;643 }644 645 writel(intr_mask, qphy->base + cfg->regs[QUSB2PHY_INTR_CTRL]);646 647 /* hold core PLL into reset */648 if (cfg->has_pll_override) {649 qusb2_setbits(qphy->base,650 cfg->regs[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE],651 CORE_PLL_EN_FROM_RESET | CORE_RESET |652 CORE_RESET_MUX);653 }654 655 /* enable phy auto-resume only if device is connected on bus */656 if (qphy->mode != PHY_MODE_INVALID) {657 qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TEST1],658 cfg->autoresume_en);659 /* Autoresume bit has to be toggled in order to enable it */660 qusb2_clrbits(qphy->base, cfg->regs[QUSB2PHY_PORT_TEST1],661 cfg->autoresume_en);662 }663 664 if (!qphy->has_se_clk_scheme)665 clk_disable_unprepare(qphy->ref_clk);666 667 clk_disable_unprepare(qphy->cfg_ahb_clk);668 clk_disable_unprepare(qphy->iface_clk);669 670 return 0;671}672 673static int __maybe_unused qusb2_phy_runtime_resume(struct device *dev)674{675 struct qusb2_phy *qphy = dev_get_drvdata(dev);676 const struct qusb2_phy_cfg *cfg = qphy->cfg;677 int ret;678 679 dev_vdbg(dev, "Resuming QUSB2 phy, mode:%d\n", qphy->mode);680 681 if (!qphy->phy_initialized) {682 dev_vdbg(dev, "PHY not initialized, bailing out\n");683 return 0;684 }685 686 ret = clk_prepare_enable(qphy->iface_clk);687 if (ret) {688 dev_err(dev, "failed to enable iface_clk, %d\n", ret);689 return ret;690 }691 692 ret = clk_prepare_enable(qphy->cfg_ahb_clk);693 if (ret) {694 dev_err(dev, "failed to enable cfg ahb clock, %d\n", ret);695 goto disable_iface_clk;696 }697 698 if (!qphy->has_se_clk_scheme) {699 ret = clk_prepare_enable(qphy->ref_clk);700 if (ret) {701 dev_err(dev, "failed to enable ref clk, %d\n", ret);702 goto disable_ahb_clk;703 }704 }705 706 writel(0x0, qphy->base + cfg->regs[QUSB2PHY_INTR_CTRL]);707 708 /* bring core PLL out of reset */709 if (cfg->has_pll_override) {710 qusb2_clrbits(qphy->base,711 cfg->regs[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE],712 CORE_RESET | CORE_RESET_MUX);713 }714 715 return 0;716 717disable_ahb_clk:718 clk_disable_unprepare(qphy->cfg_ahb_clk);719disable_iface_clk:720 clk_disable_unprepare(qphy->iface_clk);721 722 return ret;723}724 725static int qusb2_phy_init(struct phy *phy)726{727 struct qusb2_phy *qphy = phy_get_drvdata(phy);728 const struct qusb2_phy_cfg *cfg = qphy->cfg;729 unsigned int val = 0;730 unsigned int clk_scheme;731 int ret;732 733 dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);734 735 /* turn on regulator supplies */736 ret = regulator_bulk_enable(ARRAY_SIZE(qphy->vregs), qphy->vregs);737 if (ret)738 return ret;739 740 ret = clk_prepare_enable(qphy->iface_clk);741 if (ret) {742 dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);743 goto poweroff_phy;744 }745 746 /* enable ahb interface clock to program phy */747 ret = clk_prepare_enable(qphy->cfg_ahb_clk);748 if (ret) {749 dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);750 goto disable_iface_clk;751 }752 753 /* Perform phy reset */754 ret = reset_control_assert(qphy->phy_reset);755 if (ret) {756 dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);757 goto disable_ahb_clk;758 }759 760 /* 100 us delay to keep PHY in reset mode */761 usleep_range(100, 150);762 763 ret = reset_control_deassert(qphy->phy_reset);764 if (ret) {765 dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);766 goto disable_ahb_clk;767 }768 769 /* Disable the PHY */770 qusb2_setbits(qphy->base, cfg->regs[QUSB2PHY_PORT_POWERDOWN],771 qphy->cfg->disable_ctrl);772 773 if (cfg->has_pll_test) {774 /* save reset value to override reference clock scheme later */775 val = readl(qphy->base + QUSB2PHY_PLL_TEST);776 }777 778 qcom_qusb2_phy_configure(qphy->base, cfg->regs, cfg->tbl,779 cfg->tbl_num);780 781 /* Override board specific PHY tuning values */782 qusb2_phy_override_phy_params(qphy);783 784 /* Set efuse value for tuning the PHY */785 qusb2_phy_set_tune2_param(qphy);786 787 /* Enable the PHY */788 qusb2_clrbits(qphy->base, cfg->regs[QUSB2PHY_PORT_POWERDOWN],789 POWER_DOWN);790 791 /* Required to get phy pll lock successfully */792 usleep_range(150, 160);793 794 /*795 * Not all the SoCs have got a readable TCSR_PHY_CLK_SCHEME796 * register in the TCSR so, if there's none, use the default797 * value hardcoded in the configuration.798 */799 qphy->has_se_clk_scheme = cfg->se_clk_scheme_default;800 801 /*802 * read TCSR_PHY_CLK_SCHEME register to check if single-ended803 * clock scheme is selected. If yes, then disable differential804 * ref_clk and use single-ended clock, otherwise use differential805 * ref_clk only.806 */807 if (qphy->tcsr) {808 ret = regmap_read(qphy->tcsr, qphy->cfg->clk_scheme_offset,809 &clk_scheme);810 if (ret) {811 dev_err(&phy->dev, "failed to read clk scheme reg\n");812 goto assert_phy_reset;813 }814 815 /* is it a differential clock scheme ? */816 if (!(clk_scheme & PHY_CLK_SCHEME_SEL)) {817 dev_vdbg(&phy->dev, "%s(): select differential clk\n",818 __func__);819 qphy->has_se_clk_scheme = false;820 } else {821 dev_vdbg(&phy->dev, "%s(): select single-ended clk\n",822 __func__);823 }824 }825 826 if (!qphy->has_se_clk_scheme) {827 ret = clk_prepare_enable(qphy->ref_clk);828 if (ret) {829 dev_err(&phy->dev, "failed to enable ref clk, %d\n",830 ret);831 goto assert_phy_reset;832 }833 }834 835 if (cfg->has_pll_test) {836 if (!qphy->has_se_clk_scheme)837 val &= ~CLK_REF_SEL;838 else839 val |= CLK_REF_SEL;840 841 writel(val, qphy->base + QUSB2PHY_PLL_TEST);842 843 /* ensure above write is through */844 readl(qphy->base + QUSB2PHY_PLL_TEST);845 }846 847 /* Required to get phy pll lock successfully */848 usleep_range(100, 110);849 850 val = readb(qphy->base + cfg->regs[QUSB2PHY_PLL_STATUS]);851 if (!(val & cfg->mask_core_ready)) {852 dev_err(&phy->dev,853 "QUSB2PHY pll lock failed: status reg = %x\n", val);854 ret = -EBUSY;855 goto disable_ref_clk;856 }857 qphy->phy_initialized = true;858 859 return 0;860 861disable_ref_clk:862 if (!qphy->has_se_clk_scheme)863 clk_disable_unprepare(qphy->ref_clk);864assert_phy_reset:865 reset_control_assert(qphy->phy_reset);866disable_ahb_clk:867 clk_disable_unprepare(qphy->cfg_ahb_clk);868disable_iface_clk:869 clk_disable_unprepare(qphy->iface_clk);870poweroff_phy:871 regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);872 873 return ret;874}875 876static int qusb2_phy_exit(struct phy *phy)877{878 struct qusb2_phy *qphy = phy_get_drvdata(phy);879 880 /* Disable the PHY */881 qusb2_setbits(qphy->base, qphy->cfg->regs[QUSB2PHY_PORT_POWERDOWN],882 qphy->cfg->disable_ctrl);883 884 if (!qphy->has_se_clk_scheme)885 clk_disable_unprepare(qphy->ref_clk);886 887 reset_control_assert(qphy->phy_reset);888 889 clk_disable_unprepare(qphy->cfg_ahb_clk);890 clk_disable_unprepare(qphy->iface_clk);891 892 regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);893 894 qphy->phy_initialized = false;895 896 return 0;897}898 899static const struct phy_ops qusb2_phy_gen_ops = {900 .init = qusb2_phy_init,901 .exit = qusb2_phy_exit,902 .set_mode = qusb2_phy_set_mode,903 .owner = THIS_MODULE,904};905 906static const struct of_device_id qusb2_phy_of_match_table[] = {907 {908 .compatible = "qcom,ipq6018-qusb2-phy",909 .data = &ipq6018_phy_cfg,910 }, {911 .compatible = "qcom,ipq8074-qusb2-phy",912 .data = &msm8996_phy_cfg,913 }, {914 .compatible = "qcom,ipq9574-qusb2-phy",915 .data = &ipq6018_phy_cfg,916 }, {917 .compatible = "qcom,msm8953-qusb2-phy",918 .data = &msm8996_phy_cfg,919 }, {920 .compatible = "qcom,msm8996-qusb2-phy",921 .data = &msm8996_phy_cfg,922 }, {923 .compatible = "qcom,msm8998-qusb2-phy",924 .data = &msm8998_phy_cfg,925 }, {926 .compatible = "qcom,qcm2290-qusb2-phy",927 .data = &sm6115_phy_cfg,928 }, {929 .compatible = "qcom,sdm660-qusb2-phy",930 .data = &sdm660_phy_cfg,931 }, {932 .compatible = "qcom,sm4250-qusb2-phy",933 .data = &sm6115_phy_cfg,934 }, {935 .compatible = "qcom,sm6115-qusb2-phy",936 .data = &sm6115_phy_cfg,937 }, {938 /*939 * Deprecated. Only here to support legacy device940 * trees that didn't include "qcom,qusb2-v2-phy"941 */942 .compatible = "qcom,sdm845-qusb2-phy",943 .data = &qusb2_v2_phy_cfg,944 }, {945 .compatible = "qcom,qusb2-v2-phy",946 .data = &qusb2_v2_phy_cfg,947 },948 { },949};950MODULE_DEVICE_TABLE(of, qusb2_phy_of_match_table);951 952static const struct dev_pm_ops qusb2_phy_pm_ops = {953 SET_RUNTIME_PM_OPS(qusb2_phy_runtime_suspend,954 qusb2_phy_runtime_resume, NULL)955};956 957static int qusb2_phy_probe(struct platform_device *pdev)958{959 struct device *dev = &pdev->dev;960 struct qusb2_phy *qphy;961 struct phy_provider *phy_provider;962 struct phy *generic_phy;963 int ret, i;964 int num;965 u32 value;966 struct override_params *or;967 968 qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);969 if (!qphy)970 return -ENOMEM;971 or = &qphy->overrides;972 973 qphy->base = devm_platform_ioremap_resource(pdev, 0);974 if (IS_ERR(qphy->base))975 return PTR_ERR(qphy->base);976 977 qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb");978 if (IS_ERR(qphy->cfg_ahb_clk))979 return dev_err_probe(dev, PTR_ERR(qphy->cfg_ahb_clk),980 "failed to get cfg ahb clk\n");981 982 qphy->ref_clk = devm_clk_get(dev, "ref");983 if (IS_ERR(qphy->ref_clk))984 return dev_err_probe(dev, PTR_ERR(qphy->ref_clk),985 "failed to get ref clk\n");986 987 qphy->iface_clk = devm_clk_get_optional(dev, "iface");988 if (IS_ERR(qphy->iface_clk))989 return PTR_ERR(qphy->iface_clk);990 991 qphy->phy_reset = devm_reset_control_get_by_index(&pdev->dev, 0);992 if (IS_ERR(qphy->phy_reset)) {993 dev_err(dev, "failed to get phy core reset\n");994 return PTR_ERR(qphy->phy_reset);995 }996 997 num = ARRAY_SIZE(qphy->vregs);998 for (i = 0; i < num; i++)999 qphy->vregs[i].supply = qusb2_phy_vreg_names[i];1000 1001 ret = devm_regulator_bulk_get(dev, num, qphy->vregs);1002 if (ret)1003 return dev_err_probe(dev, ret,1004 "failed to get regulator supplies\n");1005 1006 /* Get the specific init parameters of QMP phy */1007 qphy->cfg = of_device_get_match_data(dev);1008 1009 qphy->tcsr = syscon_regmap_lookup_by_phandle(dev->of_node,1010 "qcom,tcsr-syscon");1011 if (IS_ERR(qphy->tcsr)) {1012 dev_dbg(dev, "failed to lookup TCSR regmap\n");1013 qphy->tcsr = NULL;1014 }1015 1016 qphy->cell = devm_nvmem_cell_get(dev, NULL);1017 if (IS_ERR(qphy->cell)) {1018 if (PTR_ERR(qphy->cell) == -EPROBE_DEFER)1019 return -EPROBE_DEFER;1020 qphy->cell = NULL;1021 dev_dbg(dev, "failed to lookup tune2 hstx trim value\n");1022 }1023 1024 if (!of_property_read_u32(dev->of_node, "qcom,imp-res-offset-value",1025 &value)) {1026 or->imp_res_offset.value = (u8)value;1027 or->imp_res_offset.override = true;1028 }1029 1030 if (!of_property_read_u32(dev->of_node, "qcom,bias-ctrl-value",1031 &value)) {1032 or->bias_ctrl.value = (u8)value;1033 or->bias_ctrl.override = true;1034 }1035 1036 if (!of_property_read_u32(dev->of_node, "qcom,charge-ctrl-value",1037 &value)) {1038 or->charge_ctrl.value = (u8)value;1039 or->charge_ctrl.override = true;1040 }1041 1042 if (!of_property_read_u32(dev->of_node, "qcom,hstx-trim-value",1043 &value)) {1044 or->hstx_trim.value = (u8)value;1045 or->hstx_trim.override = true;1046 }1047 1048 if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level",1049 &value)) {1050 or->preemphasis.value = (u8)value;1051 or->preemphasis.override = true;1052 }1053 1054 if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width",1055 &value)) {1056 or->preemphasis_width.value = (u8)value;1057 or->preemphasis_width.override = true;1058 }1059 1060 if (!of_property_read_u32(dev->of_node, "qcom,hsdisc-trim-value",1061 &value)) {1062 or->hsdisc_trim.value = (u8)value;1063 or->hsdisc_trim.override = true;1064 }1065 1066 pm_runtime_set_active(dev);1067 pm_runtime_enable(dev);1068 /*1069 * Prevent runtime pm from being ON by default. Users can enable1070 * it using power/control in sysfs.1071 */1072 pm_runtime_forbid(dev);1073 1074 generic_phy = devm_phy_create(dev, NULL, &qusb2_phy_gen_ops);1075 if (IS_ERR(generic_phy)) {1076 ret = PTR_ERR(generic_phy);1077 dev_err(dev, "failed to create phy, %d\n", ret);1078 pm_runtime_disable(dev);1079 return ret;1080 }1081 qphy->phy = generic_phy;1082 1083 dev_set_drvdata(dev, qphy);1084 phy_set_drvdata(generic_phy, qphy);1085 1086 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);1087 if (!IS_ERR(phy_provider))1088 dev_info(dev, "Registered Qcom-QUSB2 phy\n");1089 else1090 pm_runtime_disable(dev);1091 1092 return PTR_ERR_OR_ZERO(phy_provider);1093}1094 1095static struct platform_driver qusb2_phy_driver = {1096 .probe = qusb2_phy_probe,1097 .driver = {1098 .name = "qcom-qusb2-phy",1099 .pm = &qusb2_phy_pm_ops,1100 .of_match_table = qusb2_phy_of_match_table,1101 },1102};1103 1104module_platform_driver(qusb2_phy_driver);1105 1106MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");1107MODULE_DESCRIPTION("Qualcomm QUSB2 PHY driver");1108MODULE_LICENSE("GPL v2");1109