FILE
nb7vpq904m.c
File preview with syntax highlighting.
linux-6.19.14/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/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.