File Index
Files and directories
Sign in
FILE

wcd939x-usbss.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/typec/mux/wcd939x-usbss.c 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.