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