brintos

brintos / linux-shallow public Read only

0
0
Text · 30.2 KiB · c52655a Raw
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