1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2023, Linaro Ltd. All rights reserved.
4 */
5
6 #include <linux/err.h>
7 #include <linux/interrupt.h>
8 #include <linux/kernel.h>
9 #include <linux/mod_devicetable.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_graph.h>
13 #include <linux/platform_device.h>
14 #include <linux/regmap.h>
15 #include <linux/regulator/consumer.h>
16 #include <linux/slab.h>
17 #include <linux/usb/role.h>
18 #include <linux/usb/tcpm.h>
19 #include <linux/usb/typec_mux.h>
20
21 #include <drm/drm_bridge.h>
22
23 #include "qcom_pmic_typec_pdphy.h"
24 #include "qcom_pmic_typec_port.h"
25
26 struct pmic_typec_resources {
27 struct pmic_typec_pdphy_resources *pdphy_res;
28 struct pmic_typec_port_resources *port_res;
29 };
30
31 struct pmic_typec {
32 struct device *dev;
33 struct tcpm_port *tcpm_port;
34 struct tcpc_dev tcpc;
35 struct pmic_typec_pdphy *pmic_typec_pdphy;
36 struct pmic_typec_port *pmic_typec_port;
37 bool vbus_enabled;
38 struct mutex lock; /* VBUS state serialization */
39 struct drm_bridge bridge;
40 };
41
42 #define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc)
43
qcom_pmic_typec_get_vbus(struct tcpc_dev * tcpc)44 static int qcom_pmic_typec_get_vbus(struct tcpc_dev *tcpc)
45 {
46 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
47 int ret;
48
49 mutex_lock(&tcpm->lock);
50 ret = tcpm->vbus_enabled || qcom_pmic_typec_port_get_vbus(tcpm->pmic_typec_port);
51 mutex_unlock(&tcpm->lock);
52
53 return ret;
54 }
55
qcom_pmic_typec_set_vbus(struct tcpc_dev * tcpc,bool on,bool sink)56 static int qcom_pmic_typec_set_vbus(struct tcpc_dev *tcpc, bool on, bool sink)
57 {
58 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
59 int ret = 0;
60
61 mutex_lock(&tcpm->lock);
62 if (tcpm->vbus_enabled == on)
63 goto done;
64
65 ret = qcom_pmic_typec_port_set_vbus(tcpm->pmic_typec_port, on);
66 if (ret)
67 goto done;
68
69 tcpm->vbus_enabled = on;
70 tcpm_vbus_change(tcpm->tcpm_port);
71
72 done:
73 dev_dbg(tcpm->dev, "set_vbus set: %d result %d\n", on, ret);
74 mutex_unlock(&tcpm->lock);
75
76 return ret;
77 }
78
qcom_pmic_typec_set_vconn(struct tcpc_dev * tcpc,bool on)79 static int qcom_pmic_typec_set_vconn(struct tcpc_dev *tcpc, bool on)
80 {
81 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
82
83 return qcom_pmic_typec_port_set_vconn(tcpm->pmic_typec_port, on);
84 }
85
qcom_pmic_typec_get_cc(struct tcpc_dev * tcpc,enum typec_cc_status * cc1,enum typec_cc_status * cc2)86 static int qcom_pmic_typec_get_cc(struct tcpc_dev *tcpc,
87 enum typec_cc_status *cc1,
88 enum typec_cc_status *cc2)
89 {
90 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
91
92 return qcom_pmic_typec_port_get_cc(tcpm->pmic_typec_port, cc1, cc2);
93 }
94
qcom_pmic_typec_set_cc(struct tcpc_dev * tcpc,enum typec_cc_status cc)95 static int qcom_pmic_typec_set_cc(struct tcpc_dev *tcpc,
96 enum typec_cc_status cc)
97 {
98 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
99
100 return qcom_pmic_typec_port_set_cc(tcpm->pmic_typec_port, cc);
101 }
102
qcom_pmic_typec_set_polarity(struct tcpc_dev * tcpc,enum typec_cc_polarity pol)103 static int qcom_pmic_typec_set_polarity(struct tcpc_dev *tcpc,
104 enum typec_cc_polarity pol)
105 {
106 /* Polarity is set separately by phy-qcom-qmp.c */
107 return 0;
108 }
109
qcom_pmic_typec_start_toggling(struct tcpc_dev * tcpc,enum typec_port_type port_type,enum typec_cc_status cc)110 static int qcom_pmic_typec_start_toggling(struct tcpc_dev *tcpc,
111 enum typec_port_type port_type,
112 enum typec_cc_status cc)
113 {
114 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
115
116 return qcom_pmic_typec_port_start_toggling(tcpm->pmic_typec_port,
117 port_type, cc);
118 }
119
qcom_pmic_typec_set_roles(struct tcpc_dev * tcpc,bool attached,enum typec_role power_role,enum typec_data_role data_role)120 static int qcom_pmic_typec_set_roles(struct tcpc_dev *tcpc, bool attached,
121 enum typec_role power_role,
122 enum typec_data_role data_role)
123 {
124 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
125
126 return qcom_pmic_typec_pdphy_set_roles(tcpm->pmic_typec_pdphy,
127 data_role, power_role);
128 }
129
qcom_pmic_typec_set_pd_rx(struct tcpc_dev * tcpc,bool on)130 static int qcom_pmic_typec_set_pd_rx(struct tcpc_dev *tcpc, bool on)
131 {
132 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
133
134 return qcom_pmic_typec_pdphy_set_pd_rx(tcpm->pmic_typec_pdphy, on);
135 }
136
qcom_pmic_typec_pd_transmit(struct tcpc_dev * tcpc,enum tcpm_transmit_type type,const struct pd_message * msg,unsigned int negotiated_rev)137 static int qcom_pmic_typec_pd_transmit(struct tcpc_dev *tcpc,
138 enum tcpm_transmit_type type,
139 const struct pd_message *msg,
140 unsigned int negotiated_rev)
141 {
142 struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc);
143
144 return qcom_pmic_typec_pdphy_pd_transmit(tcpm->pmic_typec_pdphy, type,
145 msg, negotiated_rev);
146 }
147
qcom_pmic_typec_init(struct tcpc_dev * tcpc)148 static int qcom_pmic_typec_init(struct tcpc_dev *tcpc)
149 {
150 return 0;
151 }
152
153 #if IS_ENABLED(CONFIG_DRM)
qcom_pmic_typec_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)154 static int qcom_pmic_typec_attach(struct drm_bridge *bridge,
155 enum drm_bridge_attach_flags flags)
156 {
157 return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
158 }
159
160 static const struct drm_bridge_funcs qcom_pmic_typec_bridge_funcs = {
161 .attach = qcom_pmic_typec_attach,
162 };
163
qcom_pmic_typec_init_drm(struct pmic_typec * tcpm)164 static int qcom_pmic_typec_init_drm(struct pmic_typec *tcpm)
165 {
166 tcpm->bridge.funcs = &qcom_pmic_typec_bridge_funcs;
167 #ifdef CONFIG_OF
168 tcpm->bridge.of_node = of_get_child_by_name(tcpm->dev->of_node, "connector");
169 #endif
170 tcpm->bridge.ops = DRM_BRIDGE_OP_HPD;
171 tcpm->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
172
173 return devm_drm_bridge_add(tcpm->dev, &tcpm->bridge);
174 }
175 #else
qcom_pmic_typec_init_drm(struct pmic_typec * tcpm)176 static int qcom_pmic_typec_init_drm(struct pmic_typec *tcpm)
177 {
178 return 0;
179 }
180 #endif
181
qcom_pmic_typec_probe(struct platform_device * pdev)182 static int qcom_pmic_typec_probe(struct platform_device *pdev)
183 {
184 struct pmic_typec *tcpm;
185 struct device *dev = &pdev->dev;
186 struct device_node *np = dev->of_node;
187 const struct pmic_typec_resources *res;
188 struct regmap *regmap;
189 u32 base[2];
190 int ret;
191
192 res = of_device_get_match_data(dev);
193 if (!res)
194 return -ENODEV;
195
196 tcpm = devm_kzalloc(dev, sizeof(*tcpm), GFP_KERNEL);
197 if (!tcpm)
198 return -ENOMEM;
199
200 tcpm->dev = dev;
201 tcpm->tcpc.init = qcom_pmic_typec_init;
202 tcpm->tcpc.get_vbus = qcom_pmic_typec_get_vbus;
203 tcpm->tcpc.set_vbus = qcom_pmic_typec_set_vbus;
204 tcpm->tcpc.set_cc = qcom_pmic_typec_set_cc;
205 tcpm->tcpc.get_cc = qcom_pmic_typec_get_cc;
206 tcpm->tcpc.set_polarity = qcom_pmic_typec_set_polarity;
207 tcpm->tcpc.set_vconn = qcom_pmic_typec_set_vconn;
208 tcpm->tcpc.start_toggling = qcom_pmic_typec_start_toggling;
209 tcpm->tcpc.set_pd_rx = qcom_pmic_typec_set_pd_rx;
210 tcpm->tcpc.set_roles = qcom_pmic_typec_set_roles;
211 tcpm->tcpc.pd_transmit = qcom_pmic_typec_pd_transmit;
212
213 regmap = dev_get_regmap(dev->parent, NULL);
214 if (!regmap) {
215 dev_err(dev, "Failed to get regmap\n");
216 return -ENODEV;
217 }
218
219 ret = of_property_read_u32_array(np, "reg", base, 2);
220 if (ret)
221 return ret;
222
223 tcpm->pmic_typec_port = qcom_pmic_typec_port_alloc(dev);
224 if (IS_ERR(tcpm->pmic_typec_port))
225 return PTR_ERR(tcpm->pmic_typec_port);
226
227 tcpm->pmic_typec_pdphy = qcom_pmic_typec_pdphy_alloc(dev);
228 if (IS_ERR(tcpm->pmic_typec_pdphy))
229 return PTR_ERR(tcpm->pmic_typec_pdphy);
230
231 ret = qcom_pmic_typec_port_probe(pdev, tcpm->pmic_typec_port,
232 res->port_res, regmap, base[0]);
233 if (ret)
234 return ret;
235
236 ret = qcom_pmic_typec_pdphy_probe(pdev, tcpm->pmic_typec_pdphy,
237 res->pdphy_res, regmap, base[1]);
238 if (ret)
239 return ret;
240
241 mutex_init(&tcpm->lock);
242 platform_set_drvdata(pdev, tcpm);
243
244 ret = qcom_pmic_typec_init_drm(tcpm);
245 if (ret)
246 return ret;
247
248 tcpm->tcpc.fwnode = device_get_named_child_node(tcpm->dev, "connector");
249 if (!tcpm->tcpc.fwnode)
250 return -EINVAL;
251
252 tcpm->tcpm_port = tcpm_register_port(tcpm->dev, &tcpm->tcpc);
253 if (IS_ERR(tcpm->tcpm_port)) {
254 ret = PTR_ERR(tcpm->tcpm_port);
255 goto fwnode_remove;
256 }
257
258 ret = qcom_pmic_typec_port_start(tcpm->pmic_typec_port,
259 tcpm->tcpm_port);
260 if (ret)
261 goto fwnode_remove;
262
263 ret = qcom_pmic_typec_pdphy_start(tcpm->pmic_typec_pdphy,
264 tcpm->tcpm_port);
265 if (ret)
266 goto fwnode_remove;
267
268 return 0;
269
270 fwnode_remove:
271 fwnode_remove_software_node(tcpm->tcpc.fwnode);
272
273 return ret;
274 }
275
qcom_pmic_typec_remove(struct platform_device * pdev)276 static void qcom_pmic_typec_remove(struct platform_device *pdev)
277 {
278 struct pmic_typec *tcpm = platform_get_drvdata(pdev);
279
280 qcom_pmic_typec_pdphy_stop(tcpm->pmic_typec_pdphy);
281 qcom_pmic_typec_port_stop(tcpm->pmic_typec_port);
282 tcpm_unregister_port(tcpm->tcpm_port);
283 fwnode_remove_software_node(tcpm->tcpc.fwnode);
284 }
285
286 static struct pmic_typec_pdphy_resources pm8150b_pdphy_res = {
287 .irq_params = {
288 {
289 .virq = PMIC_PDPHY_SIG_TX_IRQ,
290 .irq_name = "sig-tx",
291 },
292 {
293 .virq = PMIC_PDPHY_SIG_RX_IRQ,
294 .irq_name = "sig-rx",
295 },
296 {
297 .virq = PMIC_PDPHY_MSG_TX_IRQ,
298 .irq_name = "msg-tx",
299 },
300 {
301 .virq = PMIC_PDPHY_MSG_RX_IRQ,
302 .irq_name = "msg-rx",
303 },
304 {
305 .virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ,
306 .irq_name = "msg-tx-failed",
307 },
308 {
309 .virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ,
310 .irq_name = "msg-tx-discarded",
311 },
312 {
313 .virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ,
314 .irq_name = "msg-rx-discarded",
315 },
316 },
317 .nr_irqs = 7,
318 };
319
320 static struct pmic_typec_port_resources pm8150b_port_res = {
321 .irq_params = {
322 {
323 .irq_name = "vpd-detect",
324 .virq = PMIC_TYPEC_VPD_IRQ,
325 },
326
327 {
328 .irq_name = "cc-state-change",
329 .virq = PMIC_TYPEC_CC_STATE_IRQ,
330 },
331 {
332 .irq_name = "vconn-oc",
333 .virq = PMIC_TYPEC_VCONN_OC_IRQ,
334 },
335
336 {
337 .irq_name = "vbus-change",
338 .virq = PMIC_TYPEC_VBUS_IRQ,
339 },
340
341 {
342 .irq_name = "attach-detach",
343 .virq = PMIC_TYPEC_ATTACH_DETACH_IRQ,
344 },
345 {
346 .irq_name = "legacy-cable-detect",
347 .virq = PMIC_TYPEC_LEGACY_CABLE_IRQ,
348 },
349
350 {
351 .irq_name = "try-snk-src-detect",
352 .virq = PMIC_TYPEC_TRY_SNK_SRC_IRQ,
353 },
354 },
355 .nr_irqs = 7,
356 };
357
358 static struct pmic_typec_resources pm8150b_typec_res = {
359 .pdphy_res = &pm8150b_pdphy_res,
360 .port_res = &pm8150b_port_res,
361 };
362
363 static const struct of_device_id qcom_pmic_typec_table[] = {
364 { .compatible = "qcom,pm8150b-typec", .data = &pm8150b_typec_res },
365 { }
366 };
367 MODULE_DEVICE_TABLE(of, qcom_pmic_typec_table);
368
369 static struct platform_driver qcom_pmic_typec_driver = {
370 .driver = {
371 .name = "qcom,pmic-typec",
372 .of_match_table = qcom_pmic_typec_table,
373 },
374 .probe = qcom_pmic_typec_probe,
375 .remove_new = qcom_pmic_typec_remove,
376 };
377
378 module_platform_driver(qcom_pmic_typec_driver);
379
380 MODULE_DESCRIPTION("QCOM PMIC USB Type-C Port Manager Driver");
381 MODULE_LICENSE("GPL");
382