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
47struct 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 bool swap_sbu_lanes;
64};
65
66static const struct regmap_config fsa4480_regmap_config = {
67 .reg_bits = 8,
68 .val_bits = 8,
69 .max_register = FSA4480_MAX_REGISTER,
70 /* Accesses only done under fsa4480->lock */
71 .disable_locking = true,
72};
73
74static int fsa4480_set(struct fsa4480 *fsa)
75{
76 bool reverse = (fsa->orientation == TYPEC_ORIENTATION_REVERSE);
77 u8 enable = FSA4480_ENABLE_DEVICE;
78 u8 sel = 0;
79
80 if (fsa->swap_sbu_lanes)
81 reverse = !reverse;
82
83 /* USB Mode */
84 if (fsa->mode < TYPEC_STATE_MODAL ||
85 (!fsa->svid && (fsa->mode == TYPEC_MODE_USB2 ||
86 fsa->mode == TYPEC_MODE_USB3))) {
87 enable |= FSA4480_ENABLE_USB;
88 sel = FSA4480_SEL_USB;
89 } else if (fsa->svid) {
90 switch (fsa->mode) {
91 /* DP Only */
92 case TYPEC_DP_STATE_C:
93 case TYPEC_DP_STATE_E:
94 enable |= FSA4480_ENABLE_SBU;
95 if (reverse)
96 sel = FSA4480_SEL_SBU_REVERSE;
97 break;
98
99 /* DP + USB */
100 case TYPEC_DP_STATE_D:
101 case TYPEC_DP_STATE_F:
102 enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_SBU;
103 sel = FSA4480_SEL_USB;
104 if (reverse)
105 sel |= FSA4480_SEL_SBU_REVERSE;
106 break;
107
108 default:
109 return -EOPNOTSUPP;
110 }
111 } else if (fsa->mode == TYPEC_MODE_AUDIO) {
112 /* Audio Accessory Mode, setup to auto Jack Detection */
113 enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_AGND;
114 } else
115 return -EOPNOTSUPP;
116
117 if (fsa->cur_enable & FSA4480_ENABLE_SBU) {
118 /* Disable SBU output while re-configuring the switch */
119 regmap_write(map: fsa->regmap, FSA4480_SWITCH_ENABLE,
120 val: fsa->cur_enable & ~FSA4480_ENABLE_SBU);
121
122 /* 35us to allow the SBU switch to turn off */
123 usleep_range(min: 35, max: 1000);
124 }
125
126 regmap_write(map: fsa->regmap, FSA4480_SWITCH_SELECT, val: sel);
127 regmap_write(map: fsa->regmap, FSA4480_SWITCH_ENABLE, val: enable);
128
129 /* Start AUDIO JACK DETECTION to setup MIC, AGND & Sense muxes */
130 if (enable & FSA4480_ENABLE_AGND)
131 regmap_write(map: fsa->regmap, FSA4480_FUNCTION_ENABLE,
132 FSA4480_ENABLE_AUTO_JACK_DETECT);
133
134 if (enable & FSA4480_ENABLE_SBU) {
135 /* 15us to allow the SBU switch to turn on again */
136 usleep_range(min: 15, max: 1000);
137 }
138
139 fsa->cur_enable = enable;
140
141 return 0;
142}
143
144static int fsa4480_switch_set(struct typec_switch_dev *sw,
145 enum typec_orientation orientation)
146{
147 struct fsa4480 *fsa = typec_switch_get_drvdata(sw);
148 int ret = 0;
149
150 mutex_lock(&fsa->lock);
151
152 if (fsa->orientation != orientation) {
153 fsa->orientation = orientation;
154
155 ret = fsa4480_set(fsa);
156 }
157
158 mutex_unlock(lock: &fsa->lock);
159
160 return ret;
161}
162
163static int fsa4480_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
164{
165 struct fsa4480 *fsa = typec_mux_get_drvdata(mux);
166 int ret = 0;
167
168 mutex_lock(&fsa->lock);
169
170 if (fsa->mode != state->mode) {
171 fsa->mode = state->mode;
172
173 if (state->alt)
174 fsa->svid = state->alt->svid;
175 else
176 fsa->svid = 0; // No SVID
177
178 ret = fsa4480_set(fsa);
179 }
180
181 mutex_unlock(lock: &fsa->lock);
182
183 return ret;
184}
185
186enum {
187 NORMAL_LANE_MAPPING,
188 INVERT_LANE_MAPPING,
189};
190
191#define DATA_LANES_COUNT 2
192
193static const int supported_data_lane_mapping[][DATA_LANES_COUNT] = {
194 [NORMAL_LANE_MAPPING] = { 0, 1 },
195 [INVERT_LANE_MAPPING] = { 1, 0 },
196};
197
198static int fsa4480_parse_data_lanes_mapping(struct fsa4480 *fsa)
199{
200 struct fwnode_handle *ep;
201 u32 data_lanes[DATA_LANES_COUNT];
202 int ret, i, j;
203
204 ep = fwnode_graph_get_next_endpoint(dev_fwnode(&fsa->client->dev), NULL);
205 if (!ep)
206 return 0;
207
208 ret = fwnode_property_read_u32_array(fwnode: ep, propname: "data-lanes", val: data_lanes, DATA_LANES_COUNT);
209 if (ret == -EINVAL)
210 /* Property isn't here, consider default mapping */
211 goto out_done;
212 if (ret) {
213 dev_err(&fsa->client->dev, "invalid data-lanes property: %d\n", ret);
214 goto out_error;
215 }
216
217 for (i = 0; i < ARRAY_SIZE(supported_data_lane_mapping); i++) {
218 for (j = 0; j < DATA_LANES_COUNT; j++) {
219 if (data_lanes[j] != supported_data_lane_mapping[i][j])
220 break;
221 }
222
223 if (j == DATA_LANES_COUNT)
224 break;
225 }
226
227 switch (i) {
228 case NORMAL_LANE_MAPPING:
229 break;
230 case INVERT_LANE_MAPPING:
231 fsa->swap_sbu_lanes = true;
232 break;
233 default:
234 dev_err(&fsa->client->dev, "invalid data-lanes mapping\n");
235 ret = -EINVAL;
236 goto out_error;
237 }
238
239out_done:
240 ret = 0;
241
242out_error:
243 fwnode_handle_put(fwnode: ep);
244
245 return ret;
246}
247
248static int fsa4480_probe(struct i2c_client *client)
249{
250 struct device *dev = &client->dev;
251 struct typec_switch_desc sw_desc = { };
252 struct typec_mux_desc mux_desc = { };
253 struct fsa4480 *fsa;
254 int ret;
255
256 fsa = devm_kzalloc(dev, size: sizeof(*fsa), GFP_KERNEL);
257 if (!fsa)
258 return -ENOMEM;
259
260 fsa->client = client;
261 mutex_init(&fsa->lock);
262
263 ret = fsa4480_parse_data_lanes_mapping(fsa);
264 if (ret)
265 return ret;
266
267 fsa->regmap = devm_regmap_init_i2c(client, &fsa4480_regmap_config);
268 if (IS_ERR(ptr: fsa->regmap))
269 return dev_err_probe(dev, err: PTR_ERR(ptr: fsa->regmap), fmt: "failed to initialize regmap\n");
270
271 /* Safe mode */
272 fsa->cur_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB;
273 fsa->mode = TYPEC_STATE_SAFE;
274 fsa->orientation = TYPEC_ORIENTATION_NONE;
275
276 /* set default settings */
277 regmap_write(map: fsa->regmap, FSA4480_SLOW_L, val: 0x00);
278 regmap_write(map: fsa->regmap, FSA4480_SLOW_R, val: 0x00);
279 regmap_write(map: fsa->regmap, FSA4480_SLOW_MIC, val: 0x00);
280 regmap_write(map: fsa->regmap, FSA4480_SLOW_SENSE, val: 0x00);
281 regmap_write(map: fsa->regmap, FSA4480_SLOW_GND, val: 0x00);
282 regmap_write(map: fsa->regmap, FSA4480_DELAY_L_R, val: 0x00);
283 regmap_write(map: fsa->regmap, FSA4480_DELAY_L_MIC, val: 0x00);
284 regmap_write(map: fsa->regmap, FSA4480_DELAY_L_SENSE, val: 0x00);
285 regmap_write(map: fsa->regmap, FSA4480_DELAY_L_AGND, val: 0x09);
286 regmap_write(map: fsa->regmap, FSA4480_SWITCH_SELECT, FSA4480_SEL_USB);
287 regmap_write(map: fsa->regmap, FSA4480_SWITCH_ENABLE, val: fsa->cur_enable);
288
289 sw_desc.drvdata = fsa;
290 sw_desc.fwnode = dev_fwnode(dev);
291 sw_desc.set = fsa4480_switch_set;
292
293 fsa->sw = typec_switch_register(parent: dev, desc: &sw_desc);
294 if (IS_ERR(ptr: fsa->sw))
295 return dev_err_probe(dev, err: PTR_ERR(ptr: fsa->sw), fmt: "failed to register typec switch\n");
296
297 mux_desc.drvdata = fsa;
298 mux_desc.fwnode = dev_fwnode(dev);
299 mux_desc.set = fsa4480_mux_set;
300
301 fsa->mux = typec_mux_register(parent: dev, desc: &mux_desc);
302 if (IS_ERR(ptr: fsa->mux)) {
303 typec_switch_unregister(sw: fsa->sw);
304 return dev_err_probe(dev, err: PTR_ERR(ptr: fsa->mux), fmt: "failed to register typec mux\n");
305 }
306
307 i2c_set_clientdata(client, data: fsa);
308 return 0;
309}
310
311static void fsa4480_remove(struct i2c_client *client)
312{
313 struct fsa4480 *fsa = i2c_get_clientdata(client);
314
315 typec_mux_unregister(mux: fsa->mux);
316 typec_switch_unregister(sw: fsa->sw);
317}
318
319static const struct i2c_device_id fsa4480_table[] = {
320 { "fsa4480" },
321 { }
322};
323MODULE_DEVICE_TABLE(i2c, fsa4480_table);
324
325static const struct of_device_id fsa4480_of_table[] = {
326 { .compatible = "fcs,fsa4480" },
327 { }
328};
329MODULE_DEVICE_TABLE(of, fsa4480_of_table);
330
331static struct i2c_driver fsa4480_driver = {
332 .driver = {
333 .name = "fsa4480",
334 .of_match_table = fsa4480_of_table,
335 },
336 .probe = fsa4480_probe,
337 .remove = fsa4480_remove,
338 .id_table = fsa4480_table,
339};
340module_i2c_driver(fsa4480_driver);
341
342MODULE_DESCRIPTION("ON Semiconductor FSA4480 driver");
343MODULE_LICENSE("GPL v2");
344

source code of linux/drivers/usb/typec/mux/fsa4480.c