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(map: 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(map: ptn->regmap, PTN36502_MODE_CTRL1_REG, val: 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(map: 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(map: ptn->regmap, PTN36502_MODE_CTRL1_REG, val: 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(map: ptn->regmap, PTN36502_DP_LINK_CTRL_REG, val: 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(map: ptn->regmap, PTN36502_DP_LANE_CTRL_REG(0), val: lane_ctrl_val); |
208 | regmap_write(map: ptn->regmap, PTN36502_DP_LANE_CTRL_REG(1), val: lane_ctrl_val); |
209 | regmap_write(map: ptn->regmap, PTN36502_DP_LANE_CTRL_REG(2), val: lane_ctrl_val); |
210 | regmap_write(map: ptn->regmap, PTN36502_DP_LANE_CTRL_REG(3), val: 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(sw: 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(lock: &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(lock: &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(map: ptn->regmap, PTN36502_CHIP_ID_REG, |
267 | val: ®_val); |
268 | if (ret < 0) |
269 | return dev_err_probe(dev, err: ret, fmt: "Failed to read chip ID\n" ); |
270 | |
271 | if (reg_val != PTN36502_CHIP_ID) |
272 | return dev_err_probe(dev, err: -ENODEV, fmt: "Unexpected chip ID: %x\n" , reg_val); |
273 | |
274 | ret = regmap_read(map: ptn->regmap, PTN36502_CHIP_REVISION_REG, |
275 | val: ®_val); |
276 | if (ret < 0) |
277 | return dev_err_probe(dev, err: ret, fmt: "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(dev: &ptn->client->dev, node: ptn->client->dev.of_node, port: 0, endpoint: 0); |
297 | if (IS_ERR(ptr: next_bridge)) { |
298 | dev_err(&ptn->client->dev, "failed to acquire drm_bridge: %pe\n" , next_bridge); |
299 | return PTR_ERR(ptr: next_bridge); |
300 | } |
301 | |
302 | return drm_bridge_attach(encoder: bridge->encoder, bridge: next_bridge, previous: bridge, |
303 | flags: 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(dev: &ptn->client->dev, bridge: &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, size: 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(ptr: ptn->regmap)) { |
346 | dev_err(&client->dev, "Failed to allocate register map\n" ); |
347 | return PTR_ERR(ptr: 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, id: "vdd18" ); |
356 | if (IS_ERR(ptr: ptn->vdd18_supply)) |
357 | return PTR_ERR(ptr: ptn->vdd18_supply); |
358 | |
359 | ptn->typec_switch = fwnode_typec_switch_get(fwnode: dev->fwnode); |
360 | if (IS_ERR(ptr: ptn->typec_switch)) |
361 | return dev_err_probe(dev, err: PTR_ERR(ptr: ptn->typec_switch), |
362 | fmt: "Failed to acquire orientation-switch\n" ); |
363 | |
364 | ret = regulator_enable(regulator: ptn->vdd18_supply); |
365 | if (ret) |
366 | return dev_err_probe(dev, err: ret, fmt: "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(parent: dev, desc: &sw_desc); |
381 | if (IS_ERR(ptr: ptn->sw)) { |
382 | ret = dev_err_probe(dev, err: PTR_ERR(ptr: ptn->sw), |
383 | fmt: "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(parent: dev, desc: &retimer_desc); |
392 | if (IS_ERR(ptr: ptn->retimer)) { |
393 | ret = dev_err_probe(dev, err: PTR_ERR(ptr: ptn->retimer), |
394 | fmt: "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(sw: ptn->sw); |
402 | |
403 | err_disable_regulator: |
404 | regulator_disable(regulator: 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(retimer: ptn->retimer); |
414 | typec_switch_unregister(sw: ptn->sw); |
415 | |
416 | regulator_disable(regulator: 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" ); |
445 | |