File Index
Files and directories
Sign in
FILE

nb7vpq904m.c

File preview with syntax highlighting.

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