1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2023, Linaro Ltd. All rights reserved. |
4 | */ |
5 | |
6 | #include <linux/delay.h> |
7 | #include <linux/err.h> |
8 | #include <linux/interrupt.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/mod_devicetable.h> |
11 | #include <linux/module.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/regulator/consumer.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/usb/tcpm.h> |
17 | #include <linux/usb/typec_mux.h> |
18 | #include <linux/workqueue.h> |
19 | |
20 | #include "qcom_pmic_typec.h" |
21 | #include "qcom_pmic_typec_port.h" |
22 | |
23 | #define TYPEC_SNK_STATUS_REG 0x06 |
24 | #define DETECTED_SNK_TYPE_MASK GENMASK(6, 0) |
25 | #define SNK_DAM_MASK GENMASK(6, 4) |
26 | #define SNK_DAM_500MA BIT(6) |
27 | #define SNK_DAM_1500MA BIT(5) |
28 | #define SNK_DAM_3000MA BIT(4) |
29 | #define SNK_RP_STD BIT(3) |
30 | #define SNK_RP_1P5 BIT(2) |
31 | #define SNK_RP_3P0 BIT(1) |
32 | #define SNK_RP_SHORT BIT(0) |
33 | |
34 | #define TYPEC_SRC_STATUS_REG 0x08 |
35 | #define DETECTED_SRC_TYPE_MASK GENMASK(4, 0) |
36 | #define SRC_HIGH_BATT BIT(5) |
37 | #define SRC_DEBUG_ACCESS BIT(4) |
38 | #define SRC_RD_OPEN BIT(3) |
39 | #define SRC_RD_RA_VCONN BIT(2) |
40 | #define SRC_RA_OPEN BIT(1) |
41 | #define AUDIO_ACCESS_RA_RA BIT(0) |
42 | |
43 | #define TYPEC_STATE_MACHINE_STATUS_REG 0x09 |
44 | #define TYPEC_ATTACH_DETACH_STATE BIT(5) |
45 | |
46 | #define TYPEC_SM_STATUS_REG 0x0A |
47 | #define TYPEC_SM_VBUS_VSAFE5V BIT(5) |
48 | #define TYPEC_SM_VBUS_VSAFE0V BIT(6) |
49 | #define TYPEC_SM_USBIN_LT_LV BIT(7) |
50 | |
51 | #define TYPEC_MISC_STATUS_REG 0x0B |
52 | #define TYPEC_WATER_DETECTION_STATUS BIT(7) |
53 | #define SNK_SRC_MODE BIT(6) |
54 | #define TYPEC_VBUS_DETECT BIT(5) |
55 | #define TYPEC_VBUS_ERROR_STATUS BIT(4) |
56 | #define TYPEC_DEBOUNCE_DONE BIT(3) |
57 | #define CC_ORIENTATION BIT(1) |
58 | #define CC_ATTACHED BIT(0) |
59 | |
60 | #define LEGACY_CABLE_STATUS_REG 0x0D |
61 | #define TYPEC_LEGACY_CABLE_STATUS BIT(1) |
62 | #define TYPEC_NONCOMP_LEGACY_CABLE_STATUS BIT(0) |
63 | |
64 | #define TYPEC_U_USB_STATUS_REG 0x0F |
65 | #define U_USB_GROUND_NOVBUS BIT(6) |
66 | #define U_USB_GROUND BIT(4) |
67 | #define U_USB_FMB1 BIT(3) |
68 | #define U_USB_FLOAT1 BIT(2) |
69 | #define U_USB_FMB2 BIT(1) |
70 | #define U_USB_FLOAT2 BIT(0) |
71 | |
72 | #define TYPEC_MODE_CFG_REG 0x44 |
73 | #define TYPEC_TRY_MODE_MASK GENMASK(4, 3) |
74 | #define EN_TRY_SNK BIT(4) |
75 | #define EN_TRY_SRC BIT(3) |
76 | #define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0) |
77 | #define EN_SRC_ONLY BIT(2) |
78 | #define EN_SNK_ONLY BIT(1) |
79 | #define TYPEC_DISABLE_CMD BIT(0) |
80 | |
81 | #define TYPEC_VCONN_CONTROL_REG 0x46 |
82 | #define VCONN_EN_ORIENTATION BIT(2) |
83 | #define VCONN_EN_VALUE BIT(1) |
84 | #define VCONN_EN_SRC BIT(0) |
85 | |
86 | #define TYPEC_CCOUT_CONTROL_REG 0x48 |
87 | #define TYPEC_CCOUT_BUFFER_EN BIT(2) |
88 | #define TYPEC_CCOUT_VALUE BIT(1) |
89 | #define TYPEC_CCOUT_SRC BIT(0) |
90 | |
91 | #define DEBUG_ACCESS_SRC_CFG_REG 0x4C |
92 | #define EN_UNORIENTED_DEBUG_ACCESS_SRC BIT(0) |
93 | |
94 | #define TYPE_C_CRUDE_SENSOR_CFG_REG 0x4e |
95 | #define EN_SRC_CRUDE_SENSOR BIT(1) |
96 | #define EN_SNK_CRUDE_SENSOR BIT(0) |
97 | |
98 | #define TYPEC_EXIT_STATE_CFG_REG 0x50 |
99 | #define BYPASS_VSAFE0V_DURING_ROLE_SWAP BIT(3) |
100 | #define SEL_SRC_UPPER_REF BIT(2) |
101 | #define USE_TPD_FOR_EXITING_ATTACHSRC BIT(1) |
102 | #define EXIT_SNK_BASED_ON_CC BIT(0) |
103 | |
104 | #define TYPEC_CURRSRC_CFG_REG 0x52 |
105 | #define TYPEC_SRC_RP_SEL_330UA BIT(1) |
106 | #define TYPEC_SRC_RP_SEL_180UA BIT(0) |
107 | #define TYPEC_SRC_RP_SEL_80UA 0 |
108 | #define TYPEC_SRC_RP_SEL_MASK GENMASK(1, 0) |
109 | |
110 | #define TYPEC_INTERRUPT_EN_CFG_1_REG 0x5E |
111 | #define TYPEC_LEGACY_CABLE_INT_EN BIT(7) |
112 | #define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN BIT(6) |
113 | #define TYPEC_TRYSOURCE_DETECT_INT_EN BIT(5) |
114 | #define TYPEC_TRYSINK_DETECT_INT_EN BIT(4) |
115 | #define TYPEC_CCOUT_DETACH_INT_EN BIT(3) |
116 | #define TYPEC_CCOUT_ATTACH_INT_EN BIT(2) |
117 | #define TYPEC_VBUS_DEASSERT_INT_EN BIT(1) |
118 | #define TYPEC_VBUS_ASSERT_INT_EN BIT(0) |
119 | |
120 | #define TYPEC_INTERRUPT_EN_CFG_2_REG 0x60 |
121 | #define TYPEC_SRC_BATT_HPWR_INT_EN BIT(6) |
122 | #define MICRO_USB_STATE_CHANGE_INT_EN BIT(5) |
123 | #define TYPEC_STATE_MACHINE_CHANGE_INT_EN BIT(4) |
124 | #define TYPEC_DEBUG_ACCESS_DETECT_INT_EN BIT(3) |
125 | #define TYPEC_WATER_DETECTION_INT_EN BIT(2) |
126 | #define TYPEC_VBUS_ERROR_INT_EN BIT(1) |
127 | #define TYPEC_DEBOUNCE_DONE_INT_EN BIT(0) |
128 | |
129 | #define TYPEC_DEBOUNCE_OPTION_REG 0x62 |
130 | #define REDUCE_TCCDEBOUNCE_TO_2MS BIT(2) |
131 | |
132 | #define TYPE_C_SBU_CFG_REG 0x6A |
133 | #define SEL_SBU1_ISRC_VAL 0x04 |
134 | #define SEL_SBU2_ISRC_VAL 0x01 |
135 | |
136 | #define TYPEC_U_USB_CFG_REG 0x70 |
137 | #define EN_MICRO_USB_FACTORY_MODE BIT(1) |
138 | #define EN_MICRO_USB_MODE BIT(0) |
139 | |
140 | #define TYPEC_PMI632_U_USB_WATER_PROTECTION_CFG_REG 0x72 |
141 | |
142 | #define TYPEC_U_USB_WATER_PROTECTION_CFG_REG 0x73 |
143 | #define EN_MICRO_USB_WATER_PROTECTION BIT(4) |
144 | #define MICRO_USB_DETECTION_ON_TIME_CFG_MASK GENMASK(3, 2) |
145 | #define MICRO_USB_DETECTION_PERIOD_CFG_MASK GENMASK(1, 0) |
146 | |
147 | #define TYPEC_PMI632_MICRO_USB_MODE_REG 0x73 |
148 | #define MICRO_USB_MODE_ONLY BIT(0) |
149 | |
150 | /* Interrupt numbers */ |
151 | #define PMIC_TYPEC_OR_RID_IRQ 0x0 |
152 | #define PMIC_TYPEC_VPD_IRQ 0x1 |
153 | #define PMIC_TYPEC_CC_STATE_IRQ 0x2 |
154 | #define PMIC_TYPEC_VCONN_OC_IRQ 0x3 |
155 | #define PMIC_TYPEC_VBUS_IRQ 0x4 |
156 | #define PMIC_TYPEC_ATTACH_DETACH_IRQ 0x5 |
157 | #define PMIC_TYPEC_LEGACY_CABLE_IRQ 0x6 |
158 | #define PMIC_TYPEC_TRY_SNK_SRC_IRQ 0x7 |
159 | |
160 | struct pmic_typec_port_irq_data { |
161 | int virq; |
162 | int irq; |
163 | struct pmic_typec_port *pmic_typec_port; |
164 | }; |
165 | |
166 | struct pmic_typec_port { |
167 | struct device *dev; |
168 | struct tcpm_port *tcpm_port; |
169 | struct regmap *regmap; |
170 | u32 base; |
171 | unsigned int nr_irqs; |
172 | struct pmic_typec_port_irq_data *irq_data; |
173 | |
174 | struct regulator *vdd_vbus; |
175 | bool vbus_enabled; |
176 | struct mutex vbus_lock; /* VBUS state serialization */ |
177 | |
178 | int cc; |
179 | bool debouncing_cc; |
180 | struct delayed_work cc_debounce_dwork; |
181 | |
182 | spinlock_t lock; /* Register atomicity */ |
183 | }; |
184 | |
185 | static const char * const typec_cc_status_name[] = { |
186 | [TYPEC_CC_OPEN] = "Open" , |
187 | [TYPEC_CC_RA] = "Ra" , |
188 | [TYPEC_CC_RD] = "Rd" , |
189 | [TYPEC_CC_RP_DEF] = "Rp-def" , |
190 | [TYPEC_CC_RP_1_5] = "Rp-1.5" , |
191 | [TYPEC_CC_RP_3_0] = "Rp-3.0" , |
192 | }; |
193 | |
194 | static const char *rp_unknown = "unknown" ; |
195 | |
196 | static const char *cc_to_name(enum typec_cc_status cc) |
197 | { |
198 | if (cc > TYPEC_CC_RP_3_0) |
199 | return rp_unknown; |
200 | |
201 | return typec_cc_status_name[cc]; |
202 | } |
203 | |
204 | static const char * const rp_sel_name[] = { |
205 | [TYPEC_SRC_RP_SEL_80UA] = "Rp-def-80uA" , |
206 | [TYPEC_SRC_RP_SEL_180UA] = "Rp-1.5-180uA" , |
207 | [TYPEC_SRC_RP_SEL_330UA] = "Rp-3.0-330uA" , |
208 | }; |
209 | |
210 | static const char *rp_sel_to_name(int rp_sel) |
211 | { |
212 | if (rp_sel > TYPEC_SRC_RP_SEL_330UA) |
213 | return rp_unknown; |
214 | |
215 | return rp_sel_name[rp_sel]; |
216 | } |
217 | |
218 | #define misc_to_cc(msic) !!(misc & CC_ORIENTATION) ? "cc1" : "cc2" |
219 | #define misc_to_vconn(msic) !!(misc & CC_ORIENTATION) ? "cc2" : "cc1" |
220 | |
221 | static void qcom_pmic_typec_port_cc_debounce(struct work_struct *work) |
222 | { |
223 | struct pmic_typec_port *pmic_typec_port = |
224 | container_of(work, struct pmic_typec_port, cc_debounce_dwork.work); |
225 | unsigned long flags; |
226 | |
227 | spin_lock_irqsave(&pmic_typec_port->lock, flags); |
228 | pmic_typec_port->debouncing_cc = false; |
229 | spin_unlock_irqrestore(lock: &pmic_typec_port->lock, flags); |
230 | |
231 | dev_dbg(pmic_typec_port->dev, "Debounce cc complete\n" ); |
232 | } |
233 | |
234 | static irqreturn_t pmic_typec_port_isr(int irq, void *dev_id) |
235 | { |
236 | struct pmic_typec_port_irq_data *irq_data = dev_id; |
237 | struct pmic_typec_port *pmic_typec_port = irq_data->pmic_typec_port; |
238 | u32 misc_stat; |
239 | bool vbus_change = false; |
240 | bool cc_change = false; |
241 | unsigned long flags; |
242 | int ret; |
243 | |
244 | spin_lock_irqsave(&pmic_typec_port->lock, flags); |
245 | |
246 | ret = regmap_read(map: pmic_typec_port->regmap, |
247 | reg: pmic_typec_port->base + TYPEC_MISC_STATUS_REG, |
248 | val: &misc_stat); |
249 | if (ret) |
250 | goto done; |
251 | |
252 | switch (irq_data->virq) { |
253 | case PMIC_TYPEC_VBUS_IRQ: |
254 | vbus_change = true; |
255 | break; |
256 | case PMIC_TYPEC_CC_STATE_IRQ: |
257 | case PMIC_TYPEC_ATTACH_DETACH_IRQ: |
258 | if (!pmic_typec_port->debouncing_cc) |
259 | cc_change = true; |
260 | break; |
261 | } |
262 | |
263 | done: |
264 | spin_unlock_irqrestore(lock: &pmic_typec_port->lock, flags); |
265 | |
266 | if (vbus_change) |
267 | tcpm_vbus_change(port: pmic_typec_port->tcpm_port); |
268 | |
269 | if (cc_change) |
270 | tcpm_cc_change(port: pmic_typec_port->tcpm_port); |
271 | |
272 | return IRQ_HANDLED; |
273 | } |
274 | |
275 | static int qcom_pmic_typec_port_vbus_detect(struct pmic_typec_port *pmic_typec_port) |
276 | { |
277 | struct device *dev = pmic_typec_port->dev; |
278 | unsigned int misc; |
279 | int ret; |
280 | |
281 | ret = regmap_read(map: pmic_typec_port->regmap, |
282 | reg: pmic_typec_port->base + TYPEC_MISC_STATUS_REG, |
283 | val: &misc); |
284 | if (ret) |
285 | misc = 0; |
286 | |
287 | dev_dbg(dev, "get_vbus: 0x%08x detect %d\n" , misc, !!(misc & TYPEC_VBUS_DETECT)); |
288 | |
289 | return !!(misc & TYPEC_VBUS_DETECT); |
290 | } |
291 | |
292 | static int qcom_pmic_typec_port_vbus_toggle(struct pmic_typec_port *pmic_typec_port, bool on) |
293 | { |
294 | u32 sm_stat; |
295 | u32 val; |
296 | int ret; |
297 | |
298 | if (on) { |
299 | ret = regulator_enable(regulator: pmic_typec_port->vdd_vbus); |
300 | if (ret) |
301 | return ret; |
302 | |
303 | val = TYPEC_SM_VBUS_VSAFE5V; |
304 | } else { |
305 | ret = regulator_disable(regulator: pmic_typec_port->vdd_vbus); |
306 | if (ret) |
307 | return ret; |
308 | |
309 | val = TYPEC_SM_VBUS_VSAFE0V; |
310 | } |
311 | |
312 | /* Poll waiting for transition to required vSafe5V or vSafe0V */ |
313 | ret = regmap_read_poll_timeout(pmic_typec_port->regmap, |
314 | pmic_typec_port->base + TYPEC_SM_STATUS_REG, |
315 | sm_stat, sm_stat & val, |
316 | 100, 250000); |
317 | if (ret) |
318 | dev_warn(pmic_typec_port->dev, "vbus vsafe%dv fail\n" , on ? 5 : 0); |
319 | |
320 | return 0; |
321 | } |
322 | |
323 | static int qcom_pmic_typec_port_get_vbus(struct tcpc_dev *tcpc) |
324 | { |
325 | struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); |
326 | struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; |
327 | int ret; |
328 | |
329 | mutex_lock(&pmic_typec_port->vbus_lock); |
330 | ret = pmic_typec_port->vbus_enabled || qcom_pmic_typec_port_vbus_detect(pmic_typec_port); |
331 | mutex_unlock(lock: &pmic_typec_port->vbus_lock); |
332 | |
333 | return ret; |
334 | } |
335 | |
336 | static int qcom_pmic_typec_port_set_vbus(struct tcpc_dev *tcpc, bool on, bool sink) |
337 | { |
338 | struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); |
339 | struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; |
340 | int ret = 0; |
341 | |
342 | mutex_lock(&pmic_typec_port->vbus_lock); |
343 | if (pmic_typec_port->vbus_enabled == on) |
344 | goto done; |
345 | |
346 | ret = qcom_pmic_typec_port_vbus_toggle(pmic_typec_port, on); |
347 | if (ret) |
348 | goto done; |
349 | |
350 | pmic_typec_port->vbus_enabled = on; |
351 | tcpm_vbus_change(port: tcpm->tcpm_port); |
352 | |
353 | done: |
354 | dev_dbg(tcpm->dev, "set_vbus set: %d result %d\n" , on, ret); |
355 | mutex_unlock(lock: &pmic_typec_port->vbus_lock); |
356 | |
357 | return ret; |
358 | } |
359 | |
360 | static int qcom_pmic_typec_port_get_cc(struct tcpc_dev *tcpc, |
361 | enum typec_cc_status *cc1, |
362 | enum typec_cc_status *cc2) |
363 | { |
364 | struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); |
365 | struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; |
366 | struct device *dev = pmic_typec_port->dev; |
367 | unsigned int misc, val; |
368 | bool attached; |
369 | int ret = 0; |
370 | |
371 | ret = regmap_read(map: pmic_typec_port->regmap, |
372 | reg: pmic_typec_port->base + TYPEC_MISC_STATUS_REG, val: &misc); |
373 | if (ret) |
374 | goto done; |
375 | |
376 | attached = !!(misc & CC_ATTACHED); |
377 | |
378 | if (pmic_typec_port->debouncing_cc) { |
379 | ret = -EBUSY; |
380 | goto done; |
381 | } |
382 | |
383 | *cc1 = TYPEC_CC_OPEN; |
384 | *cc2 = TYPEC_CC_OPEN; |
385 | |
386 | if (!attached) |
387 | goto done; |
388 | |
389 | if (misc & SNK_SRC_MODE) { |
390 | ret = regmap_read(map: pmic_typec_port->regmap, |
391 | reg: pmic_typec_port->base + TYPEC_SRC_STATUS_REG, |
392 | val: &val); |
393 | if (ret) |
394 | goto done; |
395 | switch (val & DETECTED_SRC_TYPE_MASK) { |
396 | case AUDIO_ACCESS_RA_RA: |
397 | val = TYPEC_CC_RA; |
398 | *cc1 = TYPEC_CC_RA; |
399 | *cc2 = TYPEC_CC_RA; |
400 | break; |
401 | case SRC_RD_OPEN: |
402 | val = TYPEC_CC_RD; |
403 | break; |
404 | case SRC_RD_RA_VCONN: |
405 | val = TYPEC_CC_RD; |
406 | *cc1 = TYPEC_CC_RA; |
407 | *cc2 = TYPEC_CC_RA; |
408 | break; |
409 | default: |
410 | dev_warn(dev, "unexpected src status %.2x\n" , val); |
411 | val = TYPEC_CC_RD; |
412 | break; |
413 | } |
414 | } else { |
415 | ret = regmap_read(map: pmic_typec_port->regmap, |
416 | reg: pmic_typec_port->base + TYPEC_SNK_STATUS_REG, |
417 | val: &val); |
418 | if (ret) |
419 | goto done; |
420 | switch (val & DETECTED_SNK_TYPE_MASK) { |
421 | case SNK_RP_STD: |
422 | val = TYPEC_CC_RP_DEF; |
423 | break; |
424 | case SNK_RP_1P5: |
425 | val = TYPEC_CC_RP_1_5; |
426 | break; |
427 | case SNK_RP_3P0: |
428 | val = TYPEC_CC_RP_3_0; |
429 | break; |
430 | default: |
431 | dev_warn(dev, "unexpected snk status %.2x\n" , val); |
432 | val = TYPEC_CC_RP_DEF; |
433 | break; |
434 | } |
435 | val = TYPEC_CC_RP_DEF; |
436 | } |
437 | |
438 | if (misc & CC_ORIENTATION) |
439 | *cc2 = val; |
440 | else |
441 | *cc1 = val; |
442 | |
443 | done: |
444 | dev_dbg(dev, "get_cc: misc 0x%08x cc1 0x%08x %s cc2 0x%08x %s attached %d cc=%s\n" , |
445 | misc, *cc1, cc_to_name(*cc1), *cc2, cc_to_name(*cc2), attached, |
446 | misc_to_cc(misc)); |
447 | |
448 | return ret; |
449 | } |
450 | |
451 | static void qcom_pmic_set_cc_debounce(struct pmic_typec_port *pmic_typec_port) |
452 | { |
453 | pmic_typec_port->debouncing_cc = true; |
454 | schedule_delayed_work(dwork: &pmic_typec_port->cc_debounce_dwork, |
455 | delay: msecs_to_jiffies(m: 2)); |
456 | } |
457 | |
458 | static int qcom_pmic_typec_port_set_cc(struct tcpc_dev *tcpc, |
459 | enum typec_cc_status cc) |
460 | { |
461 | struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); |
462 | struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; |
463 | struct device *dev = pmic_typec_port->dev; |
464 | unsigned int mode, currsrc; |
465 | unsigned int misc; |
466 | unsigned long flags; |
467 | int ret; |
468 | |
469 | spin_lock_irqsave(&pmic_typec_port->lock, flags); |
470 | |
471 | ret = regmap_read(map: pmic_typec_port->regmap, |
472 | reg: pmic_typec_port->base + TYPEC_MISC_STATUS_REG, |
473 | val: &misc); |
474 | if (ret) |
475 | goto done; |
476 | |
477 | mode = EN_SRC_ONLY; |
478 | |
479 | switch (cc) { |
480 | case TYPEC_CC_OPEN: |
481 | currsrc = TYPEC_SRC_RP_SEL_80UA; |
482 | break; |
483 | case TYPEC_CC_RP_DEF: |
484 | currsrc = TYPEC_SRC_RP_SEL_80UA; |
485 | break; |
486 | case TYPEC_CC_RP_1_5: |
487 | currsrc = TYPEC_SRC_RP_SEL_180UA; |
488 | break; |
489 | case TYPEC_CC_RP_3_0: |
490 | currsrc = TYPEC_SRC_RP_SEL_330UA; |
491 | break; |
492 | case TYPEC_CC_RD: |
493 | currsrc = TYPEC_SRC_RP_SEL_80UA; |
494 | mode = EN_SNK_ONLY; |
495 | break; |
496 | default: |
497 | dev_warn(dev, "unexpected set_cc %d\n" , cc); |
498 | ret = -EINVAL; |
499 | goto done; |
500 | } |
501 | |
502 | if (mode == EN_SRC_ONLY) { |
503 | ret = regmap_write(map: pmic_typec_port->regmap, |
504 | reg: pmic_typec_port->base + TYPEC_CURRSRC_CFG_REG, |
505 | val: currsrc); |
506 | if (ret) |
507 | goto done; |
508 | } |
509 | |
510 | pmic_typec_port->cc = cc; |
511 | qcom_pmic_set_cc_debounce(pmic_typec_port); |
512 | ret = 0; |
513 | |
514 | done: |
515 | spin_unlock_irqrestore(lock: &pmic_typec_port->lock, flags); |
516 | |
517 | dev_dbg(dev, "set_cc: currsrc=%x %s mode %s debounce %d attached %d cc=%s\n" , |
518 | currsrc, rp_sel_to_name(currsrc), |
519 | mode == EN_SRC_ONLY ? "EN_SRC_ONLY" : "EN_SNK_ONLY" , |
520 | pmic_typec_port->debouncing_cc, !!(misc & CC_ATTACHED), |
521 | misc_to_cc(misc)); |
522 | |
523 | return ret; |
524 | } |
525 | |
526 | static int qcom_pmic_typec_port_set_polarity(struct tcpc_dev *tcpc, |
527 | enum typec_cc_polarity pol) |
528 | { |
529 | /* Polarity is set separately by phy-qcom-qmp.c */ |
530 | return 0; |
531 | } |
532 | |
533 | static int qcom_pmic_typec_port_set_vconn(struct tcpc_dev *tcpc, bool on) |
534 | { |
535 | struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); |
536 | struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; |
537 | struct device *dev = pmic_typec_port->dev; |
538 | unsigned int orientation, misc, mask, value; |
539 | unsigned long flags; |
540 | int ret; |
541 | |
542 | spin_lock_irqsave(&pmic_typec_port->lock, flags); |
543 | |
544 | ret = regmap_read(map: pmic_typec_port->regmap, |
545 | reg: pmic_typec_port->base + TYPEC_MISC_STATUS_REG, val: &misc); |
546 | if (ret) |
547 | goto done; |
548 | |
549 | /* Set VCONN on the inversion of the active CC channel */ |
550 | orientation = (misc & CC_ORIENTATION) ? 0 : VCONN_EN_ORIENTATION; |
551 | if (on) { |
552 | mask = VCONN_EN_ORIENTATION | VCONN_EN_VALUE; |
553 | value = orientation | VCONN_EN_VALUE | VCONN_EN_SRC; |
554 | } else { |
555 | mask = VCONN_EN_VALUE; |
556 | value = 0; |
557 | } |
558 | |
559 | ret = regmap_update_bits(map: pmic_typec_port->regmap, |
560 | reg: pmic_typec_port->base + TYPEC_VCONN_CONTROL_REG, |
561 | mask, val: value); |
562 | done: |
563 | spin_unlock_irqrestore(lock: &pmic_typec_port->lock, flags); |
564 | |
565 | dev_dbg(dev, "set_vconn: orientation %d control 0x%08x state %s cc %s vconn %s\n" , |
566 | orientation, value, on ? "on" : "off" , misc_to_vconn(misc), misc_to_cc(misc)); |
567 | |
568 | return ret; |
569 | } |
570 | |
571 | static int qcom_pmic_typec_port_start_toggling(struct tcpc_dev *tcpc, |
572 | enum typec_port_type port_type, |
573 | enum typec_cc_status cc) |
574 | { |
575 | struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); |
576 | struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; |
577 | struct device *dev = pmic_typec_port->dev; |
578 | unsigned int misc; |
579 | u8 mode = 0; |
580 | unsigned long flags; |
581 | int ret; |
582 | |
583 | switch (port_type) { |
584 | case TYPEC_PORT_SRC: |
585 | mode = EN_SRC_ONLY; |
586 | break; |
587 | case TYPEC_PORT_SNK: |
588 | mode = EN_SNK_ONLY; |
589 | break; |
590 | case TYPEC_PORT_DRP: |
591 | mode = EN_TRY_SNK; |
592 | break; |
593 | } |
594 | |
595 | spin_lock_irqsave(&pmic_typec_port->lock, flags); |
596 | |
597 | ret = regmap_read(map: pmic_typec_port->regmap, |
598 | reg: pmic_typec_port->base + TYPEC_MISC_STATUS_REG, val: &misc); |
599 | if (ret) |
600 | goto done; |
601 | |
602 | dev_dbg(dev, "start_toggling: misc 0x%08x attached %d port_type %d current cc %d new %d\n" , |
603 | misc, !!(misc & CC_ATTACHED), port_type, pmic_typec_port->cc, cc); |
604 | |
605 | qcom_pmic_set_cc_debounce(pmic_typec_port); |
606 | |
607 | /* force it to toggle at least once */ |
608 | ret = regmap_write(map: pmic_typec_port->regmap, |
609 | reg: pmic_typec_port->base + TYPEC_MODE_CFG_REG, |
610 | TYPEC_DISABLE_CMD); |
611 | if (ret) |
612 | goto done; |
613 | |
614 | ret = regmap_write(map: pmic_typec_port->regmap, |
615 | reg: pmic_typec_port->base + TYPEC_MODE_CFG_REG, |
616 | val: mode); |
617 | done: |
618 | spin_unlock_irqrestore(lock: &pmic_typec_port->lock, flags); |
619 | |
620 | return ret; |
621 | } |
622 | |
623 | #define TYPEC_INTR_EN_CFG_1_MASK \ |
624 | (TYPEC_LEGACY_CABLE_INT_EN | \ |
625 | TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN | \ |
626 | TYPEC_TRYSOURCE_DETECT_INT_EN | \ |
627 | TYPEC_TRYSINK_DETECT_INT_EN | \ |
628 | TYPEC_CCOUT_DETACH_INT_EN | \ |
629 | TYPEC_CCOUT_ATTACH_INT_EN | \ |
630 | TYPEC_VBUS_DEASSERT_INT_EN | \ |
631 | TYPEC_VBUS_ASSERT_INT_EN) |
632 | |
633 | #define TYPEC_INTR_EN_CFG_2_MASK \ |
634 | (TYPEC_STATE_MACHINE_CHANGE_INT_EN | TYPEC_VBUS_ERROR_INT_EN | \ |
635 | TYPEC_DEBOUNCE_DONE_INT_EN) |
636 | |
637 | static int qcom_pmic_typec_port_start(struct pmic_typec *tcpm, |
638 | struct tcpm_port *tcpm_port) |
639 | { |
640 | struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; |
641 | int i; |
642 | int mask; |
643 | int ret; |
644 | |
645 | /* Configure interrupt sources */ |
646 | ret = regmap_write(map: pmic_typec_port->regmap, |
647 | reg: pmic_typec_port->base + TYPEC_INTERRUPT_EN_CFG_1_REG, |
648 | TYPEC_INTR_EN_CFG_1_MASK); |
649 | if (ret) |
650 | goto done; |
651 | |
652 | ret = regmap_write(map: pmic_typec_port->regmap, |
653 | reg: pmic_typec_port->base + TYPEC_INTERRUPT_EN_CFG_2_REG, |
654 | TYPEC_INTR_EN_CFG_2_MASK); |
655 | if (ret) |
656 | goto done; |
657 | |
658 | /* start in TRY_SNK mode */ |
659 | ret = regmap_write(map: pmic_typec_port->regmap, |
660 | reg: pmic_typec_port->base + TYPEC_MODE_CFG_REG, EN_TRY_SNK); |
661 | if (ret) |
662 | goto done; |
663 | |
664 | /* Configure VCONN for software control */ |
665 | ret = regmap_update_bits(map: pmic_typec_port->regmap, |
666 | reg: pmic_typec_port->base + TYPEC_VCONN_CONTROL_REG, |
667 | VCONN_EN_SRC | VCONN_EN_VALUE, VCONN_EN_SRC); |
668 | if (ret) |
669 | goto done; |
670 | |
671 | /* Set CC threshold to 1.6 Volts | tPDdebounce = 10-20ms */ |
672 | mask = SEL_SRC_UPPER_REF | USE_TPD_FOR_EXITING_ATTACHSRC; |
673 | ret = regmap_update_bits(map: pmic_typec_port->regmap, |
674 | reg: pmic_typec_port->base + TYPEC_EXIT_STATE_CFG_REG, |
675 | mask, val: mask); |
676 | if (ret) |
677 | goto done; |
678 | |
679 | pmic_typec_port->tcpm_port = tcpm_port; |
680 | |
681 | for (i = 0; i < pmic_typec_port->nr_irqs; i++) |
682 | enable_irq(irq: pmic_typec_port->irq_data[i].irq); |
683 | |
684 | done: |
685 | return ret; |
686 | } |
687 | |
688 | static void qcom_pmic_typec_port_stop(struct pmic_typec *tcpm) |
689 | { |
690 | struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; |
691 | int i; |
692 | |
693 | for (i = 0; i < pmic_typec_port->nr_irqs; i++) |
694 | disable_irq(irq: pmic_typec_port->irq_data[i].irq); |
695 | } |
696 | |
697 | int qcom_pmic_typec_port_probe(struct platform_device *pdev, |
698 | struct pmic_typec *tcpm, |
699 | const struct pmic_typec_port_resources *res, |
700 | struct regmap *regmap, |
701 | u32 base) |
702 | { |
703 | struct device *dev = &pdev->dev; |
704 | struct pmic_typec_port_irq_data *irq_data; |
705 | struct pmic_typec_port *pmic_typec_port; |
706 | int i, ret, irq; |
707 | |
708 | pmic_typec_port = devm_kzalloc(dev, size: sizeof(*pmic_typec_port), GFP_KERNEL); |
709 | if (!pmic_typec_port) |
710 | return -ENOMEM; |
711 | |
712 | if (!res->nr_irqs || res->nr_irqs > PMIC_TYPEC_MAX_IRQS) |
713 | return -EINVAL; |
714 | |
715 | irq_data = devm_kzalloc(dev, size: sizeof(*irq_data) * res->nr_irqs, |
716 | GFP_KERNEL); |
717 | if (!irq_data) |
718 | return -ENOMEM; |
719 | |
720 | mutex_init(&pmic_typec_port->vbus_lock); |
721 | |
722 | pmic_typec_port->vdd_vbus = devm_regulator_get(dev, id: "vdd-vbus" ); |
723 | if (IS_ERR(ptr: pmic_typec_port->vdd_vbus)) |
724 | return PTR_ERR(ptr: pmic_typec_port->vdd_vbus); |
725 | |
726 | pmic_typec_port->dev = dev; |
727 | pmic_typec_port->base = base; |
728 | pmic_typec_port->regmap = regmap; |
729 | pmic_typec_port->nr_irqs = res->nr_irqs; |
730 | pmic_typec_port->irq_data = irq_data; |
731 | spin_lock_init(&pmic_typec_port->lock); |
732 | INIT_DELAYED_WORK(&pmic_typec_port->cc_debounce_dwork, |
733 | qcom_pmic_typec_port_cc_debounce); |
734 | |
735 | irq = platform_get_irq(pdev, 0); |
736 | if (irq < 0) |
737 | return irq; |
738 | |
739 | for (i = 0; i < res->nr_irqs; i++, irq_data++) { |
740 | irq = platform_get_irq_byname(pdev, |
741 | res->irq_params[i].irq_name); |
742 | if (irq < 0) |
743 | return irq; |
744 | |
745 | irq_data->pmic_typec_port = pmic_typec_port; |
746 | irq_data->irq = irq; |
747 | irq_data->virq = res->irq_params[i].virq; |
748 | ret = devm_request_threaded_irq(dev, irq, NULL, thread_fn: pmic_typec_port_isr, |
749 | IRQF_ONESHOT | IRQF_NO_AUTOEN, |
750 | devname: res->irq_params[i].irq_name, |
751 | dev_id: irq_data); |
752 | if (ret) |
753 | return ret; |
754 | } |
755 | |
756 | tcpm->pmic_typec_port = pmic_typec_port; |
757 | |
758 | tcpm->tcpc.get_vbus = qcom_pmic_typec_port_get_vbus; |
759 | tcpm->tcpc.set_vbus = qcom_pmic_typec_port_set_vbus; |
760 | tcpm->tcpc.set_cc = qcom_pmic_typec_port_set_cc; |
761 | tcpm->tcpc.get_cc = qcom_pmic_typec_port_get_cc; |
762 | tcpm->tcpc.set_polarity = qcom_pmic_typec_port_set_polarity; |
763 | tcpm->tcpc.set_vconn = qcom_pmic_typec_port_set_vconn; |
764 | tcpm->tcpc.start_toggling = qcom_pmic_typec_port_start_toggling; |
765 | |
766 | tcpm->port_start = qcom_pmic_typec_port_start; |
767 | tcpm->port_stop = qcom_pmic_typec_port_stop; |
768 | |
769 | return 0; |
770 | } |
771 | |
772 | const struct pmic_typec_port_resources pm8150b_port_res = { |
773 | .irq_params = { |
774 | { |
775 | .irq_name = "vpd-detect" , |
776 | .virq = PMIC_TYPEC_VPD_IRQ, |
777 | }, |
778 | |
779 | { |
780 | .irq_name = "cc-state-change" , |
781 | .virq = PMIC_TYPEC_CC_STATE_IRQ, |
782 | }, |
783 | { |
784 | .irq_name = "vconn-oc" , |
785 | .virq = PMIC_TYPEC_VCONN_OC_IRQ, |
786 | }, |
787 | |
788 | { |
789 | .irq_name = "vbus-change" , |
790 | .virq = PMIC_TYPEC_VBUS_IRQ, |
791 | }, |
792 | |
793 | { |
794 | .irq_name = "attach-detach" , |
795 | .virq = PMIC_TYPEC_ATTACH_DETACH_IRQ, |
796 | }, |
797 | { |
798 | .irq_name = "legacy-cable-detect" , |
799 | .virq = PMIC_TYPEC_LEGACY_CABLE_IRQ, |
800 | }, |
801 | |
802 | { |
803 | .irq_name = "try-snk-src-detect" , |
804 | .virq = PMIC_TYPEC_TRY_SNK_SRC_IRQ, |
805 | }, |
806 | }, |
807 | .nr_irqs = 7, |
808 | }; |
809 | |