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