xref: /linux/drivers/usb/typec/tcpm/maxim_contaminant.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
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 ret;
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 ret;
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 	/* Sleep to allow comparators settle */
192 	usleep_range(5000, 6000);
193 	ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION, PLUG_ORNT_CC1);
194 	if (ret < 0)
195 		return ret;
196 
197 	usleep_range(5000, 6000);
198 	ret = max_tcpci_read8(chip, VENDOR_CC_STATUS2, vendor_cc_status2_cc1);
199 	if (ret < 0)
200 		return ret;
201 
202 	ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION, PLUG_ORNT_CC2);
203 	if (ret < 0)
204 		return ret;
205 
206 	usleep_range(5000, 6000);
207 	ret = max_tcpci_read8(chip, VENDOR_CC_STATUS2, vendor_cc_status2_cc2);
208 	if (ret < 0)
209 		return ret;
210 
211 	ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCOMPEN, 0);
212 	if (ret < 0)
213 		return ret;
214 
215 	ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCRPCTRL,
216 				 FIELD_PREP(CCRPCTRL, 0));
217 	if (ret < 0)
218 		return ret;
219 
220 	return 0;
221 }
222 
max_contaminant_detect_contaminant(struct max_tcpci_chip * chip)223 static 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;
276 exit:
277 	max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl_backup);
278 	return NOT_DETECTED;
279 }
280 
max_contaminant_enable_dry_detection(struct max_tcpci_chip * chip)281 static 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,
288 				 CCWTRDEB | CCWTRSEL | WTRCYCLE,
289 				 FIELD_PREP(CCWTRDEB, CCWTRDEB_1MS)
290 				 | FIELD_PREP(CCWTRSEL, CCWTRSEL_1V)
291 				 | FIELD_PREP(WTRCYCLE, WTRCYCLE_4_8_S));
292 	if (ret < 0)
293 		return ret;
294 
295 	ret = regmap_update_bits(regmap, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP, TCPC_ROLE_CTRL_DRP);
296 	if (ret < 0)
297 		return ret;
298 
299 	ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCONNDRY, CCCONNDRY);
300 	if (ret < 0)
301 		return ret;
302 	ret = max_tcpci_read8(chip, TCPC_VENDOR_CC_CTRL1, &temp);
303 	if (ret < 0)
304 		return ret;
305 
306 	ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL,
307 				 FIELD_PREP(CCLPMODESEL,
308 					    ULTRA_LOW_POWER_MODE));
309 	if (ret < 0)
310 		return ret;
311 	ret = max_tcpci_read8(chip, TCPC_VENDOR_CC_CTRL2, &temp);
312 	if (ret < 0)
313 		return ret;
314 
315 	/* Enable Look4Connection before sending the command */
316 	ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_EN_LK4CONN_ALRT,
317 				 TCPC_TCPC_CTRL_EN_LK4CONN_ALRT);
318 	if (ret < 0)
319 		return ret;
320 
321 	ret = max_tcpci_write8(chip, TCPC_COMMAND, TCPC_CMD_LOOK4CONNECTION);
322 	if (ret < 0)
323 		return ret;
324 	return 0;
325 }
326 
max_contaminant_is_contaminant(struct max_tcpci_chip * chip,bool disconnect_while_debounce,bool * cc_handled)327 bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce,
328 				    bool *cc_handled)
329 {
330 	u8 cc_status, pwr_cntl;
331 	int ret;
332 
333 	*cc_handled = true;
334 
335 	ret = max_tcpci_read8(chip, TCPC_CC_STATUS, &cc_status);
336 	if (ret < 0)
337 		return false;
338 
339 	ret = max_tcpci_read8(chip, TCPC_POWER_CTRL, &pwr_cntl);
340 	if (ret < 0)
341 		return false;
342 
343 	if (chip->contaminant_state == NOT_DETECTED || chip->contaminant_state == SINK) {
344 		if (!disconnect_while_debounce)
345 			msleep(100);
346 
347 		ret = max_tcpci_read8(chip, TCPC_CC_STATUS, &cc_status);
348 		if (ret < 0)
349 			return false;
350 
351 		if (IS_CC_OPEN(cc_status)) {
352 			u8 role_ctrl, role_ctrl_backup;
353 
354 			ret = max_tcpci_read8(chip, TCPC_ROLE_CTRL, &role_ctrl);
355 			if (ret < 0)
356 				return false;
357 
358 			role_ctrl_backup = role_ctrl;
359 			role_ctrl |= 0x0F;
360 			role_ctrl &= ~(TCPC_ROLE_CTRL_DRP);
361 			ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl);
362 			if (ret < 0)
363 				return false;
364 
365 			chip->contaminant_state = max_contaminant_detect_contaminant(chip);
366 
367 			ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, role_ctrl_backup);
368 			if (ret < 0)
369 				return false;
370 
371 			if (chip->contaminant_state == DETECTED) {
372 				max_contaminant_enable_dry_detection(chip);
373 				return true;
374 			}
375 		}
376 	} else if (chip->contaminant_state == DETECTED) {
377 		if (!(cc_status & TCPC_CC_STATUS_TOGGLING)) {
378 			chip->contaminant_state = max_contaminant_detect_contaminant(chip);
379 			if (chip->contaminant_state == DETECTED) {
380 				max_contaminant_enable_dry_detection(chip);
381 				return true;
382 			}
383 		}
384 	}
385 
386 	*cc_handled = false;
387 	return false;
388 }
389 
390 MODULE_DESCRIPTION("MAXIM TCPC CONTAMINANT Module");
391 MODULE_AUTHOR("Badhri Jagan Sridharan <badhri@google.com>");
392 MODULE_LICENSE("GPL");
393