1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * UCSI ACPI driver
4  *
5  * Copyright (C) 2017, Intel Corporation
6  * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
7  */
8 
9 #include <linux/platform_device.h>
10 #include <linux/module.h>
11 #include <linux/acpi.h>
12 #include <linux/dmi.h>
13 
14 #include "ucsi.h"
15 
16 #define UCSI_DSM_UUID		"6f8398c2-7ca4-11e4-ad36-631042b5008f"
17 #define UCSI_DSM_FUNC_WRITE	1
18 #define UCSI_DSM_FUNC_READ	2
19 
20 struct ucsi_acpi {
21 	struct device *dev;
22 	struct ucsi *ucsi;
23 	void *base;
24 	struct completion complete;
25 	unsigned long flags;
26 	guid_t guid;
27 	u64 cmd;
28 	bool dell_quirk_probed;
29 	bool dell_quirk_active;
30 };
31 
ucsi_acpi_dsm(struct ucsi_acpi * ua,int func)32 static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func)
33 {
34 	union acpi_object *obj;
35 
36 	obj = acpi_evaluate_dsm(ACPI_HANDLE(ua->dev), &ua->guid, 1, func,
37 				NULL);
38 	if (!obj) {
39 		dev_err(ua->dev, "%s: failed to evaluate _DSM %d\n",
40 			__func__, func);
41 		return -EIO;
42 	}
43 
44 	ACPI_FREE(obj);
45 	return 0;
46 }
47 
ucsi_acpi_read(struct ucsi * ucsi,unsigned int offset,void * val,size_t val_len)48 static int ucsi_acpi_read(struct ucsi *ucsi, unsigned int offset,
49 			  void *val, size_t val_len)
50 {
51 	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
52 	int ret;
53 
54 	ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
55 	if (ret)
56 		return ret;
57 
58 	memcpy(val, ua->base + offset, val_len);
59 
60 	return 0;
61 }
62 
ucsi_acpi_async_write(struct ucsi * ucsi,unsigned int offset,const void * val,size_t val_len)63 static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset,
64 				 const void *val, size_t val_len)
65 {
66 	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
67 
68 	memcpy(ua->base + offset, val, val_len);
69 	ua->cmd = *(u64 *)val;
70 
71 	return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE);
72 }
73 
ucsi_acpi_sync_write(struct ucsi * ucsi,unsigned int offset,const void * val,size_t val_len)74 static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset,
75 				const void *val, size_t val_len)
76 {
77 	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
78 	bool ack = UCSI_COMMAND(*(u64 *)val) == UCSI_ACK_CC_CI;
79 	int ret;
80 
81 	if (ack)
82 		set_bit(ACK_PENDING, &ua->flags);
83 	else
84 		set_bit(COMMAND_PENDING, &ua->flags);
85 
86 	ret = ucsi_acpi_async_write(ucsi, offset, val, val_len);
87 	if (ret)
88 		goto out_clear_bit;
89 
90 	if (!wait_for_completion_timeout(&ua->complete, 5 * HZ))
91 		ret = -ETIMEDOUT;
92 
93 out_clear_bit:
94 	if (ack)
95 		clear_bit(ACK_PENDING, &ua->flags);
96 	else
97 		clear_bit(COMMAND_PENDING, &ua->flags);
98 
99 	return ret;
100 }
101 
102 static const struct ucsi_operations ucsi_acpi_ops = {
103 	.read = ucsi_acpi_read,
104 	.sync_write = ucsi_acpi_sync_write,
105 	.async_write = ucsi_acpi_async_write
106 };
107 
108 static int
ucsi_zenbook_read(struct ucsi * ucsi,unsigned int offset,void * val,size_t val_len)109 ucsi_zenbook_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len)
110 {
111 	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
112 	int ret;
113 
114 	if (offset == UCSI_VERSION || UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) {
115 		ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
116 		if (ret)
117 			return ret;
118 	}
119 
120 	memcpy(val, ua->base + offset, val_len);
121 
122 	return 0;
123 }
124 
125 static const struct ucsi_operations ucsi_zenbook_ops = {
126 	.read = ucsi_zenbook_read,
127 	.sync_write = ucsi_acpi_sync_write,
128 	.async_write = ucsi_acpi_async_write
129 };
130 
131 /*
132  * Some Dell laptops expect that an ACK command with the
133  * UCSI_ACK_CONNECTOR_CHANGE bit set is followed by a (separate)
134  * ACK command that only has the UCSI_ACK_COMMAND_COMPLETE bit set.
135  * If this is not done events are not delivered to OSPM and
136  * subsequent commands will timeout.
137  */
138 static int
ucsi_dell_sync_write(struct ucsi * ucsi,unsigned int offset,const void * val,size_t val_len)139 ucsi_dell_sync_write(struct ucsi *ucsi, unsigned int offset,
140 		     const void *val, size_t val_len)
141 {
142 	struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
143 	u64 cmd = *(u64 *)val, ack = 0;
144 	int ret;
145 
146 	if (UCSI_COMMAND(cmd) == UCSI_ACK_CC_CI &&
147 	    cmd & UCSI_ACK_CONNECTOR_CHANGE)
148 		ack = UCSI_ACK_CC_CI | UCSI_ACK_COMMAND_COMPLETE;
149 
150 	ret = ucsi_acpi_sync_write(ucsi, offset, val, val_len);
151 	if (ret != 0)
152 		return ret;
153 	if (ack == 0)
154 		return ret;
155 
156 	if (!ua->dell_quirk_probed) {
157 		ua->dell_quirk_probed = true;
158 
159 		cmd = UCSI_GET_CAPABILITY;
160 		ret = ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &cmd,
161 					   sizeof(cmd));
162 		if (ret == 0)
163 			return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL,
164 						    &ack, sizeof(ack));
165 		if (ret != -ETIMEDOUT)
166 			return ret;
167 
168 		ua->dell_quirk_active = true;
169 		dev_err(ua->dev, "Firmware bug: Additional ACK required after ACKing a connector change.\n");
170 		dev_err(ua->dev, "Firmware bug: Enabling workaround\n");
171 	}
172 
173 	if (!ua->dell_quirk_active)
174 		return ret;
175 
176 	return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &ack, sizeof(ack));
177 }
178 
179 static const struct ucsi_operations ucsi_dell_ops = {
180 	.read = ucsi_acpi_read,
181 	.sync_write = ucsi_dell_sync_write,
182 	.async_write = ucsi_acpi_async_write
183 };
184 
185 static const struct dmi_system_id ucsi_acpi_quirks[] = {
186 	{
187 		.matches = {
188 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
189 			DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"),
190 		},
191 		.driver_data = (void *)&ucsi_zenbook_ops,
192 	},
193 	{
194 		.matches = {
195 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
196 		},
197 		.driver_data = (void *)&ucsi_dell_ops,
198 	},
199 	{ }
200 };
201 
ucsi_acpi_notify(acpi_handle handle,u32 event,void * data)202 static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
203 {
204 	struct ucsi_acpi *ua = data;
205 	u32 cci;
206 	int ret;
207 
208 	ret = ua->ucsi->ops->read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci));
209 	if (ret)
210 		return;
211 
212 	if (UCSI_CCI_CONNECTOR(cci))
213 		ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci));
214 
215 	if (cci & UCSI_CCI_ACK_COMPLETE && test_bit(ACK_PENDING, &ua->flags))
216 		complete(&ua->complete);
217 	if (cci & UCSI_CCI_COMMAND_COMPLETE &&
218 	    test_bit(COMMAND_PENDING, &ua->flags))
219 		complete(&ua->complete);
220 }
221 
ucsi_acpi_probe(struct platform_device * pdev)222 static int ucsi_acpi_probe(struct platform_device *pdev)
223 {
224 	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
225 	const struct ucsi_operations *ops = &ucsi_acpi_ops;
226 	const struct dmi_system_id *id;
227 	struct ucsi_acpi *ua;
228 	struct resource *res;
229 	acpi_status status;
230 	int ret;
231 
232 	if (adev->dep_unmet)
233 		return -EPROBE_DEFER;
234 
235 	ua = devm_kzalloc(&pdev->dev, sizeof(*ua), GFP_KERNEL);
236 	if (!ua)
237 		return -ENOMEM;
238 
239 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
240 	if (!res) {
241 		dev_err(&pdev->dev, "missing memory resource\n");
242 		return -ENODEV;
243 	}
244 
245 	ua->base = devm_memremap(&pdev->dev, res->start, resource_size(res), MEMREMAP_WB);
246 	if (IS_ERR(ua->base))
247 		return PTR_ERR(ua->base);
248 
249 	ret = guid_parse(UCSI_DSM_UUID, &ua->guid);
250 	if (ret)
251 		return ret;
252 
253 	init_completion(&ua->complete);
254 	ua->dev = &pdev->dev;
255 
256 	id = dmi_first_match(ucsi_acpi_quirks);
257 	if (id)
258 		ops = id->driver_data;
259 
260 	ua->ucsi = ucsi_create(&pdev->dev, ops);
261 	if (IS_ERR(ua->ucsi))
262 		return PTR_ERR(ua->ucsi);
263 
264 	ucsi_set_drvdata(ua->ucsi, ua);
265 
266 	status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev),
267 					     ACPI_DEVICE_NOTIFY,
268 					     ucsi_acpi_notify, ua);
269 	if (ACPI_FAILURE(status)) {
270 		dev_err(&pdev->dev, "failed to install notify handler\n");
271 		ucsi_destroy(ua->ucsi);
272 		return -ENODEV;
273 	}
274 
275 	ret = ucsi_register(ua->ucsi);
276 	if (ret) {
277 		acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
278 					   ACPI_DEVICE_NOTIFY,
279 					   ucsi_acpi_notify);
280 		ucsi_destroy(ua->ucsi);
281 		return ret;
282 	}
283 
284 	platform_set_drvdata(pdev, ua);
285 
286 	return 0;
287 }
288 
ucsi_acpi_remove(struct platform_device * pdev)289 static void ucsi_acpi_remove(struct platform_device *pdev)
290 {
291 	struct ucsi_acpi *ua = platform_get_drvdata(pdev);
292 
293 	ucsi_unregister(ua->ucsi);
294 	ucsi_destroy(ua->ucsi);
295 
296 	acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY,
297 				   ucsi_acpi_notify);
298 }
299 
ucsi_acpi_resume(struct device * dev)300 static int ucsi_acpi_resume(struct device *dev)
301 {
302 	struct ucsi_acpi *ua = dev_get_drvdata(dev);
303 
304 	return ucsi_resume(ua->ucsi);
305 }
306 
307 static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_acpi_pm_ops, NULL, ucsi_acpi_resume);
308 
309 static const struct acpi_device_id ucsi_acpi_match[] = {
310 	{ "PNP0CA0", 0 },
311 	{ },
312 };
313 MODULE_DEVICE_TABLE(acpi, ucsi_acpi_match);
314 
315 static struct platform_driver ucsi_acpi_platform_driver = {
316 	.driver = {
317 		.name = "ucsi_acpi",
318 		.pm = pm_ptr(&ucsi_acpi_pm_ops),
319 		.acpi_match_table = ACPI_PTR(ucsi_acpi_match),
320 	},
321 	.probe = ucsi_acpi_probe,
322 	.remove_new = ucsi_acpi_remove,
323 };
324 
325 module_platform_driver(ucsi_acpi_platform_driver);
326 
327 MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
328 MODULE_LICENSE("GPL v2");
329 MODULE_DESCRIPTION("UCSI ACPI driver");
330