Merge tag '6.6-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
[sfrench/cifs-2.6.git] / drivers / usb / typec / mux / nb7vpq904m.c
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/drm_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
62 struct 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 drm_bridge bridge;
74
75         struct mutex lock; /* protect non-concurrent retimer & switch */
76
77         enum typec_orientation orientation;
78         unsigned long mode;
79         unsigned int svid;
80 };
81
82 static void nb7vpq904m_set_channel(struct nb7vpq904m *nb7, unsigned int channel, bool dp)
83 {
84         u8 eq, out_comp, flat_gain, loss_match;
85
86         if (dp) {
87                 eq = NB7_IS_CHAN_AD(channel) ? 0x6 : 0x4;
88                 out_comp = 0x3;
89                 flat_gain = NB7_IS_CHAN_AD(channel) ? 0x2 : 0x1;
90                 loss_match = 0x3;
91         } else {
92                 eq = 0x4;
93                 out_comp = 0x3;
94                 flat_gain = NB7_IS_CHAN_AD(channel) ? 0x3 : 0x1;
95                 loss_match = NB7_IS_CHAN_AD(channel) ? 0x1 : 0x3;
96         }
97
98         regmap_update_bits(nb7->regmap, EQ_SETTING_REG(channel),
99                            EQ_SETTING_MASK, FIELD_PREP(EQ_SETTING_MASK, eq));
100         regmap_update_bits(nb7->regmap, OUTPUT_COMPRESSION_AND_POL_REG(channel),
101                            OUTPUT_COMPRESSION_MASK, FIELD_PREP(OUTPUT_COMPRESSION_MASK, out_comp));
102         regmap_update_bits(nb7->regmap, FLAT_GAIN_REG(channel),
103                            FLAT_GAIN_MASK, FIELD_PREP(FLAT_GAIN_MASK, flat_gain));
104         regmap_update_bits(nb7->regmap, LOSS_MATCH_REG(channel),
105                            LOSS_MATCH_MASK, FIELD_PREP(LOSS_MATCH_MASK, loss_match));
106 }
107
108 static int nb7vpq904m_set(struct nb7vpq904m *nb7)
109 {
110         bool reverse = (nb7->orientation == TYPEC_ORIENTATION_REVERSE);
111
112         switch (nb7->mode) {
113         case TYPEC_STATE_SAFE:
114                 regmap_write(nb7->regmap, GEN_DEV_SET_REG,
115                              GEN_DEV_SET_CHIP_EN |
116                              GEN_DEV_SET_CHNA_EN |
117                              GEN_DEV_SET_CHNB_EN |
118                              GEN_DEV_SET_CHNC_EN |
119                              GEN_DEV_SET_CHND_EN |
120                              FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
121                                         GEN_DEV_SET_OP_MODE_USB));
122                 nb7vpq904m_set_channel(nb7, NB7_CHNA, false);
123                 nb7vpq904m_set_channel(nb7, NB7_CHNB, false);
124                 nb7vpq904m_set_channel(nb7, NB7_CHNC, false);
125                 nb7vpq904m_set_channel(nb7, NB7_CHND, false);
126                 regmap_write(nb7->regmap, AUX_CC_REG, 0x2);
127
128                 return 0;
129
130         case TYPEC_STATE_USB:
131                 /*
132                  * Normal Orientation (CC1)
133                  * A -> USB RX
134                  * B -> USB TX
135                  * C -> X
136                  * D -> X
137                  * Flipped Orientation (CC2)
138                  * A -> X
139                  * B -> X
140                  * C -> USB TX
141                  * D -> USB RX
142                  *
143                  * Reversed if data lanes are swapped
144                  */
145                 if (reverse ^ nb7->swap_data_lanes) {
146                         regmap_write(nb7->regmap, GEN_DEV_SET_REG,
147                                      GEN_DEV_SET_CHIP_EN |
148                                      GEN_DEV_SET_CHNA_EN |
149                                      GEN_DEV_SET_CHNB_EN |
150                                      FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
151                                                 GEN_DEV_SET_OP_MODE_USB));
152                         nb7vpq904m_set_channel(nb7, NB7_CHNA, false);
153                         nb7vpq904m_set_channel(nb7, NB7_CHNB, false);
154                 } else {
155                         regmap_write(nb7->regmap, GEN_DEV_SET_REG,
156                                      GEN_DEV_SET_CHIP_EN |
157                                      GEN_DEV_SET_CHNC_EN |
158                                      GEN_DEV_SET_CHND_EN |
159                                      FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
160                                                 GEN_DEV_SET_OP_MODE_USB));
161                         nb7vpq904m_set_channel(nb7, NB7_CHNC, false);
162                         nb7vpq904m_set_channel(nb7, NB7_CHND, false);
163                 }
164                 regmap_write(nb7->regmap, AUX_CC_REG, 0x2);
165
166                 return 0;
167
168         default:
169                 if (nb7->svid != USB_TYPEC_DP_SID)
170                         return -EINVAL;
171
172                 break;
173         }
174
175         /* DP Altmode Setup */
176
177         regmap_write(nb7->regmap, AUX_CC_REG, reverse ? 0x1 : 0x0);
178
179         switch (nb7->mode) {
180         case TYPEC_DP_STATE_C:
181         case TYPEC_DP_STATE_E:
182                 /*
183                  * Normal Orientation (CC1)
184                  * A -> DP3
185                  * B -> DP2
186                  * C -> DP1
187                  * D -> DP0
188                  * Flipped Orientation (CC2)
189                  * A -> DP0
190                  * B -> DP1
191                  * C -> DP2
192                  * D -> DP3
193                  */
194                 regmap_write(nb7->regmap, GEN_DEV_SET_REG,
195                              GEN_DEV_SET_CHIP_EN |
196                              GEN_DEV_SET_CHNA_EN |
197                              GEN_DEV_SET_CHNB_EN |
198                              GEN_DEV_SET_CHNC_EN |
199                              GEN_DEV_SET_CHND_EN |
200                              FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
201                                         GEN_DEV_SET_OP_MODE_DP_4LANE));
202                 nb7vpq904m_set_channel(nb7, NB7_CHNA, true);
203                 nb7vpq904m_set_channel(nb7, NB7_CHNB, true);
204                 nb7vpq904m_set_channel(nb7, NB7_CHNC, true);
205                 nb7vpq904m_set_channel(nb7, NB7_CHND, true);
206                 break;
207
208         case TYPEC_DP_STATE_D:
209         case TYPEC_DP_STATE_F:
210                 regmap_write(nb7->regmap, GEN_DEV_SET_REG,
211                              GEN_DEV_SET_CHIP_EN |
212                              GEN_DEV_SET_CHNA_EN |
213                              GEN_DEV_SET_CHNB_EN |
214                              GEN_DEV_SET_CHNC_EN |
215                              GEN_DEV_SET_CHND_EN |
216                              FIELD_PREP(GEN_DEV_SET_OP_MODE_MASK,
217                                         reverse ^ nb7->swap_data_lanes ?
218                                                 GEN_DEV_SET_OP_MODE_DP_CC2
219                                                 : GEN_DEV_SET_OP_MODE_DP_CC1));
220
221                 /*
222                  * Normal Orientation (CC1)
223                  * A -> USB RX
224                  * B -> USB TX
225                  * C -> DP1
226                  * D -> DP0
227                  * Flipped Orientation (CC2)
228                  * A -> DP0
229                  * B -> DP1
230                  * C -> USB TX
231                  * D -> USB RX
232                  *
233                  * Reversed if data lanes are swapped
234                  */
235                 if (nb7->swap_data_lanes) {
236                         nb7vpq904m_set_channel(nb7, NB7_CHNA, !reverse);
237                         nb7vpq904m_set_channel(nb7, NB7_CHNB, !reverse);
238                         nb7vpq904m_set_channel(nb7, NB7_CHNC, reverse);
239                         nb7vpq904m_set_channel(nb7, NB7_CHND, reverse);
240                 } else {
241                         nb7vpq904m_set_channel(nb7, NB7_CHNA, reverse);
242                         nb7vpq904m_set_channel(nb7, NB7_CHNB, reverse);
243                         nb7vpq904m_set_channel(nb7, NB7_CHNC, !reverse);
244                         nb7vpq904m_set_channel(nb7, NB7_CHND, !reverse);
245                 }
246                 break;
247
248         default:
249                 return -EOPNOTSUPP;
250         }
251
252         return 0;
253 }
254
255 static int nb7vpq904m_sw_set(struct typec_switch_dev *sw, enum typec_orientation orientation)
256 {
257         struct nb7vpq904m *nb7 = typec_switch_get_drvdata(sw);
258         int ret;
259
260         ret = typec_switch_set(nb7->typec_switch, orientation);
261         if (ret)
262                 return ret;
263
264         mutex_lock(&nb7->lock);
265
266         if (nb7->orientation != orientation) {
267                 nb7->orientation = orientation;
268
269                 ret = nb7vpq904m_set(nb7);
270         }
271
272         mutex_unlock(&nb7->lock);
273
274         return ret;
275 }
276
277 static int nb7vpq904m_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
278 {
279         struct nb7vpq904m *nb7 = typec_retimer_get_drvdata(retimer);
280         int ret = 0;
281
282         mutex_lock(&nb7->lock);
283
284         if (nb7->mode != state->mode) {
285                 nb7->mode = state->mode;
286
287                 if (state->alt)
288                         nb7->svid = state->alt->svid;
289                 else
290                         nb7->svid = 0; // No SVID
291
292                 ret = nb7vpq904m_set(nb7);
293         }
294
295         mutex_unlock(&nb7->lock);
296
297         return ret;
298 }
299
300 #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE)
301 static int nb7vpq904m_bridge_attach(struct drm_bridge *bridge,
302                                     enum drm_bridge_attach_flags flags)
303 {
304         struct nb7vpq904m *nb7 = container_of(bridge, struct nb7vpq904m, bridge);
305         struct drm_bridge *next_bridge;
306
307         if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
308                 return -EINVAL;
309
310         next_bridge = devm_drm_of_get_bridge(&nb7->client->dev, nb7->client->dev.of_node, 0, 0);
311         if (IS_ERR(next_bridge)) {
312                 dev_err(&nb7->client->dev, "failed to acquire drm_bridge: %pe\n", next_bridge);
313                 return PTR_ERR(next_bridge);
314         }
315
316         return drm_bridge_attach(bridge->encoder, next_bridge, bridge,
317                                  DRM_BRIDGE_ATTACH_NO_CONNECTOR);
318 }
319
320 static const struct drm_bridge_funcs nb7vpq904m_bridge_funcs = {
321         .attach = nb7vpq904m_bridge_attach,
322 };
323
324 static int nb7vpq904m_register_bridge(struct nb7vpq904m *nb7)
325 {
326         nb7->bridge.funcs = &nb7vpq904m_bridge_funcs;
327         nb7->bridge.of_node = nb7->client->dev.of_node;
328
329         return devm_drm_bridge_add(&nb7->client->dev, &nb7->bridge);
330 }
331 #else
332 static int nb7vpq904m_register_bridge(struct nb7vpq904m *nb7)
333 {
334         return 0;
335 }
336 #endif
337
338 static const struct regmap_config nb7_regmap = {
339         .max_register = 0x1f,
340         .reg_bits = 8,
341         .val_bits = 8,
342 };
343
344 enum {
345         NORMAL_LANE_MAPPING,
346         INVERT_LANE_MAPPING,
347 };
348
349 #define DATA_LANES_COUNT        4
350
351 static const int supported_data_lane_mapping[][DATA_LANES_COUNT] = {
352         [NORMAL_LANE_MAPPING] = { 0, 1, 2, 3 },
353         [INVERT_LANE_MAPPING] = { 3, 2, 1, 0 },
354 };
355
356 static int nb7vpq904m_parse_data_lanes_mapping(struct nb7vpq904m *nb7)
357 {
358         struct device_node *ep;
359         u32 data_lanes[4];
360         int ret, i, j;
361
362         ep = of_graph_get_endpoint_by_regs(nb7->client->dev.of_node, 1, 0);
363
364         if (ep) {
365                 ret = of_property_count_u32_elems(ep, "data-lanes");
366                 if (ret == -EINVAL)
367                         /* Property isn't here, consider default mapping */
368                         goto out_done;
369                 if (ret < 0)
370                         goto out_error;
371
372                 if (ret != DATA_LANES_COUNT) {
373                         dev_err(&nb7->client->dev, "expected 4 data lanes\n");
374                         ret = -EINVAL;
375                         goto out_error;
376                 }
377
378                 ret = of_property_read_u32_array(ep, "data-lanes", data_lanes, DATA_LANES_COUNT);
379                 if (ret)
380                         goto out_error;
381
382                 for (i = 0; i < ARRAY_SIZE(supported_data_lane_mapping); i++) {
383                         for (j = 0; j < DATA_LANES_COUNT; j++) {
384                                 if (data_lanes[j] != supported_data_lane_mapping[i][j])
385                                         break;
386                         }
387
388                         if (j == DATA_LANES_COUNT)
389                                 break;
390                 }
391
392                 switch (i) {
393                 case NORMAL_LANE_MAPPING:
394                         break;
395                 case INVERT_LANE_MAPPING:
396                         nb7->swap_data_lanes = true;
397                         dev_info(&nb7->client->dev, "using inverted data lanes mapping\n");
398                         break;
399                 default:
400                         dev_err(&nb7->client->dev, "invalid data lanes mapping\n");
401                         ret = -EINVAL;
402                         goto out_error;
403                 }
404         }
405
406 out_done:
407         ret = 0;
408
409 out_error:
410         of_node_put(ep);
411
412         return ret;
413 }
414
415 static int nb7vpq904m_probe(struct i2c_client *client)
416 {
417         struct device *dev = &client->dev;
418         struct typec_switch_desc sw_desc = { };
419         struct typec_retimer_desc retimer_desc = { };
420         struct nb7vpq904m *nb7;
421         int ret;
422
423         nb7 = devm_kzalloc(dev, sizeof(*nb7), GFP_KERNEL);
424         if (!nb7)
425                 return -ENOMEM;
426
427         nb7->client = client;
428
429         nb7->regmap = devm_regmap_init_i2c(client, &nb7_regmap);
430         if (IS_ERR(nb7->regmap)) {
431                 dev_err(&client->dev, "Failed to allocate register map\n");
432                 return PTR_ERR(nb7->regmap);
433         }
434
435         nb7->mode = TYPEC_STATE_SAFE;
436         nb7->orientation = TYPEC_ORIENTATION_NONE;
437
438         mutex_init(&nb7->lock);
439
440         nb7->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
441         if (IS_ERR(nb7->enable_gpio))
442                 return dev_err_probe(dev, PTR_ERR(nb7->enable_gpio),
443                                      "unable to acquire enable gpio\n");
444
445         nb7->vcc_supply = devm_regulator_get_optional(dev, "vcc");
446         if (IS_ERR(nb7->vcc_supply))
447                 return PTR_ERR(nb7->vcc_supply);
448
449         nb7->typec_switch = fwnode_typec_switch_get(dev->fwnode);
450         if (IS_ERR(nb7->typec_switch))
451                 return dev_err_probe(dev, PTR_ERR(nb7->typec_switch),
452                                      "failed to acquire orientation-switch\n");
453
454         ret = nb7vpq904m_parse_data_lanes_mapping(nb7);
455         if (ret)
456                 return ret;
457
458         ret = regulator_enable(nb7->vcc_supply);
459         if (ret)
460                 dev_warn(dev, "Failed to enable vcc: %d\n", ret);
461
462         gpiod_set_value(nb7->enable_gpio, 1);
463
464         ret = nb7vpq904m_register_bridge(nb7);
465         if (ret)
466                 goto err_disable_gpio;
467
468         sw_desc.drvdata = nb7;
469         sw_desc.fwnode = dev->fwnode;
470         sw_desc.set = nb7vpq904m_sw_set;
471
472         nb7->sw = typec_switch_register(dev, &sw_desc);
473         if (IS_ERR(nb7->sw)) {
474                 ret = dev_err_probe(dev, PTR_ERR(nb7->sw),
475                                     "Error registering typec switch\n");
476                 goto err_disable_gpio;
477         }
478
479         retimer_desc.drvdata = nb7;
480         retimer_desc.fwnode = dev->fwnode;
481         retimer_desc.set = nb7vpq904m_retimer_set;
482
483         nb7->retimer = typec_retimer_register(dev, &retimer_desc);
484         if (IS_ERR(nb7->retimer)) {
485                 ret = dev_err_probe(dev, PTR_ERR(nb7->retimer),
486                                     "Error registering typec retimer\n");
487                 goto err_switch_unregister;
488         }
489
490         return 0;
491
492 err_switch_unregister:
493         typec_switch_unregister(nb7->sw);
494
495 err_disable_gpio:
496         gpiod_set_value(nb7->enable_gpio, 0);
497         regulator_disable(nb7->vcc_supply);
498
499         return ret;
500 }
501
502 static void nb7vpq904m_remove(struct i2c_client *client)
503 {
504         struct nb7vpq904m *nb7 = i2c_get_clientdata(client);
505
506         typec_retimer_unregister(nb7->retimer);
507         typec_switch_unregister(nb7->sw);
508
509         gpiod_set_value(nb7->enable_gpio, 0);
510
511         regulator_disable(nb7->vcc_supply);
512 }
513
514 static const struct i2c_device_id nb7vpq904m_table[] = {
515         { "nb7vpq904m" },
516         { }
517 };
518 MODULE_DEVICE_TABLE(i2c, nb7vpq904m_table);
519
520 static const struct of_device_id nb7vpq904m_of_table[] = {
521         { .compatible = "onnn,nb7vpq904m" },
522         { }
523 };
524 MODULE_DEVICE_TABLE(of, nb7vpq904m_of_table);
525
526 static struct i2c_driver nb7vpq904m_driver = {
527         .driver = {
528                 .name = "nb7vpq904m",
529                 .of_match_table = nb7vpq904m_of_table,
530         },
531         .probe          = nb7vpq904m_probe,
532         .remove         = nb7vpq904m_remove,
533         .id_table       = nb7vpq904m_table,
534 };
535
536 module_i2c_driver(nb7vpq904m_driver);
537
538 MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
539 MODULE_DESCRIPTION("OnSemi NB7VPQ904M Type-C driver");
540 MODULE_LICENSE("GPL");