xref: /linux/drivers/soc/qcom/pmic_glink_altmode.c (revision c83b49383b595be50647f0c764a48c78b5f3c4f8)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
4  * Copyright (c) 2022, Linaro Ltd
5  */
6 #include <linux/auxiliary_bus.h>
7 #include <linux/bitfield.h>
8 #include <linux/module.h>
9 #include <linux/of_device.h>
10 #include <linux/mutex.h>
11 #include <linux/property.h>
12 #include <linux/soc/qcom/pdr.h>
13 #include <drm/drm_bridge.h>
14 
15 #include <linux/usb/typec_altmode.h>
16 #include <linux/usb/typec_dp.h>
17 #include <linux/usb/typec_mux.h>
18 
19 #include <linux/soc/qcom/pmic_glink.h>
20 
21 #define PMIC_GLINK_MAX_PORTS	2
22 
23 #define USBC_SC8180X_NOTIFY_IND	0x13
24 #define USBC_CMD_WRITE_REQ      0x15
25 #define USBC_NOTIFY_IND		0x16
26 
27 #define ALTMODE_PAN_EN		0x10
28 #define ALTMODE_PAN_ACK		0x11
29 
30 struct usbc_write_req {
31 	struct pmic_glink_hdr   hdr;
32 	__le32 cmd;
33 	__le32 arg;
34 	__le32 reserved;
35 };
36 
37 #define NOTIFY_PAYLOAD_SIZE 16
38 struct usbc_notify {
39 	struct pmic_glink_hdr hdr;
40 	char payload[NOTIFY_PAYLOAD_SIZE];
41 	u32 reserved;
42 };
43 
44 struct usbc_sc8180x_notify {
45 	struct pmic_glink_hdr hdr;
46 	__le32 notification;
47 	__le32 reserved[2];
48 };
49 
50 enum pmic_glink_altmode_pin_assignment {
51 	DPAM_HPD_OUT,
52 	DPAM_HPD_A,
53 	DPAM_HPD_B,
54 	DPAM_HPD_C,
55 	DPAM_HPD_D,
56 	DPAM_HPD_E,
57 	DPAM_HPD_F,
58 };
59 
60 struct pmic_glink_altmode;
61 
62 #define work_to_altmode_port(w) container_of((w), struct pmic_glink_altmode_port, work)
63 
64 struct pmic_glink_altmode_port {
65 	struct pmic_glink_altmode *altmode;
66 	unsigned int index;
67 
68 	struct typec_switch *typec_switch;
69 	struct typec_mux *typec_mux;
70 	struct typec_mux_state state;
71 	struct typec_altmode dp_alt;
72 
73 	struct work_struct work;
74 
75 	struct drm_bridge bridge;
76 
77 	enum typec_orientation orientation;
78 	u16 svid;
79 	u8 dp_data;
80 	u8 mode;
81 	u8 hpd_state;
82 	u8 hpd_irq;
83 };
84 
85 #define work_to_altmode(w) container_of((w), struct pmic_glink_altmode, enable_work)
86 
87 struct pmic_glink_altmode {
88 	struct device *dev;
89 
90 	unsigned int owner_id;
91 
92 	/* To synchronize WRITE_REQ acks */
93 	struct mutex lock;
94 
95 	struct completion pan_ack;
96 	struct pmic_glink_client *client;
97 
98 	struct work_struct enable_work;
99 
100 	struct pmic_glink_altmode_port ports[PMIC_GLINK_MAX_PORTS];
101 };
102 
103 static int pmic_glink_altmode_request(struct pmic_glink_altmode *altmode, u32 cmd, u32 arg)
104 {
105 	struct usbc_write_req req = {};
106 	unsigned long left;
107 	int ret;
108 
109 	/*
110 	 * The USBC_CMD_WRITE_REQ ack doesn't identify the request, so wait for
111 	 * one ack at a time.
112 	 */
113 	mutex_lock(&altmode->lock);
114 
115 	req.hdr.owner = cpu_to_le32(altmode->owner_id);
116 	req.hdr.type = cpu_to_le32(PMIC_GLINK_REQ_RESP);
117 	req.hdr.opcode = cpu_to_le32(USBC_CMD_WRITE_REQ);
118 	req.cmd = cpu_to_le32(cmd);
119 	req.arg = cpu_to_le32(arg);
120 
121 	ret = pmic_glink_send(altmode->client, &req, sizeof(req));
122 	if (ret) {
123 		dev_err(altmode->dev, "failed to send altmode request: %#x (%d)\n", cmd, ret);
124 		goto out_unlock;
125 	}
126 
127 	left = wait_for_completion_timeout(&altmode->pan_ack, 5 * HZ);
128 	if (!left) {
129 		dev_err(altmode->dev, "timeout waiting for altmode request ack for: %#x\n", cmd);
130 		ret = -ETIMEDOUT;
131 	}
132 
133 out_unlock:
134 	mutex_unlock(&altmode->lock);
135 	return ret;
136 }
137 
138 static void pmic_glink_altmode_enable_dp(struct pmic_glink_altmode *altmode,
139 					 struct pmic_glink_altmode_port *port,
140 					 u8 mode, bool hpd_state,
141 					 bool hpd_irq)
142 {
143 	struct typec_displayport_data dp_data = {};
144 	int ret;
145 
146 	dp_data.status = DP_STATUS_ENABLED;
147 	if (hpd_state)
148 		dp_data.status |= DP_STATUS_HPD_STATE;
149 	if (hpd_irq)
150 		dp_data.status |= DP_STATUS_IRQ_HPD;
151 	dp_data.conf = DP_CONF_SET_PIN_ASSIGN(mode);
152 
153 	port->state.alt = &port->dp_alt;
154 	port->state.data = &dp_data;
155 	port->state.mode = TYPEC_MODAL_STATE(mode);
156 
157 	ret = typec_mux_set(port->typec_mux, &port->state);
158 	if (ret)
159 		dev_err(altmode->dev, "failed to switch mux to DP\n");
160 }
161 
162 static void pmic_glink_altmode_enable_usb(struct pmic_glink_altmode *altmode,
163 					  struct pmic_glink_altmode_port *port)
164 {
165 	int ret;
166 
167 	port->state.alt = NULL;
168 	port->state.data = NULL;
169 	port->state.mode = TYPEC_STATE_USB;
170 
171 	ret = typec_mux_set(port->typec_mux, &port->state);
172 	if (ret)
173 		dev_err(altmode->dev, "failed to switch mux to USB\n");
174 }
175 
176 static void pmic_glink_altmode_worker(struct work_struct *work)
177 {
178 	struct pmic_glink_altmode_port *alt_port = work_to_altmode_port(work);
179 	struct pmic_glink_altmode *altmode = alt_port->altmode;
180 
181 	typec_switch_set(alt_port->typec_switch, alt_port->orientation);
182 
183 	if (alt_port->svid == USB_TYPEC_DP_SID)
184 		pmic_glink_altmode_enable_dp(altmode, alt_port, alt_port->mode,
185 					     alt_port->hpd_state, alt_port->hpd_irq);
186 	else
187 		pmic_glink_altmode_enable_usb(altmode, alt_port);
188 
189 	if (alt_port->hpd_state)
190 		drm_bridge_hpd_notify(&alt_port->bridge, connector_status_connected);
191 	else
192 		drm_bridge_hpd_notify(&alt_port->bridge, connector_status_disconnected);
193 
194 	pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index);
195 };
196 
197 static enum typec_orientation pmic_glink_altmode_orientation(unsigned int orientation)
198 {
199 	if (orientation == 0)
200 		return TYPEC_ORIENTATION_NORMAL;
201 	else if (orientation == 1)
202 		return TYPEC_ORIENTATION_REVERSE;
203 	else
204 		return TYPEC_ORIENTATION_NONE;
205 }
206 
207 #define SC8180X_PORT_MASK		0x000000ff
208 #define SC8180X_ORIENTATION_MASK	0x0000ff00
209 #define SC8180X_MUX_MASK		0x00ff0000
210 #define SC8180X_MODE_MASK		0x3f000000
211 #define SC8180X_HPD_STATE_MASK		0x40000000
212 #define SC8180X_HPD_IRQ_MASK		0x80000000
213 
214 static void pmic_glink_altmode_sc8180xp_notify(struct pmic_glink_altmode *altmode,
215 					       const void *data, size_t len)
216 {
217 	struct pmic_glink_altmode_port *alt_port;
218 	const struct usbc_sc8180x_notify *msg;
219 	u32 notification;
220 	u8 orientation;
221 	u8 hpd_state;
222 	u8 hpd_irq;
223 	u16 svid;
224 	u8 port;
225 	u8 mode;
226 	u8 mux;
227 
228 	if (len != sizeof(*msg)) {
229 		dev_warn(altmode->dev, "invalid length of USBC_NOTIFY indication: %zd\n", len);
230 		return;
231 	}
232 
233 	msg = data;
234 	notification = le32_to_cpu(msg->notification);
235 	port = FIELD_GET(SC8180X_PORT_MASK, notification);
236 	orientation = FIELD_GET(SC8180X_ORIENTATION_MASK, notification);
237 	mux = FIELD_GET(SC8180X_MUX_MASK, notification);
238 	mode = FIELD_GET(SC8180X_MODE_MASK, notification);
239 	hpd_state = FIELD_GET(SC8180X_HPD_STATE_MASK, notification);
240 	hpd_irq = FIELD_GET(SC8180X_HPD_IRQ_MASK, notification);
241 
242 	svid = mux == 2 ? USB_TYPEC_DP_SID : 0;
243 
244 	if (!altmode->ports[port].altmode) {
245 		dev_dbg(altmode->dev, "notification on undefined port %d\n", port);
246 		return;
247 	}
248 
249 	alt_port = &altmode->ports[port];
250 	alt_port->orientation = pmic_glink_altmode_orientation(orientation);
251 	alt_port->svid = svid;
252 	alt_port->mode = mode;
253 	alt_port->hpd_state = hpd_state;
254 	alt_port->hpd_irq = hpd_irq;
255 	schedule_work(&alt_port->work);
256 }
257 
258 #define SC8280XP_DPAM_MASK	0x3f
259 #define SC8280XP_HPD_STATE_MASK BIT(6)
260 #define SC8280XP_HPD_IRQ_MASK	BIT(7)
261 
262 static void pmic_glink_altmode_sc8280xp_notify(struct pmic_glink_altmode *altmode,
263 					       u16 svid, const void *data, size_t len)
264 {
265 	struct pmic_glink_altmode_port *alt_port;
266 	const struct usbc_notify *notify;
267 	u8 orientation;
268 	u8 hpd_state;
269 	u8 hpd_irq;
270 	u8 mode;
271 	u8 port;
272 
273 	if (len != sizeof(*notify)) {
274 		dev_warn(altmode->dev, "invalid length USBC_NOTIFY_IND: %zd\n",
275 			 len);
276 		return;
277 	}
278 
279 	notify = data;
280 
281 	port = notify->payload[0];
282 	orientation = notify->payload[1];
283 	mode = FIELD_GET(SC8280XP_DPAM_MASK, notify->payload[8]) - DPAM_HPD_A;
284 	hpd_state = FIELD_GET(SC8280XP_HPD_STATE_MASK, notify->payload[8]);
285 	hpd_irq = FIELD_GET(SC8280XP_HPD_IRQ_MASK, notify->payload[8]);
286 
287 	if (!altmode->ports[port].altmode) {
288 		dev_dbg(altmode->dev, "notification on undefined port %d\n", port);
289 		return;
290 	}
291 
292 	alt_port = &altmode->ports[port];
293 	alt_port->orientation = pmic_glink_altmode_orientation(orientation);
294 	alt_port->svid = svid;
295 	alt_port->mode = mode;
296 	alt_port->hpd_state = hpd_state;
297 	alt_port->hpd_irq = hpd_irq;
298 	schedule_work(&alt_port->work);
299 }
300 
301 static void pmic_glink_altmode_callback(const void *data, size_t len, void *priv)
302 {
303 	struct pmic_glink_altmode *altmode = priv;
304 	const struct pmic_glink_hdr *hdr = data;
305 	u16 opcode;
306 	u16 svid;
307 
308 	opcode = le32_to_cpu(hdr->opcode) & 0xff;
309 	svid = le32_to_cpu(hdr->opcode) >> 16;
310 
311 	switch (opcode) {
312 	case USBC_CMD_WRITE_REQ:
313 		complete(&altmode->pan_ack);
314 		break;
315 	case USBC_NOTIFY_IND:
316 		pmic_glink_altmode_sc8280xp_notify(altmode, svid, data, len);
317 		break;
318 	case USBC_SC8180X_NOTIFY_IND:
319 		pmic_glink_altmode_sc8180xp_notify(altmode, data, len);
320 		break;
321 	}
322 }
323 
324 static int pmic_glink_altmode_attach(struct drm_bridge *bridge,
325 				     enum drm_bridge_attach_flags flags)
326 {
327 	return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
328 }
329 
330 static const struct drm_bridge_funcs pmic_glink_altmode_bridge_funcs = {
331 	.attach = pmic_glink_altmode_attach,
332 };
333 
334 static void pmic_glink_altmode_put_mux(void *data)
335 {
336 	typec_mux_put(data);
337 }
338 
339 static void pmic_glink_altmode_put_switch(void *data)
340 {
341 	typec_switch_put(data);
342 }
343 
344 static void pmic_glink_altmode_enable_worker(struct work_struct *work)
345 {
346 	struct pmic_glink_altmode *altmode = work_to_altmode(work);
347 	int ret;
348 
349 	ret = pmic_glink_altmode_request(altmode, ALTMODE_PAN_EN, 0);
350 	if (ret)
351 		dev_err(altmode->dev, "failed to request altmode notifications\n");
352 }
353 
354 static void pmic_glink_altmode_pdr_notify(void *priv, int state)
355 {
356 	struct pmic_glink_altmode *altmode = priv;
357 
358 	if (state == SERVREG_SERVICE_STATE_UP)
359 		schedule_work(&altmode->enable_work);
360 }
361 
362 static const struct of_device_id pmic_glink_altmode_of_quirks[] = {
363 	{ .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)PMIC_GLINK_OWNER_USBC },
364 	{}
365 };
366 
367 static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
368 				    const struct auxiliary_device_id *id)
369 {
370 	struct pmic_glink_altmode_port *alt_port;
371 	struct pmic_glink_altmode *altmode;
372 	struct typec_altmode_desc mux_desc = {};
373 	const struct of_device_id *match;
374 	struct fwnode_handle *fwnode;
375 	struct device *dev = &adev->dev;
376 	u32 port;
377 	int ret;
378 
379 	altmode = devm_kzalloc(dev, sizeof(*altmode), GFP_KERNEL);
380 	if (!altmode)
381 		return -ENOMEM;
382 
383 	altmode->dev = dev;
384 
385 	match = of_match_device(pmic_glink_altmode_of_quirks, dev->parent);
386 	if (match)
387 		altmode->owner_id = (unsigned long)match->data;
388 	else
389 		altmode->owner_id = PMIC_GLINK_OWNER_USBC_PAN;
390 
391 	INIT_WORK(&altmode->enable_work, pmic_glink_altmode_enable_worker);
392 	init_completion(&altmode->pan_ack);
393 	mutex_init(&altmode->lock);
394 
395 	device_for_each_child_node(dev, fwnode) {
396 		ret = fwnode_property_read_u32(fwnode, "reg", &port);
397 		if (ret < 0) {
398 			dev_err(dev, "missing reg property of %pOFn\n", fwnode);
399 			return ret;
400 		}
401 
402 		if (port >= ARRAY_SIZE(altmode->ports)) {
403 			dev_warn(dev, "invalid connector number, ignoring\n");
404 			continue;
405 		}
406 
407 		if (altmode->ports[port].altmode) {
408 			dev_err(dev, "multiple connector definition for port %u\n", port);
409 			return -EINVAL;
410 		}
411 
412 		alt_port = &altmode->ports[port];
413 		alt_port->altmode = altmode;
414 		alt_port->index = port;
415 		INIT_WORK(&alt_port->work, pmic_glink_altmode_worker);
416 
417 		alt_port->bridge.funcs = &pmic_glink_altmode_bridge_funcs;
418 		alt_port->bridge.of_node = to_of_node(fwnode);
419 		alt_port->bridge.ops = DRM_BRIDGE_OP_HPD;
420 		alt_port->bridge.type = DRM_MODE_CONNECTOR_USB;
421 
422 		ret = devm_drm_bridge_add(dev, &alt_port->bridge);
423 		if (ret)
424 			return ret;
425 
426 		alt_port->dp_alt.svid = USB_TYPEC_DP_SID;
427 		alt_port->dp_alt.mode = USB_TYPEC_DP_MODE;
428 		alt_port->dp_alt.active = 1;
429 
430 		mux_desc.svid = USB_TYPEC_DP_SID;
431 		mux_desc.mode = USB_TYPEC_DP_MODE;
432 		alt_port->typec_mux = fwnode_typec_mux_get(fwnode, &mux_desc);
433 		if (IS_ERR(alt_port->typec_mux))
434 			return dev_err_probe(dev, PTR_ERR(alt_port->typec_mux),
435 					     "failed to acquire mode-switch for port: %d\n",
436 					     port);
437 
438 		ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_mux,
439 					       alt_port->typec_mux);
440 		if (ret)
441 			return ret;
442 
443 		alt_port->typec_switch = fwnode_typec_switch_get(fwnode);
444 		if (IS_ERR(alt_port->typec_switch))
445 			return dev_err_probe(dev, PTR_ERR(alt_port->typec_switch),
446 					     "failed to acquire orientation-switch for port: %d\n",
447 					     port);
448 
449 		ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_switch,
450 					       alt_port->typec_switch);
451 		if (ret)
452 			return ret;
453 	}
454 
455 	altmode->client = devm_pmic_glink_register_client(dev,
456 							  altmode->owner_id,
457 							  pmic_glink_altmode_callback,
458 							  pmic_glink_altmode_pdr_notify,
459 							  altmode);
460 	return PTR_ERR_OR_ZERO(altmode->client);
461 }
462 
463 static const struct auxiliary_device_id pmic_glink_altmode_id_table[] = {
464 	{ .name = "pmic_glink.altmode", },
465 	{},
466 };
467 MODULE_DEVICE_TABLE(auxiliary, pmic_glink_altmode_id_table);
468 
469 static struct auxiliary_driver pmic_glink_altmode_driver = {
470 	.name = "pmic_glink_altmode",
471 	.probe = pmic_glink_altmode_probe,
472 	.id_table = pmic_glink_altmode_id_table,
473 };
474 
475 module_auxiliary_driver(pmic_glink_altmode_driver);
476 
477 MODULE_DESCRIPTION("Qualcomm PMIC GLINK Altmode driver");
478 MODULE_LICENSE("GPL");
479