Commit | Line | Data |
---|---|---|
62b5412b NA |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* | |
3 | * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. | |
4 | * Copyright (c) 2023, Linaro Ltd | |
5 | */ | |
6 | #include <linux/auxiliary_bus.h> | |
7 | #include <linux/module.h> | |
62b5412b | 8 | #include <linux/mutex.h> |
1d103d6a | 9 | #include <linux/of_device.h> |
62b5412b NA |
10 | #include <linux/property.h> |
11 | #include <linux/soc/qcom/pdr.h> | |
c6165ed2 NA |
12 | #include <linux/usb/typec_mux.h> |
13 | #include <linux/gpio/consumer.h> | |
62b5412b NA |
14 | #include <linux/soc/qcom/pmic_glink.h> |
15 | #include "ucsi.h" | |
16 | ||
c6165ed2 NA |
17 | #define PMIC_GLINK_MAX_PORTS 2 |
18 | ||
62b5412b NA |
19 | #define UCSI_BUF_SIZE 48 |
20 | ||
21 | #define MSG_TYPE_REQ_RESP 1 | |
22 | #define UCSI_BUF_SIZE 48 | |
23 | ||
24 | #define UC_NOTIFY_RECEIVER_UCSI 0x0 | |
25 | #define UC_UCSI_READ_BUF_REQ 0x11 | |
26 | #define UC_UCSI_WRITE_BUF_REQ 0x12 | |
27 | #define UC_UCSI_USBC_NOTIFY_IND 0x13 | |
28 | ||
29 | struct ucsi_read_buf_req_msg { | |
30 | struct pmic_glink_hdr hdr; | |
31 | }; | |
32 | ||
33 | struct ucsi_read_buf_resp_msg { | |
34 | struct pmic_glink_hdr hdr; | |
35 | u8 buf[UCSI_BUF_SIZE]; | |
36 | u32 ret_code; | |
37 | }; | |
38 | ||
39 | struct ucsi_write_buf_req_msg { | |
40 | struct pmic_glink_hdr hdr; | |
41 | u8 buf[UCSI_BUF_SIZE]; | |
42 | u32 reserved; | |
43 | }; | |
44 | ||
45 | struct ucsi_write_buf_resp_msg { | |
46 | struct pmic_glink_hdr hdr; | |
47 | u32 ret_code; | |
48 | }; | |
49 | ||
50 | struct ucsi_notify_ind_msg { | |
51 | struct pmic_glink_hdr hdr; | |
52 | u32 notification; | |
53 | u32 receiver; | |
54 | u32 reserved; | |
55 | }; | |
56 | ||
57 | struct pmic_glink_ucsi { | |
58 | struct device *dev; | |
59 | ||
c6165ed2 NA |
60 | struct gpio_desc *port_orientation[PMIC_GLINK_MAX_PORTS]; |
61 | struct typec_switch *port_switch[PMIC_GLINK_MAX_PORTS]; | |
62 | ||
62b5412b NA |
63 | struct pmic_glink_client *client; |
64 | ||
65 | struct ucsi *ucsi; | |
66 | struct completion read_ack; | |
67 | struct completion write_ack; | |
68 | struct completion sync_ack; | |
69 | bool sync_pending; | |
70 | struct mutex lock; /* protects concurrent access to PMIC Glink interface */ | |
71 | ||
72 | int sync_val; | |
73 | ||
74 | struct work_struct notify_work; | |
75 | struct work_struct register_work; | |
76 | ||
77 | u8 read_buf[UCSI_BUF_SIZE]; | |
78 | }; | |
79 | ||
80 | static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, | |
81 | void *val, size_t val_len) | |
82 | { | |
83 | struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); | |
84 | struct ucsi_read_buf_req_msg req = {}; | |
85 | unsigned long left; | |
86 | int ret; | |
87 | ||
88 | req.hdr.owner = PMIC_GLINK_OWNER_USBC; | |
89 | req.hdr.type = MSG_TYPE_REQ_RESP; | |
90 | req.hdr.opcode = UC_UCSI_READ_BUF_REQ; | |
91 | ||
92 | mutex_lock(&ucsi->lock); | |
93 | memset(ucsi->read_buf, 0, sizeof(ucsi->read_buf)); | |
94 | reinit_completion(&ucsi->read_ack); | |
95 | ||
96 | ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); | |
97 | if (ret < 0) { | |
98 | dev_err(ucsi->dev, "failed to send UCSI read request: %d\n", ret); | |
99 | goto out_unlock; | |
100 | } | |
101 | ||
102 | left = wait_for_completion_timeout(&ucsi->read_ack, 5 * HZ); | |
103 | if (!left) { | |
104 | dev_err(ucsi->dev, "timeout waiting for UCSI read response\n"); | |
105 | ret = -ETIMEDOUT; | |
106 | goto out_unlock; | |
107 | } | |
108 | ||
109 | memcpy(val, &ucsi->read_buf[offset], val_len); | |
110 | ret = 0; | |
111 | ||
112 | out_unlock: | |
113 | mutex_unlock(&ucsi->lock); | |
114 | ||
115 | return ret; | |
116 | } | |
117 | ||
118 | static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned int offset, | |
119 | const void *val, size_t val_len) | |
120 | { | |
121 | struct ucsi_write_buf_req_msg req = {}; | |
122 | unsigned long left; | |
123 | int ret; | |
124 | ||
125 | req.hdr.owner = PMIC_GLINK_OWNER_USBC; | |
126 | req.hdr.type = MSG_TYPE_REQ_RESP; | |
127 | req.hdr.opcode = UC_UCSI_WRITE_BUF_REQ; | |
128 | memcpy(&req.buf[offset], val, val_len); | |
129 | ||
130 | reinit_completion(&ucsi->write_ack); | |
131 | ||
132 | ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); | |
133 | if (ret < 0) { | |
134 | dev_err(ucsi->dev, "failed to send UCSI write request: %d\n", ret); | |
135 | return ret; | |
136 | } | |
137 | ||
138 | left = wait_for_completion_timeout(&ucsi->write_ack, 5 * HZ); | |
139 | if (!left) { | |
140 | dev_err(ucsi->dev, "timeout waiting for UCSI write response\n"); | |
141 | return -ETIMEDOUT; | |
142 | } | |
143 | ||
144 | return 0; | |
145 | } | |
146 | ||
147 | static int pmic_glink_ucsi_async_write(struct ucsi *__ucsi, unsigned int offset, | |
148 | const void *val, size_t val_len) | |
149 | { | |
150 | struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); | |
151 | int ret; | |
152 | ||
153 | mutex_lock(&ucsi->lock); | |
154 | ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); | |
155 | mutex_unlock(&ucsi->lock); | |
156 | ||
157 | return ret; | |
158 | } | |
159 | ||
160 | static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, | |
161 | const void *val, size_t val_len) | |
162 | { | |
163 | struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); | |
164 | unsigned long left; | |
165 | int ret; | |
166 | ||
167 | /* TOFIX: Downstream forces recipient to CON when UCSI_GET_ALTERNATE_MODES command */ | |
168 | ||
169 | mutex_lock(&ucsi->lock); | |
170 | ucsi->sync_val = 0; | |
171 | reinit_completion(&ucsi->sync_ack); | |
172 | ucsi->sync_pending = true; | |
173 | ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); | |
174 | mutex_unlock(&ucsi->lock); | |
175 | ||
176 | left = wait_for_completion_timeout(&ucsi->sync_ack, 5 * HZ); | |
177 | if (!left) { | |
178 | dev_err(ucsi->dev, "timeout waiting for UCSI sync write response\n"); | |
179 | ret = -ETIMEDOUT; | |
180 | } else if (ucsi->sync_val) { | |
181 | dev_err(ucsi->dev, "sync write returned: %d\n", ucsi->sync_val); | |
182 | } | |
183 | ||
184 | ucsi->sync_pending = false; | |
185 | ||
186 | return ret; | |
187 | } | |
188 | ||
189 | static const struct ucsi_operations pmic_glink_ucsi_ops = { | |
190 | .read = pmic_glink_ucsi_read, | |
191 | .sync_write = pmic_glink_ucsi_sync_write, | |
192 | .async_write = pmic_glink_ucsi_async_write | |
193 | }; | |
194 | ||
195 | static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) | |
196 | { | |
197 | const struct ucsi_read_buf_resp_msg *resp = data; | |
198 | ||
199 | if (resp->ret_code) | |
200 | return; | |
201 | ||
202 | memcpy(ucsi->read_buf, resp->buf, UCSI_BUF_SIZE); | |
203 | complete(&ucsi->read_ack); | |
204 | } | |
205 | ||
206 | static void pmic_glink_ucsi_write_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) | |
207 | { | |
208 | const struct ucsi_write_buf_resp_msg *resp = data; | |
209 | ||
210 | if (resp->ret_code) | |
211 | return; | |
212 | ||
213 | ucsi->sync_val = resp->ret_code; | |
214 | complete(&ucsi->write_ack); | |
215 | } | |
216 | ||
217 | static void pmic_glink_ucsi_notify(struct work_struct *work) | |
218 | { | |
219 | struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, notify_work); | |
220 | unsigned int con_num; | |
221 | u32 cci; | |
222 | int ret; | |
223 | ||
224 | ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_CCI, &cci, sizeof(cci)); | |
225 | if (ret) { | |
226 | dev_err(ucsi->dev, "failed to read CCI on notification\n"); | |
227 | return; | |
228 | } | |
229 | ||
230 | con_num = UCSI_CCI_CONNECTOR(cci); | |
c6165ed2 | 231 | if (con_num) { |
c994cb59 | 232 | if (con_num <= PMIC_GLINK_MAX_PORTS && |
c6165ed2 NA |
233 | ucsi->port_orientation[con_num - 1]) { |
234 | int orientation = gpiod_get_value(ucsi->port_orientation[con_num - 1]); | |
235 | ||
236 | if (orientation >= 0) { | |
237 | typec_switch_set(ucsi->port_switch[con_num - 1], | |
238 | orientation ? TYPEC_ORIENTATION_REVERSE | |
239 | : TYPEC_ORIENTATION_NORMAL); | |
240 | } | |
241 | } | |
242 | ||
62b5412b | 243 | ucsi_connector_change(ucsi->ucsi, con_num); |
c6165ed2 | 244 | } |
62b5412b NA |
245 | |
246 | if (ucsi->sync_pending && cci & UCSI_CCI_BUSY) { | |
247 | ucsi->sync_val = -EBUSY; | |
248 | complete(&ucsi->sync_ack); | |
249 | } else if (ucsi->sync_pending && | |
250 | (cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))) { | |
251 | complete(&ucsi->sync_ack); | |
252 | } | |
253 | } | |
254 | ||
255 | static void pmic_glink_ucsi_register(struct work_struct *work) | |
256 | { | |
257 | struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); | |
f5e9bda0 KK |
258 | int orientation; |
259 | int i; | |
260 | ||
261 | for (i = 0; i < PMIC_GLINK_MAX_PORTS; i++) { | |
262 | if (!ucsi->port_orientation[i]) | |
263 | continue; | |
264 | orientation = gpiod_get_value(ucsi->port_orientation[i]); | |
265 | ||
266 | if (orientation >= 0) { | |
267 | typec_switch_set(ucsi->port_switch[i], | |
268 | orientation ? TYPEC_ORIENTATION_REVERSE | |
269 | : TYPEC_ORIENTATION_NORMAL); | |
270 | } | |
271 | } | |
62b5412b NA |
272 | |
273 | ucsi_register(ucsi->ucsi); | |
274 | } | |
275 | ||
276 | static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) | |
277 | { | |
278 | struct pmic_glink_ucsi *ucsi = priv; | |
279 | const struct pmic_glink_hdr *hdr = data; | |
280 | ||
3c90c5a7 | 281 | switch (le32_to_cpu(hdr->opcode)) { |
62b5412b NA |
282 | case UC_UCSI_READ_BUF_REQ: |
283 | pmic_glink_ucsi_read_ack(ucsi, data, len); | |
284 | break; | |
285 | case UC_UCSI_WRITE_BUF_REQ: | |
286 | pmic_glink_ucsi_write_ack(ucsi, data, len); | |
287 | break; | |
288 | case UC_UCSI_USBC_NOTIFY_IND: | |
289 | schedule_work(&ucsi->notify_work); | |
290 | break; | |
291 | }; | |
292 | } | |
293 | ||
294 | static void pmic_glink_ucsi_pdr_notify(void *priv, int state) | |
295 | { | |
296 | struct pmic_glink_ucsi *ucsi = priv; | |
297 | ||
298 | if (state == SERVREG_SERVICE_STATE_UP) | |
299 | schedule_work(&ucsi->register_work); | |
300 | else if (state == SERVREG_SERVICE_STATE_DOWN) | |
301 | ucsi_unregister(ucsi->ucsi); | |
302 | } | |
303 | ||
304 | static void pmic_glink_ucsi_destroy(void *data) | |
305 | { | |
306 | struct pmic_glink_ucsi *ucsi = data; | |
307 | ||
308 | /* Protect to make sure we're not in a middle of a transaction from a glink callback */ | |
309 | mutex_lock(&ucsi->lock); | |
310 | ucsi_destroy(ucsi->ucsi); | |
311 | mutex_unlock(&ucsi->lock); | |
312 | } | |
313 | ||
1d103d6a | 314 | static const struct of_device_id pmic_glink_ucsi_of_quirks[] = { |
88bae831 | 315 | { .compatible = "qcom,qcm6490-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, |
1d103d6a DB |
316 | { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, |
317 | { .compatible = "qcom,sc8280xp-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, | |
318 | { .compatible = "qcom,sm8350-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, | |
4a30dcac | 319 | { .compatible = "qcom,sm8550-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, |
1d103d6a DB |
320 | {} |
321 | }; | |
322 | ||
62b5412b NA |
323 | static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, |
324 | const struct auxiliary_device_id *id) | |
325 | { | |
326 | struct pmic_glink_ucsi *ucsi; | |
327 | struct device *dev = &adev->dev; | |
1d103d6a | 328 | const struct of_device_id *match; |
c6165ed2 | 329 | struct fwnode_handle *fwnode; |
62b5412b NA |
330 | int ret; |
331 | ||
332 | ucsi = devm_kzalloc(dev, sizeof(*ucsi), GFP_KERNEL); | |
333 | if (!ucsi) | |
334 | return -ENOMEM; | |
335 | ||
336 | ucsi->dev = dev; | |
337 | dev_set_drvdata(dev, ucsi); | |
338 | ||
339 | INIT_WORK(&ucsi->notify_work, pmic_glink_ucsi_notify); | |
340 | INIT_WORK(&ucsi->register_work, pmic_glink_ucsi_register); | |
341 | init_completion(&ucsi->read_ack); | |
342 | init_completion(&ucsi->write_ack); | |
343 | init_completion(&ucsi->sync_ack); | |
344 | mutex_init(&ucsi->lock); | |
345 | ||
346 | ucsi->ucsi = ucsi_create(dev, &pmic_glink_ucsi_ops); | |
347 | if (IS_ERR(ucsi->ucsi)) | |
348 | return PTR_ERR(ucsi->ucsi); | |
349 | ||
350 | /* Make sure we destroy *after* pmic_glink unregister */ | |
351 | ret = devm_add_action_or_reset(dev, pmic_glink_ucsi_destroy, ucsi); | |
352 | if (ret) | |
353 | return ret; | |
354 | ||
1d103d6a DB |
355 | match = of_match_device(pmic_glink_ucsi_of_quirks, dev->parent); |
356 | if (match) | |
357 | ucsi->ucsi->quirks = (unsigned long)match->data; | |
358 | ||
62b5412b NA |
359 | ucsi_set_drvdata(ucsi->ucsi, ucsi); |
360 | ||
c6165ed2 NA |
361 | device_for_each_child_node(dev, fwnode) { |
362 | struct gpio_desc *desc; | |
363 | u32 port; | |
364 | ||
365 | ret = fwnode_property_read_u32(fwnode, "reg", &port); | |
366 | if (ret < 0) { | |
367 | dev_err(dev, "missing reg property of %pOFn\n", fwnode); | |
368 | return ret; | |
369 | } | |
370 | ||
371 | if (port >= PMIC_GLINK_MAX_PORTS) { | |
372 | dev_warn(dev, "invalid connector number, ignoring\n"); | |
373 | continue; | |
374 | } | |
375 | ||
376 | desc = devm_gpiod_get_index_optional(&adev->dev, "orientation", port, GPIOD_IN); | |
377 | ||
378 | /* If GPIO isn't found, continue */ | |
379 | if (!desc) | |
380 | continue; | |
381 | ||
382 | if (IS_ERR(desc)) | |
383 | return dev_err_probe(dev, PTR_ERR(desc), | |
384 | "unable to acquire orientation gpio\n"); | |
385 | ucsi->port_orientation[port] = desc; | |
386 | ||
387 | ucsi->port_switch[port] = fwnode_typec_switch_get(fwnode); | |
388 | if (IS_ERR(ucsi->port_switch[port])) | |
389 | return dev_err_probe(dev, PTR_ERR(ucsi->port_switch[port]), | |
390 | "failed to acquire orientation-switch\n"); | |
391 | } | |
392 | ||
62b5412b NA |
393 | ucsi->client = devm_pmic_glink_register_client(dev, |
394 | PMIC_GLINK_OWNER_USBC, | |
395 | pmic_glink_ucsi_callback, | |
396 | pmic_glink_ucsi_pdr_notify, | |
397 | ucsi); | |
398 | return PTR_ERR_OR_ZERO(ucsi->client); | |
399 | } | |
400 | ||
401 | static void pmic_glink_ucsi_remove(struct auxiliary_device *adev) | |
402 | { | |
403 | struct pmic_glink_ucsi *ucsi = dev_get_drvdata(&adev->dev); | |
404 | ||
405 | /* Unregister first to stop having read & writes */ | |
406 | ucsi_unregister(ucsi->ucsi); | |
407 | } | |
408 | ||
409 | static const struct auxiliary_device_id pmic_glink_ucsi_id_table[] = { | |
410 | { .name = "pmic_glink.ucsi", }, | |
411 | {}, | |
412 | }; | |
413 | MODULE_DEVICE_TABLE(auxiliary, pmic_glink_ucsi_id_table); | |
414 | ||
415 | static struct auxiliary_driver pmic_glink_ucsi_driver = { | |
416 | .name = "pmic_glink_ucsi", | |
417 | .probe = pmic_glink_ucsi_probe, | |
418 | .remove = pmic_glink_ucsi_remove, | |
419 | .id_table = pmic_glink_ucsi_id_table, | |
420 | }; | |
421 | ||
422 | module_auxiliary_driver(pmic_glink_ucsi_driver); | |
423 | ||
424 | MODULE_DESCRIPTION("Qualcomm PMIC GLINK UCSI driver"); | |
425 | MODULE_LICENSE("GPL"); |