xref: /openbmc/linux/drivers/usb/typec/mux/fsa4480.c (revision ef1e29c6)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2021-2022 Linaro Ltd.
4  * Copyright (C) 2018-2020 The Linux Foundation
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/usb/typec_dp.h>
14 #include <linux/usb/typec_mux.h>
15 
16 #define FSA4480_SWITCH_ENABLE	0x04
17 #define FSA4480_SWITCH_SELECT	0x05
18 #define FSA4480_SWITCH_STATUS1	0x07
19 #define FSA4480_SLOW_L		0x08
20 #define FSA4480_SLOW_R		0x09
21 #define FSA4480_SLOW_MIC	0x0a
22 #define FSA4480_SLOW_SENSE	0x0b
23 #define FSA4480_SLOW_GND	0x0c
24 #define FSA4480_DELAY_L_R	0x0d
25 #define FSA4480_DELAY_L_MIC	0x0e
26 #define FSA4480_DELAY_L_SENSE	0x0f
27 #define FSA4480_DELAY_L_AGND	0x10
28 #define FSA4480_FUNCTION_ENABLE	0x12
29 #define FSA4480_RESET		0x1e
30 #define FSA4480_MAX_REGISTER	0x1f
31 
32 #define FSA4480_ENABLE_DEVICE	BIT(7)
33 #define FSA4480_ENABLE_SBU	GENMASK(6, 5)
34 #define FSA4480_ENABLE_USB	GENMASK(4, 3)
35 #define FSA4480_ENABLE_SENSE	BIT(2)
36 #define FSA4480_ENABLE_MIC	BIT(1)
37 #define FSA4480_ENABLE_AGND	BIT(0)
38 
39 #define FSA4480_SEL_SBU_REVERSE	GENMASK(6, 5)
40 #define FSA4480_SEL_USB		GENMASK(4, 3)
41 #define FSA4480_SEL_SENSE	BIT(2)
42 #define FSA4480_SEL_MIC		BIT(1)
43 #define FSA4480_SEL_AGND	BIT(0)
44 
45 #define FSA4480_ENABLE_AUTO_JACK_DETECT	BIT(0)
46 
47 struct fsa4480 {
48 	struct i2c_client *client;
49 
50 	/* used to serialize concurrent change requests */
51 	struct mutex lock;
52 
53 	struct typec_switch_dev *sw;
54 	struct typec_mux_dev *mux;
55 
56 	struct regmap *regmap;
57 
58 	enum typec_orientation orientation;
59 	unsigned long mode;
60 	unsigned int svid;
61 
62 	u8 cur_enable;
63 };
64 
65 static const struct regmap_config fsa4480_regmap_config = {
66 	.reg_bits = 8,
67 	.val_bits = 8,
68 	.max_register = FSA4480_MAX_REGISTER,
69 	/* Accesses only done under fsa4480->lock */
70 	.disable_locking = true,
71 };
72 
fsa4480_set(struct fsa4480 * fsa)73 static int fsa4480_set(struct fsa4480 *fsa)
74 {
75 	bool reverse = (fsa->orientation == TYPEC_ORIENTATION_REVERSE);
76 	u8 enable = FSA4480_ENABLE_DEVICE;
77 	u8 sel = 0;
78 
79 	/* USB Mode */
80 	if (fsa->mode < TYPEC_STATE_MODAL ||
81 	    (!fsa->svid && (fsa->mode == TYPEC_MODE_USB2 ||
82 			    fsa->mode == TYPEC_MODE_USB3))) {
83 		enable |= FSA4480_ENABLE_USB;
84 		sel = FSA4480_SEL_USB;
85 	} else if (fsa->svid) {
86 		switch (fsa->mode) {
87 		/* DP Only */
88 		case TYPEC_DP_STATE_C:
89 		case TYPEC_DP_STATE_E:
90 			enable |= FSA4480_ENABLE_SBU;
91 			if (reverse)
92 				sel = FSA4480_SEL_SBU_REVERSE;
93 			break;
94 
95 		/* DP + USB */
96 		case TYPEC_DP_STATE_D:
97 		case TYPEC_DP_STATE_F:
98 			enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_SBU;
99 			sel = FSA4480_SEL_USB;
100 			if (reverse)
101 				sel |= FSA4480_SEL_SBU_REVERSE;
102 			break;
103 
104 		default:
105 			return -EOPNOTSUPP;
106 		}
107 	} else if (fsa->mode == TYPEC_MODE_AUDIO) {
108 		/* Audio Accessory Mode, setup to auto Jack Detection */
109 		enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_AGND;
110 	} else
111 		return -EOPNOTSUPP;
112 
113 	if (fsa->cur_enable & FSA4480_ENABLE_SBU) {
114 		/* Disable SBU output while re-configuring the switch */
115 		regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE,
116 			     fsa->cur_enable & ~FSA4480_ENABLE_SBU);
117 
118 		/* 35us to allow the SBU switch to turn off */
119 		usleep_range(35, 1000);
120 	}
121 
122 	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, sel);
123 	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, enable);
124 
125 	/* Start AUDIO JACK DETECTION to setup MIC, AGND & Sense muxes */
126 	if (enable & FSA4480_ENABLE_AGND)
127 		regmap_write(fsa->regmap, FSA4480_FUNCTION_ENABLE,
128 			     FSA4480_ENABLE_AUTO_JACK_DETECT);
129 
130 	if (enable & FSA4480_ENABLE_SBU) {
131 		/* 15us to allow the SBU switch to turn on again */
132 		usleep_range(15, 1000);
133 	}
134 
135 	fsa->cur_enable = enable;
136 
137 	return 0;
138 }
139 
fsa4480_switch_set(struct typec_switch_dev * sw,enum typec_orientation orientation)140 static int fsa4480_switch_set(struct typec_switch_dev *sw,
141 			      enum typec_orientation orientation)
142 {
143 	struct fsa4480 *fsa = typec_switch_get_drvdata(sw);
144 	int ret = 0;
145 
146 	mutex_lock(&fsa->lock);
147 
148 	if (fsa->orientation != orientation) {
149 		fsa->orientation = orientation;
150 
151 		ret = fsa4480_set(fsa);
152 	}
153 
154 	mutex_unlock(&fsa->lock);
155 
156 	return ret;
157 }
158 
fsa4480_mux_set(struct typec_mux_dev * mux,struct typec_mux_state * state)159 static int fsa4480_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
160 {
161 	struct fsa4480 *fsa = typec_mux_get_drvdata(mux);
162 	int ret = 0;
163 
164 	mutex_lock(&fsa->lock);
165 
166 	if (fsa->mode != state->mode) {
167 		fsa->mode = state->mode;
168 
169 		if (state->alt)
170 			fsa->svid = state->alt->svid;
171 		else
172 			fsa->svid = 0; // No SVID
173 
174 		ret = fsa4480_set(fsa);
175 	}
176 
177 	mutex_unlock(&fsa->lock);
178 
179 	return ret;
180 }
181 
fsa4480_probe(struct i2c_client * client)182 static int fsa4480_probe(struct i2c_client *client)
183 {
184 	struct device *dev = &client->dev;
185 	struct typec_switch_desc sw_desc = { };
186 	struct typec_mux_desc mux_desc = { };
187 	struct fsa4480 *fsa;
188 
189 	fsa = devm_kzalloc(dev, sizeof(*fsa), GFP_KERNEL);
190 	if (!fsa)
191 		return -ENOMEM;
192 
193 	fsa->client = client;
194 	mutex_init(&fsa->lock);
195 
196 	fsa->regmap = devm_regmap_init_i2c(client, &fsa4480_regmap_config);
197 	if (IS_ERR(fsa->regmap))
198 		return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n");
199 
200 	/* Safe mode */
201 	fsa->cur_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB;
202 	fsa->mode = TYPEC_STATE_SAFE;
203 	fsa->orientation = TYPEC_ORIENTATION_NONE;
204 
205 	/* set default settings */
206 	regmap_write(fsa->regmap, FSA4480_SLOW_L, 0x00);
207 	regmap_write(fsa->regmap, FSA4480_SLOW_R, 0x00);
208 	regmap_write(fsa->regmap, FSA4480_SLOW_MIC, 0x00);
209 	regmap_write(fsa->regmap, FSA4480_SLOW_SENSE, 0x00);
210 	regmap_write(fsa->regmap, FSA4480_SLOW_GND, 0x00);
211 	regmap_write(fsa->regmap, FSA4480_DELAY_L_R, 0x00);
212 	regmap_write(fsa->regmap, FSA4480_DELAY_L_MIC, 0x00);
213 	regmap_write(fsa->regmap, FSA4480_DELAY_L_SENSE, 0x00);
214 	regmap_write(fsa->regmap, FSA4480_DELAY_L_AGND, 0x09);
215 	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, FSA4480_SEL_USB);
216 	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable);
217 
218 	sw_desc.drvdata = fsa;
219 	sw_desc.fwnode = dev_fwnode(dev);
220 	sw_desc.set = fsa4480_switch_set;
221 
222 	fsa->sw = typec_switch_register(dev, &sw_desc);
223 	if (IS_ERR(fsa->sw))
224 		return dev_err_probe(dev, PTR_ERR(fsa->sw), "failed to register typec switch\n");
225 
226 	mux_desc.drvdata = fsa;
227 	mux_desc.fwnode = dev_fwnode(dev);
228 	mux_desc.set = fsa4480_mux_set;
229 
230 	fsa->mux = typec_mux_register(dev, &mux_desc);
231 	if (IS_ERR(fsa->mux)) {
232 		typec_switch_unregister(fsa->sw);
233 		return dev_err_probe(dev, PTR_ERR(fsa->mux), "failed to register typec mux\n");
234 	}
235 
236 	i2c_set_clientdata(client, fsa);
237 	return 0;
238 }
239 
fsa4480_remove(struct i2c_client * client)240 static void fsa4480_remove(struct i2c_client *client)
241 {
242 	struct fsa4480 *fsa = i2c_get_clientdata(client);
243 
244 	typec_mux_unregister(fsa->mux);
245 	typec_switch_unregister(fsa->sw);
246 }
247 
248 static const struct i2c_device_id fsa4480_table[] = {
249 	{ "fsa4480" },
250 	{ }
251 };
252 MODULE_DEVICE_TABLE(i2c, fsa4480_table);
253 
254 static const struct of_device_id fsa4480_of_table[] = {
255 	{ .compatible = "fcs,fsa4480" },
256 	{ }
257 };
258 MODULE_DEVICE_TABLE(of, fsa4480_of_table);
259 
260 static struct i2c_driver fsa4480_driver = {
261 	.driver = {
262 		.name = "fsa4480",
263 		.of_match_table = fsa4480_of_table,
264 	},
265 	.probe		= fsa4480_probe,
266 	.remove		= fsa4480_remove,
267 	.id_table	= fsa4480_table,
268 };
269 module_i2c_driver(fsa4480_driver);
270 
271 MODULE_DESCRIPTION("ON Semiconductor FSA4480 driver");
272 MODULE_LICENSE("GPL v2");
273