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