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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
148 static int qcom_pmic_typec_init(struct tcpc_dev *tcpc)
149 {
150 	return 0;
151 }
152 
153 #if IS_ENABLED(CONFIG_DRM)
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 
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
176 static int qcom_pmic_typec_init_drm(struct pmic_typec *tcpm)
177 {
178 	return 0;
179 }
180 #endif
181 
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 
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