1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2022 Google, Inc 4 * 5 * USB-C module to reduce wakeups due to contaminants. 6 */ 7 8#include <linux/device.h> 9#include <linux/irqreturn.h> 10#include <linux/module.h> 11#include <linux/regmap.h> 12#include <linux/usb/tcpci.h> 13#include <linux/usb/tcpm.h> 14#include <linux/usb/typec.h> 15 16#include "tcpci_maxim.h" 17 18enum fladc_select { 19 CC1_SCALE1 = 1, 20 CC1_SCALE2, 21 CC2_SCALE1, 22 CC2_SCALE2, 23 SBU1, 24 SBU2, 25}; 26 27#define FLADC_1uA_LSB_MV 25 28/* High range CC */ 29#define FLADC_CC_HIGH_RANGE_LSB_MV 208 30/* Low range CC */ 31#define FLADC_CC_LOW_RANGE_LSB_MV 126 32 33/* 1uA current source */ 34#define FLADC_CC_SCALE1 1 35/* 5 uA current source */ 36#define FLADC_CC_SCALE2 5 37 38#define FLADC_1uA_CC_OFFSET_MV 300 39#define FLADC_CC_HIGH_RANGE_OFFSET_MV 624 40#define FLADC_CC_LOW_RANGE_OFFSET_MV 378 41 42#define CONTAMINANT_THRESHOLD_SBU_K 1000 43#define CONTAMINANT_THRESHOLD_CC_K 1000 44 45#define READ1_SLEEP_MS 10 46#define READ2_SLEEP_MS 5 47 48#define STATUS_CHECK(reg, mask, val) (((reg) & (mask)) == (val)) 49 50#define IS_CC_OPEN(cc_status) \ 51 (STATUS_CHECK((cc_status), TCPC_CC_STATUS_CC1_MASK << TCPC_CC_STATUS_CC1_SHIFT, \ 52 TCPC_CC_STATE_SRC_OPEN) && STATUS_CHECK((cc_status), \ 53 TCPC_CC_STATUS_CC2_MASK << \ 54 TCPC_CC_STATUS_CC2_SHIFT, \ 55 TCPC_CC_STATE_SRC_OPEN)) 56 57static int max_contaminant_adc_to_mv(struct max_tcpci_chip *chip, enum fladc_select channel, 58 bool ua_src, u8 fladc) 59{ 60 /* SBU channels only have 1 scale with 1uA. */ 61 if ((ua_src && (channel == CC1_SCALE2 || channel == CC2_SCALE2 || channel == SBU1 || 62 channel == SBU2))) 63 /* Mean of range */ 64 return FLADC_1uA_CC_OFFSET_MV + (fladc * FLADC_1uA_LSB_MV); 65 else if (!ua_src && (channel == CC1_SCALE1 || channel == CC2_SCALE1)) 66 return FLADC_CC_HIGH_RANGE_OFFSET_MV + (fladc * FLADC_CC_HIGH_RANGE_LSB_MV); 67 else if (!ua_src && (channel == CC1_SCALE2 || channel == CC2_SCALE2)) 68 return FLADC_CC_LOW_RANGE_OFFSET_MV + (fladc * FLADC_CC_LOW_RANGE_LSB_MV); 69 70 dev_err_once(chip->dev, "ADC ERROR: SCALE UNKNOWN"); 71 72 return -EINVAL; 73} 74 75static int max_contaminant_read_adc_mv(struct max_tcpci_chip *chip, enum fladc_select channel, 76 int sleep_msec, bool raw, bool ua_src) 77{ 78 struct regmap *regmap = chip->data.regmap; 79 u8 fladc; 80 int ret; 81 82 /* Channel & scale select */ 83 ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL_MASK, 84 channel << ADC_CHANNEL_OFFSET); 85 if (ret < 0) 86 return ret; 87 88 /* Enable ADC */ 89 ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCEN, ADCEN); 90 if (ret < 0) 91 return ret; 92 93 usleep_range(sleep_msec * 1000, (sleep_msec + 1) * 1000); 94 ret = max_tcpci_read8(chip, TCPC_VENDOR_FLADC_STATUS, &fladc); 95 if (ret < 0) 96 return ret; 97 98 /* Disable ADC */ 99 ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCEN, 0); 100 if (ret < 0) 101 return ret; 102 103 ret = regmap_update_bits(regmap, TCPC_VENDOR_ADC_CTRL1, ADCINSEL_MASK, 0); 104 if (ret < 0) 105 return ret; 106 107 if (!raw) 108 return max_contaminant_adc_to_mv(chip, channel, ua_src, fladc); 109 else 110 return fladc; 111} 112 113static int max_contaminant_read_resistance_kohm(struct max_tcpci_chip *chip, 114 enum fladc_select channel, int sleep_msec, bool raw) 115{ 116 struct regmap *regmap = chip->data.regmap; 117 int mv; 118 int ret; 119 120 if (channel == CC1_SCALE1 || channel == CC2_SCALE1 || channel == CC1_SCALE2 || 121 channel == CC2_SCALE2) { 122 /* Enable 1uA current source */ 123 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK, 124 ULTRA_LOW_POWER_MODE); 125 if (ret < 0) 126 return ret; 127 128 /* Enable 1uA current source */ 129 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, UA_1_SRC); 130 if (ret < 0) 131 return ret; 132 133 /* OVP disable */ 134 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCOVPDIS, CCOVPDIS); 135 if (ret < 0) 136 return ret; 137 138 mv = max_contaminant_read_adc_mv(chip, channel, sleep_msec, raw, true); 139 if (mv < 0) 140 return ret; 141 142 /* OVP enable */ 143 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCOVPDIS, 0); 144 if (ret < 0) 145 return ret; 146 /* returns KOhm as 1uA source is used. */ 147 return mv; 148 } 149 150 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, SBUOVPDIS, SBUOVPDIS); 151 if (ret < 0) 152 return ret; 153 154 /* SBU switches auto configure when channel is selected. */ 155 /* Enable 1ua current source */ 156 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, SBURPCTRL, SBURPCTRL); 157 if (ret < 0) 158 return ret; 159 160 mv = max_contaminant_read_adc_mv(chip, channel, sleep_msec, raw, true); 161 if (mv < 0) 162 return ret; 163 /* Disable current source */ 164 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, SBURPCTRL, 0); 165 if (ret < 0) 166 return ret; 167 168 /* OVP disable */ 169 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, SBUOVPDIS, 0); 170 if (ret < 0) 171 return ret; 172 173 return mv; 174} 175 176static int max_contaminant_read_comparators(struct max_tcpci_chip *chip, u8 *vendor_cc_status2_cc1, 177 u8 *vendor_cc_status2_cc2) 178{ 179 struct regmap *regmap = chip->data.regmap; 180 int ret; 181 182 /* Enable 80uA source */ 183 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, UA_80_SRC); 184 if (ret < 0) 185 return ret; 186 187 /* Enable comparators */ 188 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCOMPEN, CCCOMPEN); 189 if (ret < 0) 190 return ret; 191 192 /* Sleep to allow comparators settle */ 193 usleep_range(5000, 6000); 194 ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION, PLUG_ORNT_CC1); 195 if (ret < 0) 196 return ret; 197 198 usleep_range(5000, 6000); 199 ret = max_tcpci_read8(chip, VENDOR_CC_STATUS2, vendor_cc_status2_cc1); 200 if (ret < 0) 201 return ret; 202 203 ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION, PLUG_ORNT_CC2); 204 if (ret < 0) 205 return ret; 206 207 usleep_range(5000, 6000); 208 ret = max_tcpci_read8(chip, VENDOR_CC_STATUS2, vendor_cc_status2_cc2); 209 if (ret < 0) 210 return ret; 211 212 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCOMPEN, 0); 213 if (ret < 0) 214 return ret; 215 216 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL_MASK, 0); 217 if (ret < 0) 218 return ret; 219 220 return 0; 221} 222 223static int max_contaminant_detect_contaminant(struct max_tcpci_chip *chip) 224{ 225 int cc1_k, cc2_k, sbu1_k, sbu2_k, ret; 226 u8 vendor_cc_status2_cc1 = 0xff, vendor_cc_status2_cc2 = 0xff; 227 u8 role_ctrl = 0, role_ctrl_backup = 0; 228 int inferred_state = NOT_DETECTED; 229 230 ret = max_tcpci_read8(chip, TCPC_ROLE_CTRL, &role_ctrl); 231 if (ret < 0) 232 return NOT_DETECTED; 233 234 role_ctrl_backup = role_ctrl; 235 role_ctrl = 0x0F; 236 ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl); 237 if (ret < 0) 238 return NOT_DETECTED; 239 240 cc1_k = max_contaminant_read_resistance_kohm(chip, CC1_SCALE2, READ1_SLEEP_MS, false); 241 if (cc1_k < 0) 242 goto exit; 243 244 cc2_k = max_contaminant_read_resistance_kohm(chip, CC2_SCALE2, READ2_SLEEP_MS, false); 245 if (cc2_k < 0) 246 goto exit; 247 248 sbu1_k = max_contaminant_read_resistance_kohm(chip, SBU1, READ1_SLEEP_MS, false); 249 if (sbu1_k < 0) 250 goto exit; 251 252 sbu2_k = max_contaminant_read_resistance_kohm(chip, SBU2, READ2_SLEEP_MS, false); 253 if (sbu2_k < 0) 254 goto exit; 255 256 ret = max_contaminant_read_comparators(chip, &vendor_cc_status2_cc1, 257 &vendor_cc_status2_cc2); 258 259 if (ret < 0) 260 goto exit; 261 262 if ((!(CC1_VUFP_RD0P5 & vendor_cc_status2_cc1) || 263 !(CC2_VUFP_RD0P5 & vendor_cc_status2_cc2)) && 264 !(CC1_VUFP_RD0P5 & vendor_cc_status2_cc1 && CC2_VUFP_RD0P5 & vendor_cc_status2_cc2)) 265 inferred_state = SINK; 266 else if ((cc1_k < CONTAMINANT_THRESHOLD_CC_K || cc2_k < CONTAMINANT_THRESHOLD_CC_K) && 267 (sbu1_k < CONTAMINANT_THRESHOLD_SBU_K || sbu2_k < CONTAMINANT_THRESHOLD_SBU_K)) 268 inferred_state = DETECTED; 269 270 if (inferred_state == NOT_DETECTED) 271 max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl_backup); 272 else 273 max_tcpci_write8(chip, TCPC_ROLE_CTRL, (TCPC_ROLE_CTRL_DRP | 0xA)); 274 275 return inferred_state; 276exit: 277 max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl_backup); 278 return NOT_DETECTED; 279} 280 281static int max_contaminant_enable_dry_detection(struct max_tcpci_chip *chip) 282{ 283 struct regmap *regmap = chip->data.regmap; 284 u8 temp; 285 int ret; 286 287 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL3, CCWTRDEB_MASK | CCWTRSEL_MASK 288 | WTRCYCLE_MASK, CCWTRDEB_1MS << CCWTRDEB_SHIFT | 289 CCWTRSEL_1V << CCWTRSEL_SHIFT | WTRCYCLE_4_8_S << 290 WTRCYCLE_SHIFT); 291 if (ret < 0) 292 return ret; 293 294 ret = regmap_update_bits(regmap, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP, TCPC_ROLE_CTRL_DRP); 295 if (ret < 0) 296 return ret; 297 298 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCONNDRY, CCCONNDRY); 299 if (ret < 0) 300 return ret; 301 ret = max_tcpci_read8(chip, TCPC_VENDOR_CC_CTRL1, &temp); 302 if (ret < 0) 303 return ret; 304 305 ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL_MASK, 306 ULTRA_LOW_POWER_MODE); 307 if (ret < 0) 308 return ret; 309 ret = max_tcpci_read8(chip, TCPC_VENDOR_CC_CTRL2, &temp); 310 if (ret < 0) 311 return ret; 312 313 /* Enable Look4Connection before sending the command */ 314 ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_EN_LK4CONN_ALRT, 315 TCPC_TCPC_CTRL_EN_LK4CONN_ALRT); 316 if (ret < 0) 317 return ret; 318 319 ret = max_tcpci_write8(chip, TCPC_COMMAND, TCPC_CMD_LOOK4CONNECTION); 320 if (ret < 0) 321 return ret; 322 return 0; 323} 324 325bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce) 326{ 327 u8 cc_status, pwr_cntl; 328 int ret; 329 330 ret = max_tcpci_read8(chip, TCPC_CC_STATUS, &cc_status); 331 if (ret < 0) 332 return false; 333 334 ret = max_tcpci_read8(chip, TCPC_POWER_CTRL, &pwr_cntl); 335 if (ret < 0) 336 return false; 337 338 if (chip->contaminant_state == NOT_DETECTED || chip->contaminant_state == SINK) { 339 if (!disconnect_while_debounce) 340 msleep(100); 341 342 ret = max_tcpci_read8(chip, TCPC_CC_STATUS, &cc_status); 343 if (ret < 0) 344 return false; 345 346 if (IS_CC_OPEN(cc_status)) { 347 u8 role_ctrl, role_ctrl_backup; 348 349 ret = max_tcpci_read8(chip, TCPC_ROLE_CTRL, &role_ctrl); 350 if (ret < 0) 351 return false; 352 353 role_ctrl_backup = role_ctrl; 354 role_ctrl |= 0x0F; 355 role_ctrl &= ~(TCPC_ROLE_CTRL_DRP); 356 ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl); 357 if (ret < 0) 358 return false; 359 360 chip->contaminant_state = max_contaminant_detect_contaminant(chip); 361 362 ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl_backup); 363 if (ret < 0) 364 return false; 365 366 if (chip->contaminant_state == DETECTED) { 367 max_contaminant_enable_dry_detection(chip); 368 return true; 369 } 370 } 371 return false; 372 } else if (chip->contaminant_state == DETECTED) { 373 if (STATUS_CHECK(cc_status, TCPC_CC_STATUS_TOGGLING, 0)) { 374 chip->contaminant_state = max_contaminant_detect_contaminant(chip); 375 if (chip->contaminant_state == DETECTED) { 376 max_contaminant_enable_dry_detection(chip); 377 return true; 378 } 379 } 380 } 381 382 return false; 383} 384 385MODULE_DESCRIPTION("MAXIM TCPC CONTAMINANT Module"); 386MODULE_AUTHOR("Badhri Jagan Sridharan <badhri@google.com>"); 387MODULE_LICENSE("GPL"); 388