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