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