Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: typec: add support for PTN36502 redriver

Add a driver for the NXP PTN36502 Type-C USB 3.1 Gen 1 and DisplayPort
v1.2 combo redriver.

Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
Link: https://lore.kernel.org/r/20231020-ptn36502-v2-2-b37a337d463e@fairphone.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Luca Weiss and committed by
Greg Kroah-Hartman
8e99dc78 915360a5

+455
+10
drivers/usb/typec/mux/Kconfig
··· 46 46 Say Y or M if your system has a On Semiconductor NB7VPQ904M Type-C 47 47 redriver chip found on some devices with a Type-C port. 48 48 49 + config TYPEC_MUX_PTN36502 50 + tristate "NXP PTN36502 Type-C redriver driver" 51 + depends on I2C 52 + depends on DRM || DRM=n 53 + select DRM_PANEL_BRIDGE if DRM 54 + select REGMAP_I2C 55 + help 56 + Say Y or M if your system has a NXP PTN36502 Type-C redriver chip 57 + found on some devices with a Type-C port. 58 + 49 59 endmenu
+1
drivers/usb/typec/mux/Makefile
··· 5 5 obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o 6 6 obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o 7 7 obj-$(CONFIG_TYPEC_MUX_NB7VPQ904M) += nb7vpq904m.o 8 + obj-$(CONFIG_TYPEC_MUX_PTN36502) += ptn36502.o
+444
drivers/usb/typec/mux/ptn36502.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * NXP PTN36502 Type-C driver 4 + * 5 + * Copyright (C) 2023 Luca Weiss <luca.weiss@fairphone.com> 6 + * 7 + * Based on NB7VPQ904M driver: 8 + * Copyright (C) 2023 Dmitry Baryshkov <dmitry.baryshkov@linaro.org> 9 + */ 10 + 11 + #include <drm/drm_bridge.h> 12 + #include <linux/bitfield.h> 13 + #include <linux/i2c.h> 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/mutex.h> 17 + #include <linux/of_graph.h> 18 + #include <linux/regmap.h> 19 + #include <linux/regulator/consumer.h> 20 + #include <linux/usb/typec_dp.h> 21 + #include <linux/usb/typec_mux.h> 22 + #include <linux/usb/typec_retimer.h> 23 + 24 + #define PTN36502_CHIP_ID_REG 0x00 25 + #define PTN36502_CHIP_ID 0x02 26 + 27 + #define PTN36502_CHIP_REVISION_REG 0x01 28 + #define PTN36502_CHIP_REVISION_BASE_MASK GENMASK(7, 4) 29 + #define PTN36502_CHIP_REVISION_METAL_MASK GENMASK(3, 0) 30 + 31 + #define PTN36502_DP_LINK_CTRL_REG 0x06 32 + #define PTN36502_DP_LINK_CTRL_LANES_MASK GENMASK(3, 2) 33 + #define PTN36502_DP_LINK_CTRL_LANES_2 (2) 34 + #define PTN36502_DP_LINK_CTRL_LANES_4 (3) 35 + #define PTN36502_DP_LINK_CTRL_LINK_RATE_MASK GENMASK(1, 0) 36 + #define PTN36502_DP_LINK_CTRL_LINK_RATE_5_4GBPS (2) 37 + 38 + /* Registers for lane 0 (0x07) to lane 3 (0x0a) have the same layout */ 39 + #define PTN36502_DP_LANE_CTRL_REG(n) (0x07 + (n)) 40 + #define PTN36502_DP_LANE_CTRL_RX_GAIN_MASK GENMASK(6, 4) 41 + #define PTN36502_DP_LANE_CTRL_RX_GAIN_3DB (2) 42 + #define PTN36502_DP_LANE_CTRL_TX_SWING_MASK GENMASK(3, 2) 43 + #define PTN36502_DP_LANE_CTRL_TX_SWING_800MVPPD (2) 44 + #define PTN36502_DP_LANE_CTRL_PRE_EMPHASIS_MASK GENMASK(1, 0) 45 + #define PTN36502_DP_LANE_CTRL_PRE_EMPHASIS_3_5DB (1) 46 + 47 + #define PTN36502_MODE_CTRL1_REG 0x0b 48 + #define PTN36502_MODE_CTRL1_PLUG_ORIENT_MASK GENMASK(5, 5) 49 + #define PTN36502_MODE_CTRL1_PLUG_ORIENT_REVERSE (1) 50 + #define PTN36502_MODE_CTRL1_AUX_CROSSBAR_MASK GENMASK(3, 3) 51 + #define PTN36502_MODE_CTRL1_AUX_CROSSBAR_SW_ON (1) 52 + #define PTN36502_MODE_CTRL1_MODE_MASK GENMASK(2, 0) 53 + #define PTN36502_MODE_CTRL1_MODE_OFF (0) 54 + #define PTN36502_MODE_CTRL1_MODE_USB_ONLY (1) 55 + #define PTN36502_MODE_CTRL1_MODE_USB_DP (2) 56 + #define PTN36502_MODE_CTRL1_MODE_DP (3) 57 + 58 + #define PTN36502_DEVICE_CTRL_REG 0x0d 59 + #define PTN36502_DEVICE_CTRL_AUX_MONITORING_MASK GENMASK(7, 7) 60 + #define PTN36502_DEVICE_CTRL_AUX_MONITORING_EN (1) 61 + 62 + struct ptn36502 { 63 + struct i2c_client *client; 64 + struct regulator *vdd18_supply; 65 + struct regmap *regmap; 66 + struct typec_switch_dev *sw; 67 + struct typec_retimer *retimer; 68 + 69 + struct typec_switch *typec_switch; 70 + 71 + struct drm_bridge bridge; 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 + 80 + static int ptn36502_set(struct ptn36502 *ptn) 81 + { 82 + bool reverse = (ptn->orientation == TYPEC_ORIENTATION_REVERSE); 83 + unsigned int ctrl1_val = 0; 84 + unsigned int lane_ctrl_val = 0; 85 + unsigned int link_ctrl_val = 0; 86 + 87 + switch (ptn->mode) { 88 + case TYPEC_STATE_SAFE: 89 + /* Deep power saving state */ 90 + regmap_write(ptn->regmap, PTN36502_MODE_CTRL1_REG, 91 + FIELD_PREP(PTN36502_MODE_CTRL1_MODE_MASK, 92 + PTN36502_MODE_CTRL1_MODE_OFF)); 93 + return 0; 94 + 95 + case TYPEC_STATE_USB: 96 + /* 97 + * Normal Orientation (CC1) 98 + * A -> USB RX 99 + * B -> USB TX 100 + * C -> X 101 + * D -> X 102 + * Flipped Orientation (CC2) 103 + * A -> X 104 + * B -> X 105 + * C -> USB TX 106 + * D -> USB RX 107 + */ 108 + 109 + /* USB 3.1 Gen 1 only */ 110 + ctrl1_val = FIELD_PREP(PTN36502_MODE_CTRL1_MODE_MASK, 111 + PTN36502_MODE_CTRL1_MODE_USB_ONLY); 112 + if (reverse) 113 + ctrl1_val |= FIELD_PREP(PTN36502_MODE_CTRL1_PLUG_ORIENT_MASK, 114 + PTN36502_MODE_CTRL1_PLUG_ORIENT_REVERSE); 115 + 116 + regmap_write(ptn->regmap, PTN36502_MODE_CTRL1_REG, ctrl1_val); 117 + return 0; 118 + 119 + default: 120 + if (ptn->svid != USB_TYPEC_DP_SID) 121 + return -EINVAL; 122 + 123 + break; 124 + } 125 + 126 + /* DP Altmode Setup */ 127 + 128 + switch (ptn->mode) { 129 + case TYPEC_DP_STATE_C: 130 + case TYPEC_DP_STATE_E: 131 + /* 132 + * Normal Orientation (CC1) 133 + * A -> DP3 134 + * B -> DP2 135 + * C -> DP1 136 + * D -> DP0 137 + * Flipped Orientation (CC2) 138 + * A -> DP0 139 + * B -> DP1 140 + * C -> DP2 141 + * D -> DP3 142 + */ 143 + 144 + /* 4-lane DP */ 145 + ctrl1_val |= FIELD_PREP(PTN36502_MODE_CTRL1_MODE_MASK, 146 + PTN36502_MODE_CTRL1_MODE_DP); 147 + link_ctrl_val |= FIELD_PREP(PTN36502_DP_LINK_CTRL_LANES_MASK, 148 + PTN36502_DP_LINK_CTRL_LANES_4); 149 + break; 150 + 151 + case TYPEC_DP_STATE_D: 152 + case TYPEC_DP_STATE_F: /* State F is deprecated */ 153 + /* 154 + * Normal Orientation (CC1) 155 + * A -> USB RX 156 + * B -> USB TX 157 + * C -> DP1 158 + * D -> DP0 159 + * Flipped Orientation (CC2) 160 + * A -> DP0 161 + * B -> DP1 162 + * C -> USB TX 163 + * D -> USB RX 164 + */ 165 + 166 + /* USB 3.1 Gen 1 and 2-lane DP */ 167 + ctrl1_val |= FIELD_PREP(PTN36502_MODE_CTRL1_MODE_MASK, 168 + PTN36502_MODE_CTRL1_MODE_USB_DP); 169 + link_ctrl_val |= FIELD_PREP(PTN36502_DP_LINK_CTRL_LANES_MASK, 170 + PTN36502_DP_LINK_CTRL_LANES_2); 171 + break; 172 + 173 + default: 174 + return -EOPNOTSUPP; 175 + } 176 + 177 + /* Enable AUX monitoring */ 178 + regmap_write(ptn->regmap, PTN36502_DEVICE_CTRL_REG, 179 + FIELD_PREP(PTN36502_DEVICE_CTRL_AUX_MONITORING_MASK, 180 + PTN36502_DEVICE_CTRL_AUX_MONITORING_EN)); 181 + 182 + /* Enable AUX switch path */ 183 + ctrl1_val |= FIELD_PREP(PTN36502_MODE_CTRL1_AUX_CROSSBAR_MASK, 184 + PTN36502_MODE_CTRL1_AUX_CROSSBAR_SW_ON); 185 + if (reverse) 186 + ctrl1_val |= FIELD_PREP(PTN36502_MODE_CTRL1_PLUG_ORIENT_MASK, 187 + PTN36502_MODE_CTRL1_PLUG_ORIENT_REVERSE); 188 + regmap_write(ptn->regmap, PTN36502_MODE_CTRL1_REG, ctrl1_val); 189 + 190 + /* DP Link rate: 5.4 Gbps (HBR2) */ 191 + link_ctrl_val |= FIELD_PREP(PTN36502_DP_LINK_CTRL_LINK_RATE_MASK, 192 + PTN36502_DP_LINK_CTRL_LINK_RATE_5_4GBPS); 193 + regmap_write(ptn->regmap, PTN36502_DP_LINK_CTRL_REG, link_ctrl_val); 194 + 195 + /* 196 + * For all lanes: 197 + * - Rx equivalization gain: 3 dB 198 + * - TX output swing control: 800 mVppd 199 + * - Pre-emphasis control: 3.5 dB 200 + */ 201 + lane_ctrl_val = FIELD_PREP(PTN36502_DP_LANE_CTRL_RX_GAIN_MASK, 202 + PTN36502_DP_LANE_CTRL_RX_GAIN_3DB) | 203 + FIELD_PREP(PTN36502_DP_LANE_CTRL_TX_SWING_MASK, 204 + PTN36502_DP_LANE_CTRL_TX_SWING_800MVPPD) | 205 + FIELD_PREP(PTN36502_DP_LANE_CTRL_PRE_EMPHASIS_MASK, 206 + PTN36502_DP_LANE_CTRL_PRE_EMPHASIS_3_5DB); 207 + regmap_write(ptn->regmap, PTN36502_DP_LANE_CTRL_REG(0), lane_ctrl_val); 208 + regmap_write(ptn->regmap, PTN36502_DP_LANE_CTRL_REG(1), lane_ctrl_val); 209 + regmap_write(ptn->regmap, PTN36502_DP_LANE_CTRL_REG(2), lane_ctrl_val); 210 + regmap_write(ptn->regmap, PTN36502_DP_LANE_CTRL_REG(3), lane_ctrl_val); 211 + 212 + return 0; 213 + } 214 + 215 + static int ptn36502_sw_set(struct typec_switch_dev *sw, enum typec_orientation orientation) 216 + { 217 + struct ptn36502 *ptn = typec_switch_get_drvdata(sw); 218 + int ret; 219 + 220 + ret = typec_switch_set(ptn->typec_switch, orientation); 221 + if (ret) 222 + return ret; 223 + 224 + mutex_lock(&ptn->lock); 225 + 226 + if (ptn->orientation != orientation) { 227 + ptn->orientation = orientation; 228 + 229 + ret = ptn36502_set(ptn); 230 + } 231 + 232 + mutex_unlock(&ptn->lock); 233 + 234 + return ret; 235 + } 236 + 237 + static int ptn36502_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) 238 + { 239 + struct ptn36502 *ptn = typec_retimer_get_drvdata(retimer); 240 + int ret = 0; 241 + 242 + mutex_lock(&ptn->lock); 243 + 244 + if (ptn->mode != state->mode) { 245 + ptn->mode = state->mode; 246 + 247 + if (state->alt) 248 + ptn->svid = state->alt->svid; 249 + else 250 + ptn->svid = 0; // No SVID 251 + 252 + ret = ptn36502_set(ptn); 253 + } 254 + 255 + mutex_unlock(&ptn->lock); 256 + 257 + return ret; 258 + } 259 + 260 + static int ptn36502_detect(struct ptn36502 *ptn) 261 + { 262 + struct device *dev = &ptn->client->dev; 263 + unsigned int reg_val; 264 + int ret; 265 + 266 + ret = regmap_read(ptn->regmap, PTN36502_CHIP_ID_REG, 267 + &reg_val); 268 + if (ret < 0) 269 + return dev_err_probe(dev, ret, "Failed to read chip ID\n"); 270 + 271 + if (reg_val != PTN36502_CHIP_ID) 272 + return dev_err_probe(dev, -ENODEV, "Unexpected chip ID: %x\n", reg_val); 273 + 274 + ret = regmap_read(ptn->regmap, PTN36502_CHIP_REVISION_REG, 275 + &reg_val); 276 + if (ret < 0) 277 + return dev_err_probe(dev, ret, "Failed to read chip revision\n"); 278 + 279 + dev_dbg(dev, "Chip revision: base layer version %lx, metal layer version %lx\n", 280 + FIELD_GET(PTN36502_CHIP_REVISION_BASE_MASK, reg_val), 281 + FIELD_GET(PTN36502_CHIP_REVISION_METAL_MASK, reg_val)); 282 + 283 + return 0; 284 + } 285 + 286 + #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE) 287 + static int ptn36502_bridge_attach(struct drm_bridge *bridge, 288 + enum drm_bridge_attach_flags flags) 289 + { 290 + struct ptn36502 *ptn = container_of(bridge, struct ptn36502, bridge); 291 + struct drm_bridge *next_bridge; 292 + 293 + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) 294 + return -EINVAL; 295 + 296 + next_bridge = devm_drm_of_get_bridge(&ptn->client->dev, ptn->client->dev.of_node, 0, 0); 297 + if (IS_ERR(next_bridge)) { 298 + dev_err(&ptn->client->dev, "failed to acquire drm_bridge: %pe\n", next_bridge); 299 + return PTR_ERR(next_bridge); 300 + } 301 + 302 + return drm_bridge_attach(bridge->encoder, next_bridge, bridge, 303 + DRM_BRIDGE_ATTACH_NO_CONNECTOR); 304 + } 305 + 306 + static const struct drm_bridge_funcs ptn36502_bridge_funcs = { 307 + .attach = ptn36502_bridge_attach, 308 + }; 309 + 310 + static int ptn36502_register_bridge(struct ptn36502 *ptn) 311 + { 312 + ptn->bridge.funcs = &ptn36502_bridge_funcs; 313 + ptn->bridge.of_node = ptn->client->dev.of_node; 314 + 315 + return devm_drm_bridge_add(&ptn->client->dev, &ptn->bridge); 316 + } 317 + #else 318 + static int ptn36502_register_bridge(struct ptn36502 *ptn) 319 + { 320 + return 0; 321 + } 322 + #endif 323 + 324 + static const struct regmap_config ptn36502_regmap = { 325 + .max_register = 0x0d, 326 + .reg_bits = 8, 327 + .val_bits = 8, 328 + }; 329 + 330 + static int ptn36502_probe(struct i2c_client *client) 331 + { 332 + struct device *dev = &client->dev; 333 + struct typec_switch_desc sw_desc = { }; 334 + struct typec_retimer_desc retimer_desc = { }; 335 + struct ptn36502 *ptn; 336 + int ret; 337 + 338 + ptn = devm_kzalloc(dev, sizeof(*ptn), GFP_KERNEL); 339 + if (!ptn) 340 + return -ENOMEM; 341 + 342 + ptn->client = client; 343 + 344 + ptn->regmap = devm_regmap_init_i2c(client, &ptn36502_regmap); 345 + if (IS_ERR(ptn->regmap)) { 346 + dev_err(&client->dev, "Failed to allocate register map\n"); 347 + return PTR_ERR(ptn->regmap); 348 + } 349 + 350 + ptn->mode = TYPEC_STATE_SAFE; 351 + ptn->orientation = TYPEC_ORIENTATION_NONE; 352 + 353 + mutex_init(&ptn->lock); 354 + 355 + ptn->vdd18_supply = devm_regulator_get_optional(dev, "vdd18"); 356 + if (IS_ERR(ptn->vdd18_supply)) 357 + return PTR_ERR(ptn->vdd18_supply); 358 + 359 + ptn->typec_switch = fwnode_typec_switch_get(dev->fwnode); 360 + if (IS_ERR(ptn->typec_switch)) 361 + return dev_err_probe(dev, PTR_ERR(ptn->typec_switch), 362 + "Failed to acquire orientation-switch\n"); 363 + 364 + ret = regulator_enable(ptn->vdd18_supply); 365 + if (ret) 366 + return dev_err_probe(dev, ret, "Failed to enable vdd18\n"); 367 + 368 + ret = ptn36502_detect(ptn); 369 + if (ret) 370 + goto err_disable_regulator; 371 + 372 + ret = ptn36502_register_bridge(ptn); 373 + if (ret) 374 + goto err_disable_regulator; 375 + 376 + sw_desc.drvdata = ptn; 377 + sw_desc.fwnode = dev->fwnode; 378 + sw_desc.set = ptn36502_sw_set; 379 + 380 + ptn->sw = typec_switch_register(dev, &sw_desc); 381 + if (IS_ERR(ptn->sw)) { 382 + ret = dev_err_probe(dev, PTR_ERR(ptn->sw), 383 + "Failed to register typec switch\n"); 384 + goto err_disable_regulator; 385 + } 386 + 387 + retimer_desc.drvdata = ptn; 388 + retimer_desc.fwnode = dev->fwnode; 389 + retimer_desc.set = ptn36502_retimer_set; 390 + 391 + ptn->retimer = typec_retimer_register(dev, &retimer_desc); 392 + if (IS_ERR(ptn->retimer)) { 393 + ret = dev_err_probe(dev, PTR_ERR(ptn->retimer), 394 + "Failed to register typec retimer\n"); 395 + goto err_switch_unregister; 396 + } 397 + 398 + return 0; 399 + 400 + err_switch_unregister: 401 + typec_switch_unregister(ptn->sw); 402 + 403 + err_disable_regulator: 404 + regulator_disable(ptn->vdd18_supply); 405 + 406 + return ret; 407 + } 408 + 409 + static void ptn36502_remove(struct i2c_client *client) 410 + { 411 + struct ptn36502 *ptn = i2c_get_clientdata(client); 412 + 413 + typec_retimer_unregister(ptn->retimer); 414 + typec_switch_unregister(ptn->sw); 415 + 416 + regulator_disable(ptn->vdd18_supply); 417 + } 418 + 419 + static const struct i2c_device_id ptn36502_table[] = { 420 + { "ptn36502" }, 421 + { } 422 + }; 423 + MODULE_DEVICE_TABLE(i2c, ptn36502_table); 424 + 425 + static const struct of_device_id ptn36502_of_table[] = { 426 + { .compatible = "nxp,ptn36502" }, 427 + { } 428 + }; 429 + MODULE_DEVICE_TABLE(of, ptn36502_of_table); 430 + 431 + static struct i2c_driver ptn36502_driver = { 432 + .driver = { 433 + .name = "ptn36502", 434 + .of_match_table = ptn36502_of_table, 435 + }, 436 + .probe = ptn36502_probe, 437 + .remove = ptn36502_remove, 438 + .id_table = ptn36502_table, 439 + }; 440 + module_i2c_driver(ptn36502_driver); 441 + 442 + MODULE_AUTHOR("Luca Weiss <luca.weiss@fairphone.com>"); 443 + MODULE_DESCRIPTION("NXP PTN36502 Type-C driver"); 444 + MODULE_LICENSE("GPL");