brintos

brintos / linux-shallow public Read only

0
0
Text · 34.2 KiB · cf12a6f Raw
1152 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2017, The Linux Foundation. All rights reserved.4 */5 6#include <linux/clk.h>7#include <linux/clk-provider.h>8#include <linux/delay.h>9#include <linux/err.h>10#include <linux/io.h>11#include <linux/iopoll.h>12#include <linux/kernel.h>13#include <linux/mfd/syscon.h>14#include <linux/module.h>15#include <linux/of.h>16#include <linux/of_address.h>17#include <linux/phy/phy.h>18#include <linux/platform_device.h>19#include <linux/regmap.h>20#include <linux/regulator/consumer.h>21#include <linux/reset.h>22#include <linux/slab.h>23#include <linux/usb/typec.h>24#include <linux/usb/typec_mux.h>25 26#include "phy-qcom-qmp-common.h"27 28#include "phy-qcom-qmp.h"29#include "phy-qcom-qmp-pcs-misc-v3.h"30 31#define PHY_INIT_COMPLETE_TIMEOUT		1000032 33/* set of registers with offsets different per-PHY */34enum qphy_reg_layout {35	/* PCS registers */36	QPHY_SW_RESET,37	QPHY_START_CTRL,38	QPHY_PCS_STATUS,39	QPHY_PCS_AUTONOMOUS_MODE_CTRL,40	QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR,41	QPHY_PCS_POWER_DOWN_CONTROL,42	/* Keep last to ensure regs_layout arrays are properly initialized */43	QPHY_LAYOUT_SIZE44};45 46static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = {47	[QPHY_SW_RESET]			= QPHY_V3_PCS_SW_RESET,48	[QPHY_START_CTRL]		= QPHY_V3_PCS_START_CONTROL,49	[QPHY_PCS_STATUS]		= QPHY_V3_PCS_PCS_STATUS,50	[QPHY_PCS_AUTONOMOUS_MODE_CTRL]	= QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL,51	[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR,52	[QPHY_PCS_POWER_DOWN_CONTROL]	= QPHY_V3_PCS_POWER_DOWN_CONTROL,53};54 55static const unsigned int qmp_v3_usb3phy_regs_layout_qcm2290[QPHY_LAYOUT_SIZE] = {56	[QPHY_SW_RESET]			= QPHY_V3_PCS_SW_RESET,57	[QPHY_START_CTRL]		= QPHY_V3_PCS_START_CONTROL,58	[QPHY_PCS_STATUS]		= QPHY_V3_PCS_PCS_STATUS,59	[QPHY_PCS_AUTONOMOUS_MODE_CTRL]	= QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL,60	[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR,61	[QPHY_PCS_POWER_DOWN_CONTROL]	= QPHY_V3_PCS_POWER_DOWN_CONTROL,62};63 64static const struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = {65	QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),66	QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),67	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),68	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06),69	QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08),70	QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),71	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),72	QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80),73	QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),74	QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),75	QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),76	QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),77	QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),78	QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),79	QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),80	QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),81	QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),82	QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),83	QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),84	QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),85	QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),86	QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34),87	QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15),88	QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04),89	QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),90	QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00),91	QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),92	QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a),93	QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),94	QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80),95	QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01),96	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),97	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31),98	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),99	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00),100	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),101	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85),102	QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07),103};104 105static const struct qmp_phy_init_tbl msm8998_usb3_tx_tbl[] = {106	QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),107	QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),108	QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16),109	QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00),110};111 112static const struct qmp_phy_init_tbl msm8998_usb3_rx_tbl[] = {113	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),114	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),115	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e),116	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18),117	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x07),118	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),119	QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43),120	QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c),121	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75),122	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00),123	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00),124	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80),125	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a),126	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06),127	QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00),128	QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03),129	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05),130};131 132static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = {133	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),134	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),135	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),136	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40),137	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),138	QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1),139	QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f),140	QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47),141	QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b),142	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f),143	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f),144	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7),145	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e),146	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65),147	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b),148	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15),149	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d),150	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15),151	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d),152	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15),153	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d),154	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15),155	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x0d),156	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15),157	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d),158	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15),159	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d),160	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02),161	QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),162	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44),163	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),164	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),165	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40),166	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00),167	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x8a),168	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75),169	QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86),170	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),171};172 173static const struct qmp_phy_init_tbl qcm2290_usb3_serdes_tbl[] = {174	QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14),175	QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),176	QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),177	QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06),178	QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x00),179	QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL2, 0x08),180	QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f),181	QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01),182	QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00),183	QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82),184	QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55),185	QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55),186	QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03),187	QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b),188	QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),189	QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),190	QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),191	QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),192	QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a),193	QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15),194	QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34),195	QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),196	QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x00),197	QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00),198	QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00),199	QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00),200	QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a),201	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01),202	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31),203	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01),204	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00),205	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00),206	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde),207	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07),208	QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f),209	QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06),210	QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_INITVAL, 0x80),211	QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x01),212};213 214static const struct qmp_phy_init_tbl qcm2290_usb3_tx_tbl[] = {215	QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),216	QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),217	QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0xc6),218	QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00),219	QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x00),220};221 222static const struct qmp_phy_init_tbl qcm2290_usb3_rx_tbl[] = {223	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),224	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80),225	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00),226	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00),227	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a),228	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06),229	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75),230	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02),231	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e),232	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18),233	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),234	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),235	QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0a),236	QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03),237	QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16),238	QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00),239	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00),240};241 242/* the only difference is QSERDES_V3_RX_UCDR_PI_CONTROLS */243static const struct qmp_phy_init_tbl sdm660_usb3_rx_tbl[] = {244	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),245	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x00),246	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00),247	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00),248	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a),249	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06),250	QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75),251	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02),252	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e),253	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18),254	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77),255	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),256	QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0a),257	QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03),258	QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16),259	QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00),260	QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00),261};262 263static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = {264	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f),265	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x17),266	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0f),267	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),268	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),269	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),270	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),271	QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x85),272	QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1),273	QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f),274	QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47),275	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75),276	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),277	QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86),278	QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),279	QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44),280	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),281	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),282	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40),283	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00),284	QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88),285};286 287struct qmp_usbc_offsets {288	u16 serdes;289	u16 pcs;290	u16 pcs_misc;291	u16 tx;292	u16 rx;293	/* for PHYs with >= 2 lanes */294	u16 tx2;295	u16 rx2;296};297 298/* struct qmp_phy_cfg - per-PHY initialization config */299struct qmp_phy_cfg {300	const struct qmp_usbc_offsets *offsets;301 302	/* Init sequence for PHY blocks - serdes, tx, rx, pcs */303	const struct qmp_phy_init_tbl *serdes_tbl;304	int serdes_tbl_num;305	const struct qmp_phy_init_tbl *tx_tbl;306	int tx_tbl_num;307	const struct qmp_phy_init_tbl *rx_tbl;308	int rx_tbl_num;309	const struct qmp_phy_init_tbl *pcs_tbl;310	int pcs_tbl_num;311 312	/* regulators to be requested */313	const char * const *vreg_list;314	int num_vregs;315 316	/* array of registers with different offsets */317	const unsigned int *regs;318};319 320struct qmp_usbc {321	struct device *dev;322 323	const struct qmp_phy_cfg *cfg;324 325	void __iomem *serdes;326	void __iomem *pcs;327	void __iomem *pcs_misc;328	void __iomem *tx;329	void __iomem *rx;330	void __iomem *tx2;331	void __iomem *rx2;332 333	struct regmap *tcsr_map;334	u32 vls_clamp_reg;335 336	struct clk *pipe_clk;337	struct clk_bulk_data *clks;338	int num_clks;339	int num_resets;340	struct reset_control_bulk_data *resets;341	struct regulator_bulk_data *vregs;342 343	struct mutex phy_mutex;344 345	enum phy_mode mode;346	unsigned int usb_init_count;347 348	struct phy *phy;349 350	struct clk_fixed_rate pipe_clk_fixed;351 352	struct typec_switch_dev *sw;353	enum typec_orientation orientation;354};355 356static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)357{358	u32 reg;359 360	reg = readl(base + offset);361	reg |= val;362	writel(reg, base + offset);363 364	/* ensure that above write is through */365	readl(base + offset);366}367 368static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val)369{370	u32 reg;371 372	reg = readl(base + offset);373	reg &= ~val;374	writel(reg, base + offset);375 376	/* ensure that above write is through */377	readl(base + offset);378}379 380/* list of clocks required by phy */381static const char * const qmp_usbc_phy_clk_l[] = {382	"aux", "cfg_ahb", "ref", "com_aux",383};384 385/* list of resets */386static const char * const usb3phy_legacy_reset_l[] = {387	"phy", "common",388};389 390static const char * const usb3phy_reset_l[] = {391	"phy_phy", "phy",392};393 394/* list of regulators */395static const char * const qmp_phy_vreg_l[] = {396	"vdda-phy", "vdda-pll",397};398 399static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = {400	.serdes		= 0x0,401	.pcs		= 0xc00,402	.pcs_misc	= 0xa00,403	.tx		= 0x200,404	.rx		= 0x400,405	.tx2		= 0x600,406	.rx2		= 0x800,407};408 409static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {410	.offsets		= &qmp_usbc_offsets_v3_qcm2290,411 412	.serdes_tbl             = msm8998_usb3_serdes_tbl,413	.serdes_tbl_num         = ARRAY_SIZE(msm8998_usb3_serdes_tbl),414	.tx_tbl                 = msm8998_usb3_tx_tbl,415	.tx_tbl_num             = ARRAY_SIZE(msm8998_usb3_tx_tbl),416	.rx_tbl                 = msm8998_usb3_rx_tbl,417	.rx_tbl_num             = ARRAY_SIZE(msm8998_usb3_rx_tbl),418	.pcs_tbl                = msm8998_usb3_pcs_tbl,419	.pcs_tbl_num            = ARRAY_SIZE(msm8998_usb3_pcs_tbl),420	.vreg_list              = qmp_phy_vreg_l,421	.num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),422	.regs                   = qmp_v3_usb3phy_regs_layout,423};424 425static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = {426	.offsets		= &qmp_usbc_offsets_v3_qcm2290,427 428	.serdes_tbl		= qcm2290_usb3_serdes_tbl,429	.serdes_tbl_num		= ARRAY_SIZE(qcm2290_usb3_serdes_tbl),430	.tx_tbl			= qcm2290_usb3_tx_tbl,431	.tx_tbl_num		= ARRAY_SIZE(qcm2290_usb3_tx_tbl),432	.rx_tbl			= qcm2290_usb3_rx_tbl,433	.rx_tbl_num		= ARRAY_SIZE(qcm2290_usb3_rx_tbl),434	.pcs_tbl		= qcm2290_usb3_pcs_tbl,435	.pcs_tbl_num		= ARRAY_SIZE(qcm2290_usb3_pcs_tbl),436	.vreg_list		= qmp_phy_vreg_l,437	.num_vregs		= ARRAY_SIZE(qmp_phy_vreg_l),438	.regs			= qmp_v3_usb3phy_regs_layout_qcm2290,439};440 441static const struct qmp_phy_cfg sdm660_usb3phy_cfg = {442	.offsets		= &qmp_usbc_offsets_v3_qcm2290,443 444	.serdes_tbl		= qcm2290_usb3_serdes_tbl,445	.serdes_tbl_num		= ARRAY_SIZE(qcm2290_usb3_serdes_tbl),446	.tx_tbl			= qcm2290_usb3_tx_tbl,447	.tx_tbl_num		= ARRAY_SIZE(qcm2290_usb3_tx_tbl),448	.rx_tbl			= sdm660_usb3_rx_tbl,449	.rx_tbl_num		= ARRAY_SIZE(sdm660_usb3_rx_tbl),450	.pcs_tbl		= qcm2290_usb3_pcs_tbl,451	.pcs_tbl_num		= ARRAY_SIZE(qcm2290_usb3_pcs_tbl),452	.vreg_list		= qmp_phy_vreg_l,453	.num_vregs		= ARRAY_SIZE(qmp_phy_vreg_l),454	.regs			= qmp_v3_usb3phy_regs_layout_qcm2290,455};456 457static int qmp_usbc_init(struct phy *phy)458{459	struct qmp_usbc *qmp = phy_get_drvdata(phy);460	const struct qmp_phy_cfg *cfg = qmp->cfg;461	void __iomem *pcs = qmp->pcs;462	u32 val = 0;463	int ret;464 465	ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);466	if (ret) {467		dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);468		return ret;469	}470 471	ret = reset_control_bulk_assert(qmp->num_resets, qmp->resets);472	if (ret) {473		dev_err(qmp->dev, "reset assert failed\n");474		goto err_disable_regulators;475	}476 477	ret = reset_control_bulk_deassert(qmp->num_resets, qmp->resets);478	if (ret) {479		dev_err(qmp->dev, "reset deassert failed\n");480		goto err_disable_regulators;481	}482 483	ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks);484	if (ret)485		goto err_assert_reset;486 487	qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN);488 489#define SW_PORTSELECT_VAL			BIT(0)490#define SW_PORTSELECT_MUX			BIT(1)491	/* Use software based port select and switch on typec orientation */492	val = SW_PORTSELECT_MUX;493	if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)494		val |= SW_PORTSELECT_VAL;495	writel(val, qmp->pcs_misc);496 497	return 0;498 499err_assert_reset:500	reset_control_bulk_assert(qmp->num_resets, qmp->resets);501err_disable_regulators:502	regulator_bulk_disable(cfg->num_vregs, qmp->vregs);503 504	return ret;505}506 507static int qmp_usbc_exit(struct phy *phy)508{509	struct qmp_usbc *qmp = phy_get_drvdata(phy);510	const struct qmp_phy_cfg *cfg = qmp->cfg;511 512	reset_control_bulk_assert(qmp->num_resets, qmp->resets);513 514	clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);515 516	regulator_bulk_disable(cfg->num_vregs, qmp->vregs);517 518	return 0;519}520 521static int qmp_usbc_power_on(struct phy *phy)522{523	struct qmp_usbc *qmp = phy_get_drvdata(phy);524	const struct qmp_phy_cfg *cfg = qmp->cfg;525	void __iomem *status;526	unsigned int val;527	int ret;528 529	qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl,530		      cfg->serdes_tbl_num);531 532	ret = clk_prepare_enable(qmp->pipe_clk);533	if (ret) {534		dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);535		return ret;536	}537 538	/* Tx, Rx, and PCS configurations */539	qmp_configure_lane(qmp->dev, qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);540	qmp_configure_lane(qmp->dev, qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1);541 542	qmp_configure_lane(qmp->dev, qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2);543	qmp_configure_lane(qmp->dev, qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2);544 545	qmp_configure(qmp->dev, qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num);546 547	/* Pull PHY out of reset state */548	qphy_clrbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);549 550	/* start SerDes and Phy-Coding-Sublayer */551	qphy_setbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START);552 553	status = qmp->pcs + cfg->regs[QPHY_PCS_STATUS];554	ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200,555				 PHY_INIT_COMPLETE_TIMEOUT);556	if (ret) {557		dev_err(qmp->dev, "phy initialization timed-out\n");558		goto err_disable_pipe_clk;559	}560 561	return 0;562 563err_disable_pipe_clk:564	clk_disable_unprepare(qmp->pipe_clk);565 566	return ret;567}568 569static int qmp_usbc_power_off(struct phy *phy)570{571	struct qmp_usbc *qmp = phy_get_drvdata(phy);572	const struct qmp_phy_cfg *cfg = qmp->cfg;573 574	clk_disable_unprepare(qmp->pipe_clk);575 576	/* PHY reset */577	qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);578 579	/* stop SerDes and Phy-Coding-Sublayer */580	qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL],581			SERDES_START | PCS_START);582 583	/* Put PHY into POWER DOWN state: active low */584	qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL],585			SW_PWRDN);586 587	return 0;588}589 590static int qmp_usbc_enable(struct phy *phy)591{592	struct qmp_usbc *qmp = phy_get_drvdata(phy);593	int ret;594 595	mutex_lock(&qmp->phy_mutex);596 597	ret = qmp_usbc_init(phy);598	if (ret)599		goto out_unlock;600 601	ret = qmp_usbc_power_on(phy);602	if (ret) {603		qmp_usbc_exit(phy);604		goto out_unlock;605	}606 607	qmp->usb_init_count++;608out_unlock:609	mutex_unlock(&qmp->phy_mutex);610 611	return ret;612}613 614static int qmp_usbc_disable(struct phy *phy)615{616	struct qmp_usbc *qmp = phy_get_drvdata(phy);617	int ret;618 619	qmp->usb_init_count--;620	ret = qmp_usbc_power_off(phy);621	if (ret)622		return ret;623	return qmp_usbc_exit(phy);624}625 626static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode)627{628	struct qmp_usbc *qmp = phy_get_drvdata(phy);629 630	qmp->mode = mode;631 632	return 0;633}634 635static const struct phy_ops qmp_usbc_phy_ops = {636	.init		= qmp_usbc_enable,637	.exit		= qmp_usbc_disable,638	.set_mode	= qmp_usbc_set_mode,639	.owner		= THIS_MODULE,640};641 642static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp)643{644	const struct qmp_phy_cfg *cfg = qmp->cfg;645	void __iomem *pcs = qmp->pcs;646	u32 intr_mask;647 648	if (qmp->mode == PHY_MODE_USB_HOST_SS ||649	    qmp->mode == PHY_MODE_USB_DEVICE_SS)650		intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN;651	else652		intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL;653 654	/* Clear any pending interrupts status */655	qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);656	/* Writing 1 followed by 0 clears the interrupt */657	qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);658 659	qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],660		     ARCVR_DTCT_EN | ALFPS_DTCT_EN | ARCVR_DTCT_EVENT_SEL);661 662	/* Enable required PHY autonomous mode interrupts */663	qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask);664 665	/* Enable i/o clamp_n for autonomous mode */666	if (qmp->tcsr_map && qmp->vls_clamp_reg)667		regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 1);668}669 670static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp)671{672	const struct qmp_phy_cfg *cfg = qmp->cfg;673	void __iomem *pcs = qmp->pcs;674 675	/* Disable i/o clamp_n on resume for normal mode */676	if (qmp->tcsr_map && qmp->vls_clamp_reg)677		regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 0);678 679	qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL],680		     ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN);681 682	qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);683	/* Writing 1 followed by 0 clears the interrupt */684	qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);685}686 687static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev)688{689	struct qmp_usbc *qmp = dev_get_drvdata(dev);690 691	dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode);692 693	if (!qmp->phy->init_count) {694		dev_vdbg(dev, "PHY not initialized, bailing out\n");695		return 0;696	}697 698	qmp_usbc_enable_autonomous_mode(qmp);699 700	clk_disable_unprepare(qmp->pipe_clk);701	clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);702 703	return 0;704}705 706static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev)707{708	struct qmp_usbc *qmp = dev_get_drvdata(dev);709	int ret = 0;710 711	dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);712 713	if (!qmp->phy->init_count) {714		dev_vdbg(dev, "PHY not initialized, bailing out\n");715		return 0;716	}717 718	ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks);719	if (ret)720		return ret;721 722	ret = clk_prepare_enable(qmp->pipe_clk);723	if (ret) {724		dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);725		clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);726		return ret;727	}728 729	qmp_usbc_disable_autonomous_mode(qmp);730 731	return 0;732}733 734static const struct dev_pm_ops qmp_usbc_pm_ops = {735	SET_RUNTIME_PM_OPS(qmp_usbc_runtime_suspend,736			   qmp_usbc_runtime_resume, NULL)737};738 739static int qmp_usbc_vreg_init(struct qmp_usbc *qmp)740{741	const struct qmp_phy_cfg *cfg = qmp->cfg;742	struct device *dev = qmp->dev;743	int num = cfg->num_vregs;744	int i;745 746	qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);747	if (!qmp->vregs)748		return -ENOMEM;749 750	for (i = 0; i < num; i++)751		qmp->vregs[i].supply = cfg->vreg_list[i];752 753	return devm_regulator_bulk_get(dev, num, qmp->vregs);754}755 756static int qmp_usbc_reset_init(struct qmp_usbc *qmp,757			      const char *const *reset_list,758			      int num_resets)759{760	struct device *dev = qmp->dev;761	int i;762	int ret;763 764	qmp->resets = devm_kcalloc(dev, num_resets,765				   sizeof(*qmp->resets), GFP_KERNEL);766	if (!qmp->resets)767		return -ENOMEM;768 769	for (i = 0; i < num_resets; i++)770		qmp->resets[i].id = reset_list[i];771 772	qmp->num_resets = num_resets;773 774	ret = devm_reset_control_bulk_get_exclusive(dev, num_resets, qmp->resets);775	if (ret)776		return dev_err_probe(dev, ret, "failed to get resets\n");777 778	return 0;779}780 781static int qmp_usbc_clk_init(struct qmp_usbc *qmp)782{783	struct device *dev = qmp->dev;784	int num = ARRAY_SIZE(qmp_usbc_phy_clk_l);785	int i;786 787	qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL);788	if (!qmp->clks)789		return -ENOMEM;790 791	for (i = 0; i < num; i++)792		qmp->clks[i].id = qmp_usbc_phy_clk_l[i];793 794	qmp->num_clks = num;795 796	return devm_clk_bulk_get_optional(dev, num, qmp->clks);797}798 799static void phy_clk_release_provider(void *res)800{801	of_clk_del_provider(res);802}803 804/*805 * Register a fixed rate pipe clock.806 *807 * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate808 * controls it. The <s>_pipe_clk coming out of the GCC is requested809 * by the PHY driver for its operations.810 * We register the <s>_pipe_clksrc here. The gcc driver takes care811 * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.812 * Below picture shows this relationship.813 *814 *         +---------------+815 *         |   PHY block   |<<---------------------------------------+816 *         |               |                                         |817 *         |   +-------+   |                   +-----+               |818 *   I/P---^-->|  PLL  |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+819 *    clk  |   +-------+   |                   +-----+820 *         +---------------+821 */822static int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np)823{824	struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed;825	struct clk_init_data init = { };826	int ret;827 828	ret = of_property_read_string(np, "clock-output-names", &init.name);829	if (ret) {830		dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np);831		return ret;832	}833 834	init.ops = &clk_fixed_rate_ops;835 836	/* controllers using QMP phys use 125MHz pipe clock interface */837	fixed->fixed_rate = 125000000;838	fixed->hw.init = &init;839 840	ret = devm_clk_hw_register(qmp->dev, &fixed->hw);841	if (ret)842		return ret;843 844	ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw);845	if (ret)846		return ret;847 848	/*849	 * Roll a devm action because the clock provider is the child node, but850	 * the child node is not actually a device.851	 */852	return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np);853}854 855#if IS_ENABLED(CONFIG_TYPEC)856static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw,857				      enum typec_orientation orientation)858{859	struct qmp_usbc *qmp = typec_switch_get_drvdata(sw);860 861	if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE)862		return 0;863 864	mutex_lock(&qmp->phy_mutex);865	qmp->orientation = orientation;866 867	if (qmp->usb_init_count) {868		qmp_usbc_power_off(qmp->phy);869		qmp_usbc_exit(qmp->phy);870 871		qmp_usbc_init(qmp->phy);872		qmp_usbc_power_on(qmp->phy);873	}874 875	mutex_unlock(&qmp->phy_mutex);876 877	return 0;878}879 880static void qmp_usbc_typec_unregister(void *data)881{882	struct qmp_usbc *qmp = data;883 884	typec_switch_unregister(qmp->sw);885}886 887static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)888{889	struct typec_switch_desc sw_desc = {};890	struct device *dev = qmp->dev;891 892	sw_desc.drvdata = qmp;893	sw_desc.fwnode = dev->fwnode;894	sw_desc.set = qmp_usbc_typec_switch_set;895	qmp->sw = typec_switch_register(dev, &sw_desc);896	if (IS_ERR(qmp->sw)) {897		dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw);898		return PTR_ERR(qmp->sw);899	}900 901	return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp);902}903#else904static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp)905{906	return 0;907}908#endif909 910static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np)911{912	struct platform_device *pdev = to_platform_device(qmp->dev);913	struct device *dev = qmp->dev;914	int ret;915 916	qmp->serdes = devm_platform_ioremap_resource(pdev, 0);917	if (IS_ERR(qmp->serdes))918		return PTR_ERR(qmp->serdes);919 920	/*921	 * Get memory resources for the PHY:922	 * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2.923	 * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5924	 * For single lane PHYs: pcs_misc (optional) -> 3.925	 */926	qmp->tx = devm_of_iomap(dev, np, 0, NULL);927	if (IS_ERR(qmp->tx))928		return PTR_ERR(qmp->tx);929 930	qmp->rx = devm_of_iomap(dev, np, 1, NULL);931	if (IS_ERR(qmp->rx))932		return PTR_ERR(qmp->rx);933 934	qmp->pcs = devm_of_iomap(dev, np, 2, NULL);935	if (IS_ERR(qmp->pcs))936		return PTR_ERR(qmp->pcs);937 938	qmp->tx2 = devm_of_iomap(dev, np, 3, NULL);939	if (IS_ERR(qmp->tx2))940		return PTR_ERR(qmp->tx2);941 942	qmp->rx2 = devm_of_iomap(dev, np, 4, NULL);943	if (IS_ERR(qmp->rx2))944		return PTR_ERR(qmp->rx2);945 946	qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL);947	if (IS_ERR(qmp->pcs_misc)) {948		dev_vdbg(dev, "PHY pcs_misc-reg not used\n");949		qmp->pcs_misc = NULL;950	}951 952	qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL);953	if (IS_ERR(qmp->pipe_clk)) {954		return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),955				     "failed to get pipe clock\n");956	}957 958	ret = devm_clk_bulk_get_all(qmp->dev, &qmp->clks);959	if (ret < 0)960		return ret;961 962	qmp->num_clks = ret;963 964	ret = qmp_usbc_reset_init(qmp, usb3phy_legacy_reset_l,965				 ARRAY_SIZE(usb3phy_legacy_reset_l));966	if (ret)967		return ret;968 969	return 0;970}971 972static int qmp_usbc_parse_dt(struct qmp_usbc *qmp)973{974	struct platform_device *pdev = to_platform_device(qmp->dev);975	const struct qmp_phy_cfg *cfg = qmp->cfg;976	const struct qmp_usbc_offsets *offs = cfg->offsets;977	struct device *dev = qmp->dev;978	void __iomem *base;979	int ret;980 981	if (!offs)982		return -EINVAL;983 984	base = devm_platform_ioremap_resource(pdev, 0);985	if (IS_ERR(base))986		return PTR_ERR(base);987 988	qmp->serdes = base + offs->serdes;989	qmp->pcs = base + offs->pcs;990	if (offs->pcs_misc)991		qmp->pcs_misc = base + offs->pcs_misc;992	qmp->tx = base + offs->tx;993	qmp->rx = base + offs->rx;994 995	qmp->tx2 = base + offs->tx2;996	qmp->rx2 = base + offs->rx2;997 998	ret = qmp_usbc_clk_init(qmp);999	if (ret)1000		return ret;1001 1002	qmp->pipe_clk = devm_clk_get(dev, "pipe");1003	if (IS_ERR(qmp->pipe_clk)) {1004		return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),1005				     "failed to get pipe clock\n");1006	}1007 1008	ret = qmp_usbc_reset_init(qmp, usb3phy_reset_l,1009				 ARRAY_SIZE(usb3phy_reset_l));1010	if (ret)1011		return ret;1012 1013	return 0;1014}1015 1016static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp)1017{1018	struct of_phandle_args tcsr_args;1019	struct device *dev = qmp->dev;1020	int ret;1021 1022	/*  for backwards compatibility ignore if there is no property */1023	ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", 1, 0,1024					       &tcsr_args);1025	if (ret == -ENOENT)1026		return 0;1027	else if (ret < 0)1028		return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n");1029 1030	qmp->tcsr_map = syscon_node_to_regmap(tcsr_args.np);1031	of_node_put(tcsr_args.np);1032	if (IS_ERR(qmp->tcsr_map))1033		return PTR_ERR(qmp->tcsr_map);1034 1035	qmp->vls_clamp_reg = tcsr_args.args[0];1036 1037	return 0;1038}1039 1040static int qmp_usbc_probe(struct platform_device *pdev)1041{1042	struct device *dev = &pdev->dev;1043	struct phy_provider *phy_provider;1044	struct device_node *np;1045	struct qmp_usbc *qmp;1046	int ret;1047 1048	qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL);1049	if (!qmp)1050		return -ENOMEM;1051 1052	qmp->dev = dev;1053	dev_set_drvdata(dev, qmp);1054 1055	qmp->orientation = TYPEC_ORIENTATION_NORMAL;1056 1057	qmp->cfg = of_device_get_match_data(dev);1058	if (!qmp->cfg)1059		return -EINVAL;1060 1061	mutex_init(&qmp->phy_mutex);1062 1063	ret = qmp_usbc_vreg_init(qmp);1064	if (ret)1065		return ret;1066 1067	ret = qmp_usbc_typec_switch_register(qmp);1068	if (ret)1069		return ret;1070 1071	ret = qmp_usbc_parse_vls_clamp(qmp);1072	if (ret)1073		return ret;1074 1075	/* Check for legacy binding with child node. */1076	np = of_get_child_by_name(dev->of_node, "phy");1077	if (np) {1078		ret = qmp_usbc_parse_dt_legacy(qmp, np);1079	} else {1080		np = of_node_get(dev->of_node);1081		ret = qmp_usbc_parse_dt(qmp);1082	}1083	if (ret)1084		goto err_node_put;1085 1086	pm_runtime_set_active(dev);1087	ret = devm_pm_runtime_enable(dev);1088	if (ret)1089		goto err_node_put;1090	/*1091	 * Prevent runtime pm from being ON by default. Users can enable1092	 * it using power/control in sysfs.1093	 */1094	pm_runtime_forbid(dev);1095 1096	ret = phy_pipe_clk_register(qmp, np);1097	if (ret)1098		goto err_node_put;1099 1100	qmp->phy = devm_phy_create(dev, np, &qmp_usbc_phy_ops);1101	if (IS_ERR(qmp->phy)) {1102		ret = PTR_ERR(qmp->phy);1103		dev_err(dev, "failed to create PHY: %d\n", ret);1104		goto err_node_put;1105	}1106 1107	phy_set_drvdata(qmp->phy, qmp);1108 1109	of_node_put(np);1110 1111	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);1112 1113	return PTR_ERR_OR_ZERO(phy_provider);1114 1115err_node_put:1116	of_node_put(np);1117	return ret;1118}1119 1120static const struct of_device_id qmp_usbc_of_match_table[] = {1121	{1122		.compatible = "qcom,msm8998-qmp-usb3-phy",1123		.data = &msm8998_usb3phy_cfg,1124	}, {1125		.compatible = "qcom,qcm2290-qmp-usb3-phy",1126		.data = &qcm2290_usb3phy_cfg,1127	}, {1128		.compatible = "qcom,sdm660-qmp-usb3-phy",1129		.data = &sdm660_usb3phy_cfg,1130	}, {1131		.compatible = "qcom,sm6115-qmp-usb3-phy",1132		.data = &qcm2290_usb3phy_cfg,1133	},1134	{ },1135};1136MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table);1137 1138static struct platform_driver qmp_usbc_driver = {1139	.probe		= qmp_usbc_probe,1140	.driver = {1141		.name	= "qcom-qmp-usbc-phy",1142		.pm	= &qmp_usbc_pm_ops,1143		.of_match_table = qmp_usbc_of_match_table,1144	},1145};1146 1147module_platform_driver(qmp_usbc_driver);1148 1149MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");1150MODULE_DESCRIPTION("Qualcomm QMP USB-C PHY driver");1151MODULE_LICENSE("GPL");1152