FILE
wcd939x-usbss.c
File preview with syntax highlighting.
linux-6.19.14/drivers/usb/typec/mux/wcd939x-usbss.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * Copyright (C) 2023 Linaro Ltd. 5 */ 6 7#include <linux/bits.h> 8#include <linux/i2c.h> 9#include <linux/kernel.h> 10#include <linux/module.h> 11#include <linux/mutex.h> 12#include <linux/regmap.h> 13#include <linux/bitfield.h> 14#include <linux/gpio/consumer.h> 15#include <linux/usb/typec_dp.h> 16#include <linux/usb/typec_mux.h> 17 18#define WCD_USBSS_PMP_OUT1 0x2 19 20#define WCD_USBSS_DP_DN_MISC1 0x20 21 22#define WCD_USBSS_DP_DN_MISC1_DP_PCOMP_2X_DYN_BST_ON_EN BIT(3) 23#define WCD_USBSS_DP_DN_MISC1_DN_PCOMP_2X_DYN_BST_ON_EN BIT(0) 24 25#define WCD_USBSS_MG1_EN 0x24 26 27#define WCD_USBSS_MG1_EN_CT_SNS_EN BIT(1) 28 29#define WCD_USBSS_MG1_BIAS 0x25 30 31#define WCD_USBSS_MG1_BIAS_PCOMP_DYN_BST_EN BIT(3) 32 33#define WCD_USBSS_MG1_MISC 0x27 34 35#define WCD_USBSS_MG1_MISC_PCOMP_2X_DYN_BST_ON_EN BIT(5) 36 37#define WCD_USBSS_MG2_EN 0x28 38 39#define WCD_USBSS_MG2_EN_CT_SNS_EN BIT(1) 40 41#define WCD_USBSS_MG2_BIAS 0x29 42 43#define WCD_USBSS_MG2_BIAS_PCOMP_DYN_BST_EN BIT(3) 44 45#define WCD_USBSS_MG2_MISC 0x30 46 47#define WCD_USBSS_MG2_MISC_PCOMP_2X_DYN_BST_ON_EN BIT(5) 48 49#define WCD_USBSS_DISP_AUXP_THRESH 0x80 50 51#define WCD_USBSS_DISP_AUXP_THRESH_DISP_AUXP_OVPON_CM GENMASK(7, 5) 52 53#define WCD_USBSS_DISP_AUXP_CTL 0x81 54 55#define WCD_USBSS_DISP_AUXP_CTL_LK_CANCEL_TRK_COEFF GENMASK(2, 0) 56 57#define WCD_USBSS_CPLDO_CTL2 0xa1 58 59#define WCD_USBSS_SWITCH_SETTINGS_ENABLE 0x403 60 61#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DEVICE_ENABLE BIT(7) 62#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXP_TO_MGX_SWITCHES BIT(6) 63#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXM_TO_MGX_SWITCHES BIT(5) 64#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES BIT(4) 65#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES BIT(3) 66#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_SENSE_SWITCHES BIT(2) 67#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_MIC_SWITCHES BIT(1) 68#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_AGND_SWITCHES BIT(0) 69 70#define WCD_USBSS_SWITCH_SELECT0 0x404 71 72#define WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES BIT(7) /* 1-> MG2 */ 73#define WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES BIT(6) /* 1-> MG2 */ 74#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES GENMASK(5, 4) 75#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES GENMASK(3, 2) 76#define WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES BIT(1) /* 1-> SBU2 */ 77#define WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES BIT(0) /* 1-> MG2 */ 78 79#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_L 0 80#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_DN 1 81#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_DN2 2 82 83#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_R 0 84#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_DP 1 85#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_DR2 2 86 87#define WCD_USBSS_SWITCH_SELECT1 0x405 88 89#define WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES BIT(0) /* 1-> MG2 */ 90 91#define WCD_USBSS_DELAY_R_SW 0x40d 92#define WCD_USBSS_DELAY_MIC_SW 0x40e 93#define WCD_USBSS_DELAY_SENSE_SW 0x40f 94#define WCD_USBSS_DELAY_GND_SW 0x410 95#define WCD_USBSS_DELAY_L_SW 0x411 96 97#define WCD_USBSS_FUNCTION_ENABLE 0x413 98 99#define WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT GENMASK(1, 0) 100 101#define WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT_MANUAL 1 102#define WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT_AUDIO_FSM 2 103 104#define WCD_USBSS_EQUALIZER1 0x415 105 106#define WCD_USBSS_EQUALIZER1_EQ_EN BIT(7) 107#define WCD_USBSS_EQUALIZER1_BW_SETTINGS GENMASK(6, 3) 108 109#define WCD_USBSS_USB_SS_CNTL 0x419 110 111#define WCD_USBSS_USB_SS_CNTL_STANDBY_STATE BIT(4) 112#define WCD_USBSS_USB_SS_CNTL_RCO_EN BIT(3) 113#define WCD_USBSS_USB_SS_CNTL_USB_SS_MODE GENMASK(2, 0) 114 115#define WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_AATC 2 116#define WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_USB 5 117 118#define WCD_USBSS_AUDIO_FSM_START 0x433 119 120#define WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG BIT(0) 121 122#define WCD_USBSS_RATIO_SPKR_REXT_L_LSB 0x461 123#define WCD_USBSS_RATIO_SPKR_REXT_L_MSB 0x462 124#define WCD_USBSS_RATIO_SPKR_REXT_R_LSB 0x463 125#define WCD_USBSS_RATIO_SPKR_REXT_R_MSB 0x464 126#define WCD_USBSS_AUD_COEF_L_K0_0 0x475 127#define WCD_USBSS_AUD_COEF_L_K0_1 0x476 128#define WCD_USBSS_AUD_COEF_L_K0_2 0x477 129#define WCD_USBSS_AUD_COEF_L_K1_0 0x478 130#define WCD_USBSS_AUD_COEF_L_K1_1 0x479 131#define WCD_USBSS_AUD_COEF_L_K2_0 0x47a 132#define WCD_USBSS_AUD_COEF_L_K2_1 0x47b 133#define WCD_USBSS_AUD_COEF_L_K3_0 0x47c 134#define WCD_USBSS_AUD_COEF_L_K3_1 0x47d 135#define WCD_USBSS_AUD_COEF_L_K4_0 0x47e 136#define WCD_USBSS_AUD_COEF_L_K4_1 0x47f 137#define WCD_USBSS_AUD_COEF_L_K5_0 0x480 138#define WCD_USBSS_AUD_COEF_L_K5_1 0x481 139#define WCD_USBSS_AUD_COEF_R_K0_0 0x482 140#define WCD_USBSS_AUD_COEF_R_K0_1 0x483 141#define WCD_USBSS_AUD_COEF_R_K0_2 0x484 142#define WCD_USBSS_AUD_COEF_R_K1_0 0x485 143#define WCD_USBSS_AUD_COEF_R_K1_1 0x486 144#define WCD_USBSS_AUD_COEF_R_K2_0 0x487 145#define WCD_USBSS_AUD_COEF_R_K2_1 0x488 146#define WCD_USBSS_AUD_COEF_R_K3_0 0x489 147#define WCD_USBSS_AUD_COEF_R_K3_1 0x48a 148#define WCD_USBSS_AUD_COEF_R_K4_0 0x48b 149#define WCD_USBSS_AUD_COEF_R_K4_1 0x48c 150#define WCD_USBSS_AUD_COEF_R_K5_0 0x48d 151#define WCD_USBSS_AUD_COEF_R_K5_1 0x48e 152#define WCD_USBSS_GND_COEF_L_K0_0 0x48f 153#define WCD_USBSS_GND_COEF_L_K0_1 0x490 154#define WCD_USBSS_GND_COEF_L_K0_2 0x491 155#define WCD_USBSS_GND_COEF_L_K1_0 0x492 156#define WCD_USBSS_GND_COEF_L_K1_1 0x493 157#define WCD_USBSS_GND_COEF_L_K2_0 0x494 158#define WCD_USBSS_GND_COEF_L_K2_1 0x495 159#define WCD_USBSS_GND_COEF_L_K3_0 0x496 160#define WCD_USBSS_GND_COEF_L_K3_1 0x497 161#define WCD_USBSS_GND_COEF_L_K4_0 0x498 162#define WCD_USBSS_GND_COEF_L_K4_1 0x499 163#define WCD_USBSS_GND_COEF_L_K5_0 0x49a 164#define WCD_USBSS_GND_COEF_L_K5_1 0x49b 165#define WCD_USBSS_GND_COEF_R_K0_0 0x49c 166#define WCD_USBSS_GND_COEF_R_K0_1 0x49d 167#define WCD_USBSS_GND_COEF_R_K0_2 0x49e 168#define WCD_USBSS_GND_COEF_R_K1_0 0x49f 169#define WCD_USBSS_GND_COEF_R_K1_1 0x4a0 170#define WCD_USBSS_GND_COEF_R_K2_0 0x4a1 171#define WCD_USBSS_GND_COEF_R_K2_1 0x4a2 172#define WCD_USBSS_GND_COEF_R_K3_0 0x4a3 173#define WCD_USBSS_GND_COEF_R_K3_1 0x4a4 174#define WCD_USBSS_GND_COEF_R_K4_0 0x4a5 175#define WCD_USBSS_GND_COEF_R_K4_1 0x4a6 176#define WCD_USBSS_GND_COEF_R_K5_0 0x4a7 177#define WCD_USBSS_GND_COEF_R_K5_1 0x4a8 178 179#define WCD_USBSS_MAX_REGISTER 0x4c1 180 181struct wcd939x_usbss { 182 struct i2c_client *client; 183 struct gpio_desc *reset_gpio; 184 struct regulator *vdd_supply; 185 186 /* used to serialize concurrent change requests */ 187 struct mutex lock; 188 189 struct typec_switch_dev *sw; 190 struct typec_mux_dev *mux; 191 192 struct regmap *regmap; 193 194 struct typec_mux *codec; 195 struct typec_switch *codec_switch; 196 197 enum typec_orientation orientation; 198 unsigned long mode; 199 unsigned int svid; 200}; 201 202static const struct regmap_range_cfg wcd939x_usbss_ranges[] = { 203 { 204 .range_min = 0, 205 .range_max = WCD_USBSS_MAX_REGISTER, 206 .selector_reg = 0x0, 207 .selector_mask = 0xff, 208 .selector_shift = 0, 209 .window_start = 0, 210 .window_len = 0x100, 211 }, 212}; 213 214static const struct regmap_config wcd939x_usbss_regmap_config = { 215 .reg_bits = 8, 216 .val_bits = 8, 217 .max_register = WCD_USBSS_MAX_REGISTER, 218 .ranges = wcd939x_usbss_ranges, 219 .num_ranges = ARRAY_SIZE(wcd939x_usbss_ranges), 220}; 221 222/* Linearlizer coefficients for 32ohm load */ 223static const struct { 224 unsigned int offset; 225 unsigned int mask; 226 unsigned int value; 227} wcd939x_usbss_coeff_init[] = { 228 { WCD_USBSS_AUD_COEF_L_K5_0, GENMASK(7, 0), 0x39 }, 229 { WCD_USBSS_AUD_COEF_R_K5_0, GENMASK(7, 0), 0x39 }, 230 { WCD_USBSS_GND_COEF_L_K2_0, GENMASK(7, 0), 0xe8 }, 231 { WCD_USBSS_GND_COEF_L_K4_0, GENMASK(7, 0), 0x73 }, 232 { WCD_USBSS_GND_COEF_R_K2_0, GENMASK(7, 0), 0xe8 }, 233 { WCD_USBSS_GND_COEF_R_K4_0, GENMASK(7, 0), 0x73 }, 234 { WCD_USBSS_RATIO_SPKR_REXT_L_LSB, GENMASK(7, 0), 0x00 }, 235 { WCD_USBSS_RATIO_SPKR_REXT_L_MSB, GENMASK(6, 0), 0x04 }, 236 { WCD_USBSS_RATIO_SPKR_REXT_R_LSB, GENMASK(7, 0), 0x00 }, 237 { WCD_USBSS_RATIO_SPKR_REXT_R_MSB, GENMASK(6, 0), 0x04 }, 238}; 239 240static int wcd939x_usbss_set(struct wcd939x_usbss *usbss) 241{ 242 bool reverse = (usbss->orientation == TYPEC_ORIENTATION_REVERSE); 243 bool enable_audio = false; 244 bool enable_usb = false; 245 bool enable_dp = false; 246 int ret; 247 248 /* USB Mode */ 249 if (usbss->mode < TYPEC_STATE_MODAL || 250 (!usbss->svid && (usbss->mode == TYPEC_MODE_USB2 || 251 usbss->mode == TYPEC_MODE_USB3))) { 252 enable_usb = true; 253 } else if (usbss->svid) { 254 switch (usbss->mode) { 255 /* DP Only */ 256 case TYPEC_DP_STATE_C: 257 case TYPEC_DP_STATE_E: 258 enable_dp = true; 259 break; 260 261 /* DP + USB */ 262 case TYPEC_DP_STATE_D: 263 case TYPEC_DP_STATE_F: 264 enable_usb = true; 265 enable_dp = true; 266 break; 267 268 default: 269 return -EOPNOTSUPP; 270 } 271 } else if (usbss->mode == TYPEC_MODE_AUDIO) { 272 enable_audio = true; 273 } else { 274 return -EOPNOTSUPP; 275 } 276 277 /* Disable all switches */ 278 ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, 279 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXP_TO_MGX_SWITCHES | 280 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXM_TO_MGX_SWITCHES | 281 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES | 282 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES | 283 WCD_USBSS_SWITCH_SETTINGS_ENABLE_SENSE_SWITCHES | 284 WCD_USBSS_SWITCH_SETTINGS_ENABLE_MIC_SWITCHES | 285 WCD_USBSS_SWITCH_SETTINGS_ENABLE_AGND_SWITCHES); 286 if (ret) 287 return ret; 288 289 /* Clear switches */ 290 ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, 291 WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES | 292 WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES | 293 WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES | 294 WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES | 295 WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES | 296 WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES); 297 if (ret) 298 return ret; 299 300 ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT1, 301 WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES); 302 if (ret) 303 return ret; 304 305 /* Enable OVP_MG1_BIAS PCOMP_DYN_BST_EN */ 306 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG1_BIAS, 307 WCD_USBSS_MG1_BIAS_PCOMP_DYN_BST_EN); 308 if (ret) 309 return ret; 310 311 /* Enable OVP_MG2_BIAS PCOMP_DYN_BST_EN */ 312 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG2_BIAS, 313 WCD_USBSS_MG2_BIAS_PCOMP_DYN_BST_EN); 314 if (ret) 315 return ret; 316 317 /* Disable Equalizer in safe mode */ 318 ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_EQUALIZER1, 319 WCD_USBSS_EQUALIZER1_EQ_EN); 320 if (ret) 321 return ret; 322 323 /* Start FSM with all disabled, force write */ 324 ret = regmap_write_bits(usbss->regmap, WCD_USBSS_AUDIO_FSM_START, 325 WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG, 326 WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG); 327 328 /* 35us to allow the SBU switch to turn off */ 329 usleep_range(35, 1000); 330 331 /* Setup Audio Accessory mux/switch */ 332 if (enable_audio) { 333 int i; 334 335 /* 336 * AATC switch configuration: 337 * "Normal": 338 * - R: DNR 339 * - L: DNL 340 * - Sense: GSBU2 341 * - Mic: MG1 342 * - AGND: MG2 343 * "Swapped": 344 * - R: DNR 345 * - L: DNL 346 * - Sense: GSBU1 347 * - Mic: MG2 348 * - AGND: MG1 349 * Swapped information is given by the codec MBHC logic 350 */ 351 352 /* Set AATC mode */ 353 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, 354 WCD_USBSS_USB_SS_CNTL_USB_SS_MODE, 355 FIELD_PREP(WCD_USBSS_USB_SS_CNTL_USB_SS_MODE, 356 WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_AATC)); 357 if (ret) 358 return ret; 359 360 /* Select L for DNL_SWITCHES and R for DPR_SWITCHES */ 361 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, 362 WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES | 363 WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES, 364 FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES, 365 WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_L) | 366 FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES, 367 WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_R)); 368 if (ret) 369 return ret; 370 371 if (reverse) 372 /* Select MG2 for MIC, SBU1 for Sense */ 373 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, 374 WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES, 375 WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES); 376 else 377 /* Select MG1 for MIC, SBU2 for Sense */ 378 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, 379 WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES, 380 WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES); 381 if (ret) 382 return ret; 383 384 if (reverse) 385 /* Disable OVP_MG1_BIAS PCOMP_DYN_BST_EN */ 386 ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_MG1_BIAS, 387 WCD_USBSS_MG1_BIAS_PCOMP_DYN_BST_EN); 388 else 389 /* Disable OVP_MG2_BIAS PCOMP_DYN_BST_EN */ 390 ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_MG2_BIAS, 391 WCD_USBSS_MG2_BIAS_PCOMP_DYN_BST_EN); 392 if (ret) 393 return ret; 394 395 /* Enable SENSE, MIC switches */ 396 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, 397 WCD_USBSS_SWITCH_SETTINGS_ENABLE_SENSE_SWITCHES | 398 WCD_USBSS_SWITCH_SETTINGS_ENABLE_MIC_SWITCHES); 399 if (ret) 400 return ret; 401 402 if (reverse) 403 /* Select MG1 for AGND_SWITCHES */ 404 ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT1, 405 WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES); 406 else 407 /* Select MG2 for AGND_SWITCHES */ 408 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT1, 409 WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES); 410 if (ret) 411 return ret; 412 413 /* Enable AGND switches */ 414 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, 415 WCD_USBSS_SWITCH_SETTINGS_ENABLE_AGND_SWITCHES); 416 if (ret) 417 return ret; 418 419 /* Enable DPR, DNL switches */ 420 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, 421 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES | 422 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES); 423 if (ret) 424 return ret; 425 426 /* Setup FSM delays */ 427 ret = regmap_write(usbss->regmap, WCD_USBSS_DELAY_L_SW, 0x02); 428 if (ret) 429 return ret; 430 431 ret = regmap_write(usbss->regmap, WCD_USBSS_DELAY_R_SW, 0x02); 432 if (ret) 433 return ret; 434 435 ret = regmap_write(usbss->regmap, WCD_USBSS_DELAY_MIC_SW, 0x01); 436 if (ret) 437 return ret; 438 439 /* Start FSM, force write */ 440 ret = regmap_write_bits(usbss->regmap, WCD_USBSS_AUDIO_FSM_START, 441 WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG, 442 WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG); 443 if (ret) 444 return ret; 445 446 /* Default Linearlizer coefficients */ 447 for (i = 0; i < ARRAY_SIZE(wcd939x_usbss_coeff_init); ++i) 448 regmap_update_bits(usbss->regmap, 449 wcd939x_usbss_coeff_init[i].offset, 450 wcd939x_usbss_coeff_init[i].mask, 451 wcd939x_usbss_coeff_init[i].value); 452 453 return 0; 454 } 455 456 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, 457 WCD_USBSS_USB_SS_CNTL_USB_SS_MODE, 458 FIELD_PREP(WCD_USBSS_USB_SS_CNTL_USB_SS_MODE, 459 WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_USB)); 460 if (ret) 461 return ret; 462 463 /* Enable USB muxes */ 464 if (enable_usb) { 465 /* Do not enable Equalizer in safe mode */ 466 if (usbss->mode != TYPEC_STATE_SAFE) { 467 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_EQUALIZER1, 468 WCD_USBSS_EQUALIZER1_EQ_EN); 469 if (ret) 470 return ret; 471 } 472 473 /* Select DN for DNL_SWITCHES and DP for DPR_SWITCHES */ 474 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, 475 WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES | 476 WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES, 477 FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES, 478 WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_DN) | 479 FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES, 480 WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_DP)); 481 if (ret) 482 return ret; 483 484 /* Enable DNL_SWITCHES and DPR_SWITCHES */ 485 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, 486 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES | 487 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES); 488 if (ret) 489 return ret; 490 } 491 492 /* Enable DP AUX muxes */ 493 if (enable_dp) { 494 /* Update Leakage Canceller Coefficient for AUXP pins */ 495 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_DISP_AUXP_CTL, 496 WCD_USBSS_DISP_AUXP_CTL_LK_CANCEL_TRK_COEFF, 497 FIELD_PREP(WCD_USBSS_DISP_AUXP_CTL_LK_CANCEL_TRK_COEFF, 498 5)); 499 if (ret) 500 return ret; 501 502 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_DISP_AUXP_THRESH, 503 WCD_USBSS_DISP_AUXP_THRESH_DISP_AUXP_OVPON_CM); 504 if (ret) 505 return ret; 506 507 if (reverse) 508 /* Select MG2 for AUXP and MG1 for AUXM */ 509 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, 510 WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES | 511 WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES, 512 WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES); 513 else 514 /* Select MG1 for AUXP and MG2 for AUXM */ 515 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0, 516 WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES | 517 WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES, 518 WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES); 519 if (ret) 520 return ret; 521 522 /* Enable DP_AUXP_TO_MGX and DP_AUXM_TO_MGX switches */ 523 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, 524 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXP_TO_MGX_SWITCHES | 525 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXM_TO_MGX_SWITCHES); 526 527 /* 15us to allow the SBU switch to turn on again */ 528 usleep_range(15, 1000); 529 } 530 531 return 0; 532} 533 534static int wcd939x_usbss_switch_set(struct typec_switch_dev *sw, 535 enum typec_orientation orientation) 536{ 537 struct wcd939x_usbss *usbss = typec_switch_get_drvdata(sw); 538 int ret = 0; 539 540 mutex_lock(&usbss->lock); 541 542 if (usbss->orientation != orientation) { 543 usbss->orientation = orientation; 544 545 ret = wcd939x_usbss_set(usbss); 546 } 547 548 mutex_unlock(&usbss->lock); 549 550 if (ret) 551 return ret; 552 553 /* Report orientation to codec after switch has been done */ 554 return typec_switch_set(usbss->codec_switch, orientation); 555} 556 557static int wcd939x_usbss_mux_set(struct typec_mux_dev *mux, 558 struct typec_mux_state *state) 559{ 560 struct wcd939x_usbss *usbss = typec_mux_get_drvdata(mux); 561 int ret = 0; 562 563 mutex_lock(&usbss->lock); 564 565 if (usbss->mode != state->mode) { 566 usbss->mode = state->mode; 567 568 if (state->alt) 569 usbss->svid = state->alt->svid; 570 else 571 usbss->svid = 0; // No SVID 572 573 ret = wcd939x_usbss_set(usbss); 574 } 575 576 mutex_unlock(&usbss->lock); 577 578 if (ret) 579 return ret; 580 581 /* Report event to codec after switch has been done */ 582 return typec_mux_set(usbss->codec, state); 583} 584 585static int wcd939x_usbss_probe(struct i2c_client *client) 586{ 587 struct device *dev = &client->dev; 588 struct typec_switch_desc sw_desc = { }; 589 struct typec_mux_desc mux_desc = { }; 590 struct wcd939x_usbss *usbss; 591 int ret; 592 593 usbss = devm_kzalloc(dev, sizeof(*usbss), GFP_KERNEL); 594 if (!usbss) 595 return -ENOMEM; 596 597 usbss->client = client; 598 mutex_init(&usbss->lock); 599 600 usbss->regmap = devm_regmap_init_i2c(client, &wcd939x_usbss_regmap_config); 601 if (IS_ERR(usbss->regmap)) 602 return dev_err_probe(dev, PTR_ERR(usbss->regmap), "failed to initialize regmap\n"); 603 604 usbss->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 605 if (IS_ERR(usbss->reset_gpio)) 606 return dev_err_probe(dev, PTR_ERR(usbss->reset_gpio), 607 "unable to acquire reset gpio\n"); 608 609 usbss->vdd_supply = devm_regulator_get_optional(dev, "vdd"); 610 if (IS_ERR(usbss->vdd_supply)) 611 return PTR_ERR(usbss->vdd_supply); 612 613 /* Get Codec's MUX & Switch devices */ 614 usbss->codec = fwnode_typec_mux_get(dev->fwnode); 615 if (IS_ERR(usbss->codec)) 616 return dev_err_probe(dev, PTR_ERR(usbss->codec), 617 "failed to acquire codec mode-switch\n"); 618 619 usbss->codec_switch = fwnode_typec_switch_get(dev->fwnode); 620 if (IS_ERR(usbss->codec_switch)) { 621 ret = dev_err_probe(dev, PTR_ERR(usbss->codec_switch), 622 "failed to acquire codec orientation-switch\n"); 623 goto err_mux_put; 624 } 625 626 usbss->mode = TYPEC_STATE_SAFE; 627 usbss->orientation = TYPEC_ORIENTATION_NONE; 628 629 gpiod_set_value(usbss->reset_gpio, 1); 630 631 ret = regulator_enable(usbss->vdd_supply); 632 if (ret) { 633 dev_err(dev, "Failed to enable vdd: %d\n", ret); 634 goto err_mux_switch; 635 } 636 637 msleep(20); 638 639 gpiod_set_value(usbss->reset_gpio, 0); 640 641 msleep(20); 642 643 /* Disable standby */ 644 ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, 645 WCD_USBSS_USB_SS_CNTL_STANDBY_STATE); 646 if (ret) 647 goto err_regulator_disable; 648 649 /* Set manual mode by default */ 650 ret = regmap_update_bits(usbss->regmap, WCD_USBSS_FUNCTION_ENABLE, 651 WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT, 652 FIELD_PREP(WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT, 653 WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT_MANUAL)); 654 if (ret) 655 goto err_regulator_disable; 656 657 /* Enable dynamic boosting for DP and DN */ 658 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_DP_DN_MISC1, 659 WCD_USBSS_DP_DN_MISC1_DP_PCOMP_2X_DYN_BST_ON_EN | 660 WCD_USBSS_DP_DN_MISC1_DN_PCOMP_2X_DYN_BST_ON_EN); 661 if (ret) 662 goto err_regulator_disable; 663 664 /* Enable dynamic boosting for MG1 OVP */ 665 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG1_MISC, 666 WCD_USBSS_MG1_MISC_PCOMP_2X_DYN_BST_ON_EN); 667 if (ret) 668 goto err_regulator_disable; 669 670 /* Enable dynamic boosting for MG2 OVP */ 671 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG2_MISC, 672 WCD_USBSS_MG2_MISC_PCOMP_2X_DYN_BST_ON_EN); 673 if (ret) 674 goto err_regulator_disable; 675 676 /* Write 0xFF to WCD_USBSS_CPLDO_CTL2 */ 677 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_CPLDO_CTL2, 0xff); 678 if (ret) 679 goto err_regulator_disable; 680 681 /* Set RCO_EN: WCD_USBSS_USB_SS_CNTL Bit<3> --> 0x0 --> 0x1 */ 682 ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, 683 WCD_USBSS_USB_SS_CNTL_RCO_EN); 684 if (ret) 685 goto err_regulator_disable; 686 687 ret = regmap_set_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL, 688 WCD_USBSS_USB_SS_CNTL_RCO_EN); 689 if (ret) 690 goto err_regulator_disable; 691 692 /* Disable all switches but enable the mux */ 693 ret = regmap_write(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE, 694 WCD_USBSS_SWITCH_SETTINGS_ENABLE_DEVICE_ENABLE); 695 if (ret) 696 goto err_regulator_disable; 697 698 /* Setup in SAFE mode */ 699 ret = wcd939x_usbss_set(usbss); 700 if (ret) 701 goto err_regulator_disable; 702 703 sw_desc.drvdata = usbss; 704 sw_desc.fwnode = dev_fwnode(dev); 705 sw_desc.set = wcd939x_usbss_switch_set; 706 707 usbss->sw = typec_switch_register(dev, &sw_desc); 708 if (IS_ERR(usbss->sw)) { 709 ret = dev_err_probe(dev, PTR_ERR(usbss->sw), "failed to register typec switch\n"); 710 goto err_regulator_disable; 711 } 712 713 mux_desc.drvdata = usbss; 714 mux_desc.fwnode = dev_fwnode(dev); 715 mux_desc.set = wcd939x_usbss_mux_set; 716 717 usbss->mux = typec_mux_register(dev, &mux_desc); 718 if (IS_ERR(usbss->mux)) { 719 ret = dev_err_probe(dev, PTR_ERR(usbss->mux), "failed to register typec mux\n"); 720 goto err_switch_unregister; 721 } 722 723 i2c_set_clientdata(client, usbss); 724 725 return 0; 726 727err_switch_unregister: 728 typec_switch_unregister(usbss->sw); 729 730err_regulator_disable: 731 regulator_disable(usbss->vdd_supply); 732 733err_mux_switch: 734 typec_switch_put(usbss->codec_switch); 735 736err_mux_put: 737 typec_mux_put(usbss->codec); 738 739 return ret; 740} 741 742static void wcd939x_usbss_remove(struct i2c_client *client) 743{ 744 struct wcd939x_usbss *usbss = i2c_get_clientdata(client); 745 746 typec_mux_unregister(usbss->mux); 747 typec_switch_unregister(usbss->sw); 748 749 regulator_disable(usbss->vdd_supply); 750 751 typec_switch_put(usbss->codec_switch); 752 typec_mux_put(usbss->codec); 753} 754 755static const struct i2c_device_id wcd939x_usbss_table[] = { 756 { "wcd9390-usbss" }, 757 { } 758}; 759MODULE_DEVICE_TABLE(i2c, wcd939x_usbss_table); 760 761static const struct of_device_id wcd939x_usbss_of_table[] = { 762 { .compatible = "qcom,wcd9390-usbss" }, 763 { } 764}; 765MODULE_DEVICE_TABLE(of, wcd939x_usbss_of_table); 766 767static struct i2c_driver wcd939x_usbss_driver = { 768 .driver = { 769 .name = "wcd939x-usbss", 770 .of_match_table = wcd939x_usbss_of_table, 771 }, 772 .probe = wcd939x_usbss_probe, 773 .remove = wcd939x_usbss_remove, 774 .id_table = wcd939x_usbss_table, 775}; 776module_i2c_driver(wcd939x_usbss_driver); 777 778MODULE_DESCRIPTION("Qualcomm WCD939x USBSS driver"); 779MODULE_LICENSE("GPL");
~/
Read-only file preview.