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 | bool swap_sbu_lanes; |
64 | }; |
65 | |
66 | static 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 | |
74 | static 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 | |
144 | static 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 | |
163 | static 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 | |
186 | enum { |
187 | NORMAL_LANE_MAPPING, |
188 | INVERT_LANE_MAPPING, |
189 | }; |
190 | |
191 | #define DATA_LANES_COUNT 2 |
192 | |
193 | static const int supported_data_lane_mapping[][DATA_LANES_COUNT] = { |
194 | [NORMAL_LANE_MAPPING] = { 0, 1 }, |
195 | [INVERT_LANE_MAPPING] = { 1, 0 }, |
196 | }; |
197 | |
198 | static 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 | |
239 | out_done: |
240 | ret = 0; |
241 | |
242 | out_error: |
243 | fwnode_handle_put(fwnode: ep); |
244 | |
245 | return ret; |
246 | } |
247 | |
248 | static 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 | |
311 | static 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 | |
319 | static const struct i2c_device_id fsa4480_table[] = { |
320 | { "fsa4480" }, |
321 | { } |
322 | }; |
323 | MODULE_DEVICE_TABLE(i2c, fsa4480_table); |
324 | |
325 | static const struct of_device_id fsa4480_of_table[] = { |
326 | { .compatible = "fcs,fsa4480" }, |
327 | { } |
328 | }; |
329 | MODULE_DEVICE_TABLE(of, fsa4480_of_table); |
330 | |
331 | static 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 | }; |
340 | module_i2c_driver(fsa4480_driver); |
341 | |
342 | MODULE_DESCRIPTION("ON Semiconductor FSA4480 driver" ); |
343 | MODULE_LICENSE("GPL v2" ); |
344 | |