1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * OnSemi NB7VPQ904M Type-C driver
4 *
5 * Copyright (C) 2023 Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
6 */
7#include <linux/i2c.h>
8#include <linux/mutex.h>
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/regmap.h>
12#include <linux/bitfield.h>
13#include <linux/of_graph.h>
14#include <drm/bridge/aux-bridge.h>
15#include <linux/usb/typec_dp.h>
16#include <linux/usb/typec_mux.h>
17#include <linux/usb/typec_retimer.h>
18#include <linux/gpio/consumer.h>
19#include <linux/regulator/consumer.h>
20
21#define NB7_CHNA 0
22#define NB7_CHNB 1
23#define NB7_CHNC 2
24#define NB7_CHND 3
25#define NB7_IS_CHAN_AD(channel) (channel == NB7_CHNA || channel == NB7_CHND)
26
27#define GEN_DEV_SET_REG 0x00
28
29#define GEN_DEV_SET_CHIP_EN BIT(0)
30#define GEN_DEV_SET_CHNA_EN BIT(4)
31#define GEN_DEV_SET_CHNB_EN BIT(5)
32#define GEN_DEV_SET_CHNC_EN BIT(6)
33#define GEN_DEV_SET_CHND_EN BIT(7)
34
35#define GEN_DEV_SET_OP_MODE_MASK GENMASK(3, 1)
36
37#define GEN_DEV_SET_OP_MODE_DP_CC2 0
38#define GEN_DEV_SET_OP_MODE_DP_CC1 1
39#define GEN_DEV_SET_OP_MODE_DP_4LANE 2
40#define GEN_DEV_SET_OP_MODE_USB 5
41
42#define EQ_SETTING_REG_BASE 0x01
43#define EQ_SETTING_REG(n) (EQ_SETTING_REG_BASE + (n) * 2)
44#define EQ_SETTING_MASK GENMASK(3, 1)
45
46#define OUTPUT_COMPRESSION_AND_POL_REG_BASE 0x02
47#define OUTPUT_COMPRESSION_AND_POL_REG(n) (OUTPUT_COMPRESSION_AND_POL_REG_BASE + (n) * 2)
48#define OUTPUT_COMPRESSION_MASK GENMASK(2, 1)
49
50#define FLAT_GAIN_REG_BASE 0x18
51#define FLAT_GAIN_REG(n) (FLAT_GAIN_REG_BASE + (n) * 2)
52#define FLAT_GAIN_MASK GENMASK(1, 0)
53
54#define LOSS_MATCH_REG_BASE 0x19
55#define LOSS_MATCH_REG(n) (LOSS_MATCH_REG_BASE + (n) * 2)
56#define LOSS_MATCH_MASK GENMASK(1, 0)
57
58#define AUX_CC_REG 0x09
59
60#define CHIP_VERSION_REG 0x17
61
62struct nb7vpq904m {
63 struct i2c_client *client;
64 struct gpio_desc *enable_gpio;
65 struct regulator *vcc_supply;
66 struct regmap *regmap;
67 struct typec_switch_dev *sw;
68 struct typec_retimer *retimer;
69
70 bool swap_data_lanes;
71 struct typec_switch *typec_switch;
72
73 struct mutex lock; /* protect non-concurrent retimer & switch */
74
75 enum typec_orientation orientation;
76 unsigned long mode;
77 unsigned int svid;
78};
79
80static void nb7vpq904m_set_channel(struct nb7vpq904m *nb7, unsigned int channel, bool dp)
81{
82 u8 eq, out_comp, flat_gain, loss_match;
83
84 if (dp) {
85 eq = NB7_IS_CHAN_AD(channel) ? 0x6 : 0x4;
86 out_comp = 0x3;
87 flat_gain = NB7_IS_CHAN_AD(channel) ? 0x2 : 0x1;
88 loss_match = 0x3;
89 } else {
90 eq = 0x4;
91 out_comp = 0x3;
92 flat_gain = NB7_IS_CHAN_AD(channel) ? 0x3 : 0x1;
93 loss_match = NB7_IS_CHAN_AD(channel) ? 0x1 : 0x3;
94 }
95
96 regmap_update_bits(map: nb7->regmap, EQ_SETTING_REG(channel),
97 EQ_SETTING_MASK, FIELD_PREP(EQ_SETTING_MASK, eq));
98 regmap_update_bits(map: nb7->regmap, OUTPUT_COMPRESSION_AND_POL_REG(channel),
99 OUTPUT_COMPRESSION_MASK, FIELD_PREP(OUTPUT_COMPRESSION_MASK, out_comp));
100 regmap_update_bits(map: nb7->regmap, FLAT_GAIN_REG(channel),
101 FLAT_GAIN_MASK, FIELD_PREP(FLAT_GAIN_MASK, flat_gain));
102 regmap_update_bits(map: nb7->regmap, LOSS_MATCH_REG(channel),
103 LOSS_MATCH_MASK, FIELD_PREP(LOSS_MATCH_MASK, loss_match));
104}
105
106static int nb7vpq904m_set(struct nb7vpq904m *nb7)
107{
108 bool reverse = (nb7->orientation == TYPEC_ORIENTATION_REVERSE);
109
110 switch (nb7->mode) {
111 case TYPEC_STATE_SAFE:
112 regmap_write(map: nb7->regmap, GEN_DEV_SET_REG,
113 GEN_DEV_SET_CHIP_EN |
114 GEN_DEV_SET_CHNA_EN |
115 GEN_DEV_SET_CHNB_EN |
116 GEN_DEV_SET_CHNC_EN |
117 GEN_DEV_SET_CHND_EN |
118 FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
119 GEN_DEV_SET_OP_MODE_USB));
120 nb7vpq904m_set_channel(nb7, NB7_CHNA, dp: false);
121 nb7vpq904m_set_channel(nb7, NB7_CHNB, dp: false);
122 nb7vpq904m_set_channel(nb7, NB7_CHNC, dp: false);
123 nb7vpq904m_set_channel(nb7, NB7_CHND, dp: false);
124 regmap_write(map: nb7->regmap, AUX_CC_REG, val: 0x2);
125
126 return 0;
127
128 case TYPEC_STATE_USB:
129 /*
130 * Normal Orientation (CC1)
131 * A -> USB RX
132 * B -> USB TX
133 * C -> X
134 * D -> X
135 * Flipped Orientation (CC2)
136 * A -> X
137 * B -> X
138 * C -> USB TX
139 * D -> USB RX
140 *
141 * Reversed if data lanes are swapped
142 */
143 if (reverse ^ nb7->swap_data_lanes) {
144 regmap_write(map: nb7->regmap, GEN_DEV_SET_REG,
145 GEN_DEV_SET_CHIP_EN |
146 GEN_DEV_SET_CHNA_EN |
147 GEN_DEV_SET_CHNB_EN |
148 FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
149 GEN_DEV_SET_OP_MODE_USB));
150 nb7vpq904m_set_channel(nb7, NB7_CHNA, dp: false);
151 nb7vpq904m_set_channel(nb7, NB7_CHNB, dp: false);
152 } else {
153 regmap_write(map: nb7->regmap, GEN_DEV_SET_REG,
154 GEN_DEV_SET_CHIP_EN |
155 GEN_DEV_SET_CHNC_EN |
156 GEN_DEV_SET_CHND_EN |
157 FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
158 GEN_DEV_SET_OP_MODE_USB));
159 nb7vpq904m_set_channel(nb7, NB7_CHNC, dp: false);
160 nb7vpq904m_set_channel(nb7, NB7_CHND, dp: false);
161 }
162 regmap_write(map: nb7->regmap, AUX_CC_REG, val: 0x2);
163
164 return 0;
165
166 default:
167 if (nb7->svid != USB_TYPEC_DP_SID)
168 return -EINVAL;
169
170 break;
171 }
172
173 /* DP Altmode Setup */
174
175 regmap_write(map: nb7->regmap, AUX_CC_REG, val: reverse ? 0x1 : 0x0);
176
177 switch (nb7->mode) {
178 case TYPEC_DP_STATE_C:
179 case TYPEC_DP_STATE_E:
180 /*
181 * Normal Orientation (CC1)
182 * A -> DP3
183 * B -> DP2
184 * C -> DP1
185 * D -> DP0
186 * Flipped Orientation (CC2)
187 * A -> DP0
188 * B -> DP1
189 * C -> DP2
190 * D -> DP3
191 */
192 regmap_write(map: nb7->regmap, GEN_DEV_SET_REG,
193 GEN_DEV_SET_CHIP_EN |
194 GEN_DEV_SET_CHNA_EN |
195 GEN_DEV_SET_CHNB_EN |
196 GEN_DEV_SET_CHNC_EN |
197 GEN_DEV_SET_CHND_EN |
198 FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
199 GEN_DEV_SET_OP_MODE_DP_4LANE));
200 nb7vpq904m_set_channel(nb7, NB7_CHNA, dp: true);
201 nb7vpq904m_set_channel(nb7, NB7_CHNB, dp: true);
202 nb7vpq904m_set_channel(nb7, NB7_CHNC, dp: true);
203 nb7vpq904m_set_channel(nb7, NB7_CHND, dp: true);
204 break;
205
206 case TYPEC_DP_STATE_D:
207 case TYPEC_DP_STATE_F:
208 regmap_write(map: nb7->regmap, GEN_DEV_SET_REG,
209 GEN_DEV_SET_CHIP_EN |
210 GEN_DEV_SET_CHNA_EN |
211 GEN_DEV_SET_CHNB_EN |
212 GEN_DEV_SET_CHNC_EN |
213 GEN_DEV_SET_CHND_EN |
214 FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
215 reverse ^ nb7->swap_data_lanes ?
216 GEN_DEV_SET_OP_MODE_DP_CC2
217 : GEN_DEV_SET_OP_MODE_DP_CC1));
218
219 /*
220 * Normal Orientation (CC1)
221 * A -> USB RX
222 * B -> USB TX
223 * C -> DP1
224 * D -> DP0
225 * Flipped Orientation (CC2)
226 * A -> DP0
227 * B -> DP1
228 * C -> USB TX
229 * D -> USB RX
230 *
231 * Reversed if data lanes are swapped
232 */
233 if (nb7->swap_data_lanes) {
234 nb7vpq904m_set_channel(nb7, NB7_CHNA, dp: !reverse);
235 nb7vpq904m_set_channel(nb7, NB7_CHNB, dp: !reverse);
236 nb7vpq904m_set_channel(nb7, NB7_CHNC, dp: reverse);
237 nb7vpq904m_set_channel(nb7, NB7_CHND, dp: reverse);
238 } else {
239 nb7vpq904m_set_channel(nb7, NB7_CHNA, dp: reverse);
240 nb7vpq904m_set_channel(nb7, NB7_CHNB, dp: reverse);
241 nb7vpq904m_set_channel(nb7, NB7_CHNC, dp: !reverse);
242 nb7vpq904m_set_channel(nb7, NB7_CHND, dp: !reverse);
243 }
244 break;
245
246 default:
247 return -EOPNOTSUPP;
248 }
249
250 return 0;
251}
252
253static int nb7vpq904m_sw_set(struct typec_switch_dev *sw, enum typec_orientation orientation)
254{
255 struct nb7vpq904m *nb7 = typec_switch_get_drvdata(sw);
256 int ret;
257
258 ret = typec_switch_set(sw: nb7->typec_switch, orientation);
259 if (ret)
260 return ret;
261
262 mutex_lock(&nb7->lock);
263
264 if (nb7->orientation != orientation) {
265 nb7->orientation = orientation;
266
267 ret = nb7vpq904m_set(nb7);
268 }
269
270 mutex_unlock(lock: &nb7->lock);
271
272 return ret;
273}
274
275static int nb7vpq904m_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
276{
277 struct nb7vpq904m *nb7 = typec_retimer_get_drvdata(retimer);
278 int ret = 0;
279
280 mutex_lock(&nb7->lock);
281
282 if (nb7->mode != state->mode) {
283 nb7->mode = state->mode;
284
285 if (state->alt)
286 nb7->svid = state->alt->svid;
287 else
288 nb7->svid = 0; // No SVID
289
290 ret = nb7vpq904m_set(nb7);
291 }
292
293 mutex_unlock(lock: &nb7->lock);
294
295 return ret;
296}
297
298static const struct regmap_config nb7_regmap = {
299 .max_register = 0x1f,
300 .reg_bits = 8,
301 .val_bits = 8,
302};
303
304enum {
305 NORMAL_LANE_MAPPING,
306 INVERT_LANE_MAPPING,
307};
308
309#define DATA_LANES_COUNT 4
310
311static const int supported_data_lane_mapping[][DATA_LANES_COUNT] = {
312 [NORMAL_LANE_MAPPING] = { 0, 1, 2, 3 },
313 [INVERT_LANE_MAPPING] = { 3, 2, 1, 0 },
314};
315
316static int nb7vpq904m_parse_data_lanes_mapping(struct nb7vpq904m *nb7)
317{
318 struct device_node *ep;
319 u32 data_lanes[4];
320 int ret, i, j;
321
322 ep = of_graph_get_endpoint_by_regs(parent: nb7->client->dev.of_node, port_reg: 1, reg: 0);
323
324 if (ep) {
325 ret = of_property_count_u32_elems(np: ep, propname: "data-lanes");
326 if (ret == -EINVAL)
327 /* Property isn't here, consider default mapping */
328 goto out_done;
329 if (ret < 0)
330 goto out_error;
331
332 if (ret != DATA_LANES_COUNT) {
333 dev_err(&nb7->client->dev, "expected 4 data lanes\n");
334 ret = -EINVAL;
335 goto out_error;
336 }
337
338 ret = of_property_read_u32_array(np: ep, propname: "data-lanes", out_values: data_lanes, DATA_LANES_COUNT);
339 if (ret)
340 goto out_error;
341
342 for (i = 0; i < ARRAY_SIZE(supported_data_lane_mapping); i++) {
343 for (j = 0; j < DATA_LANES_COUNT; j++) {
344 if (data_lanes[j] != supported_data_lane_mapping[i][j])
345 break;
346 }
347
348 if (j == DATA_LANES_COUNT)
349 break;
350 }
351
352 switch (i) {
353 case NORMAL_LANE_MAPPING:
354 break;
355 case INVERT_LANE_MAPPING:
356 nb7->swap_data_lanes = true;
357 dev_info(&nb7->client->dev, "using inverted data lanes mapping\n");
358 break;
359 default:
360 dev_err(&nb7->client->dev, "invalid data lanes mapping\n");
361 ret = -EINVAL;
362 goto out_error;
363 }
364 }
365
366out_done:
367 ret = 0;
368
369out_error:
370 of_node_put(node: ep);
371
372 return ret;
373}
374
375static int nb7vpq904m_probe(struct i2c_client *client)
376{
377 struct device *dev = &client->dev;
378 struct typec_switch_desc sw_desc = { };
379 struct typec_retimer_desc retimer_desc = { };
380 struct nb7vpq904m *nb7;
381 int ret;
382
383 nb7 = devm_kzalloc(dev, size: sizeof(*nb7), GFP_KERNEL);
384 if (!nb7)
385 return -ENOMEM;
386
387 nb7->client = client;
388
389 nb7->regmap = devm_regmap_init_i2c(client, &nb7_regmap);
390 if (IS_ERR(ptr: nb7->regmap)) {
391 dev_err(&client->dev, "Failed to allocate register map\n");
392 return PTR_ERR(ptr: nb7->regmap);
393 }
394
395 nb7->mode = TYPEC_STATE_SAFE;
396 nb7->orientation = TYPEC_ORIENTATION_NONE;
397
398 mutex_init(&nb7->lock);
399
400 nb7->enable_gpio = devm_gpiod_get_optional(dev, con_id: "enable", flags: GPIOD_OUT_LOW);
401 if (IS_ERR(ptr: nb7->enable_gpio))
402 return dev_err_probe(dev, err: PTR_ERR(ptr: nb7->enable_gpio),
403 fmt: "unable to acquire enable gpio\n");
404
405 nb7->vcc_supply = devm_regulator_get_optional(dev, id: "vcc");
406 if (IS_ERR(ptr: nb7->vcc_supply))
407 return PTR_ERR(ptr: nb7->vcc_supply);
408
409 nb7->typec_switch = fwnode_typec_switch_get(fwnode: dev->fwnode);
410 if (IS_ERR(ptr: nb7->typec_switch))
411 return dev_err_probe(dev, err: PTR_ERR(ptr: nb7->typec_switch),
412 fmt: "failed to acquire orientation-switch\n");
413
414 ret = nb7vpq904m_parse_data_lanes_mapping(nb7);
415 if (ret)
416 return ret;
417
418 ret = regulator_enable(regulator: nb7->vcc_supply);
419 if (ret)
420 dev_warn(dev, "Failed to enable vcc: %d\n", ret);
421
422 gpiod_set_value(desc: nb7->enable_gpio, value: 1);
423
424 ret = drm_aux_bridge_register(parent: dev);
425 if (ret)
426 goto err_disable_gpio;
427
428 sw_desc.drvdata = nb7;
429 sw_desc.fwnode = dev->fwnode;
430 sw_desc.set = nb7vpq904m_sw_set;
431
432 nb7->sw = typec_switch_register(parent: dev, desc: &sw_desc);
433 if (IS_ERR(ptr: nb7->sw)) {
434 ret = dev_err_probe(dev, err: PTR_ERR(ptr: nb7->sw),
435 fmt: "Error registering typec switch\n");
436 goto err_disable_gpio;
437 }
438
439 retimer_desc.drvdata = nb7;
440 retimer_desc.fwnode = dev->fwnode;
441 retimer_desc.set = nb7vpq904m_retimer_set;
442
443 nb7->retimer = typec_retimer_register(parent: dev, desc: &retimer_desc);
444 if (IS_ERR(ptr: nb7->retimer)) {
445 ret = dev_err_probe(dev, err: PTR_ERR(ptr: nb7->retimer),
446 fmt: "Error registering typec retimer\n");
447 goto err_switch_unregister;
448 }
449
450 return 0;
451
452err_switch_unregister:
453 typec_switch_unregister(sw: nb7->sw);
454
455err_disable_gpio:
456 gpiod_set_value(desc: nb7->enable_gpio, value: 0);
457 regulator_disable(regulator: nb7->vcc_supply);
458
459 return ret;
460}
461
462static void nb7vpq904m_remove(struct i2c_client *client)
463{
464 struct nb7vpq904m *nb7 = i2c_get_clientdata(client);
465
466 typec_retimer_unregister(retimer: nb7->retimer);
467 typec_switch_unregister(sw: nb7->sw);
468
469 gpiod_set_value(desc: nb7->enable_gpio, value: 0);
470
471 regulator_disable(regulator: nb7->vcc_supply);
472}
473
474static const struct i2c_device_id nb7vpq904m_table[] = {
475 { "nb7vpq904m" },
476 { }
477};
478MODULE_DEVICE_TABLE(i2c, nb7vpq904m_table);
479
480static const struct of_device_id nb7vpq904m_of_table[] = {
481 { .compatible = "onnn,nb7vpq904m" },
482 { }
483};
484MODULE_DEVICE_TABLE(of, nb7vpq904m_of_table);
485
486static struct i2c_driver nb7vpq904m_driver = {
487 .driver = {
488 .name = "nb7vpq904m",
489 .of_match_table = nb7vpq904m_of_table,
490 },
491 .probe = nb7vpq904m_probe,
492 .remove = nb7vpq904m_remove,
493 .id_table = nb7vpq904m_table,
494};
495
496module_i2c_driver(nb7vpq904m_driver);
497
498MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
499MODULE_DESCRIPTION("OnSemi NB7VPQ904M Type-C driver");
500MODULE_LICENSE("GPL");
501

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