1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // LPC interface for ChromeOS Embedded Controller |
3 | // |
4 | // Copyright (C) 2012-2015 Google, Inc |
5 | // |
6 | // This driver uses the ChromeOS EC byte-level message-based protocol for |
7 | // communicating the keyboard state (which keys are pressed) from a keyboard EC |
8 | // to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, |
9 | // but everything else (including deghosting) is done here. The main |
10 | // motivation for this is to keep the EC firmware as simple as possible, since |
11 | // it cannot be easily upgraded and EC flash/IRAM space is relatively |
12 | // expensive. |
13 | |
14 | #include <linux/acpi.h> |
15 | #include <linux/dmi.h> |
16 | #include <linux/delay.h> |
17 | #include <linux/io.h> |
18 | #include <linux/interrupt.h> |
19 | #include <linux/kobject.h> |
20 | #include <linux/module.h> |
21 | #include <linux/platform_data/cros_ec_commands.h> |
22 | #include <linux/platform_data/cros_ec_proto.h> |
23 | #include <linux/platform_device.h> |
24 | #include <linux/printk.h> |
25 | #include <linux/reboot.h> |
26 | #include <linux/suspend.h> |
27 | |
28 | #include "cros_ec.h" |
29 | #include "cros_ec_lpc_mec.h" |
30 | |
31 | #define DRV_NAME "cros_ec_lpcs" |
32 | #define ACPI_DRV_NAME "GOOG0004" |
33 | |
34 | /* True if ACPI device is present */ |
35 | static bool cros_ec_lpc_acpi_device_found; |
36 | |
37 | /** |
38 | * struct lpc_driver_ops - LPC driver operations |
39 | * @read: Copy length bytes from EC address offset into buffer dest. Returns |
40 | * the 8-bit checksum of all bytes read. |
41 | * @write: Copy length bytes from buffer msg into EC address offset. Returns |
42 | * the 8-bit checksum of all bytes written. |
43 | */ |
44 | struct lpc_driver_ops { |
45 | u8 (*read)(unsigned int offset, unsigned int length, u8 *dest); |
46 | u8 (*write)(unsigned int offset, unsigned int length, const u8 *msg); |
47 | }; |
48 | |
49 | static struct lpc_driver_ops cros_ec_lpc_ops = { }; |
50 | |
51 | /* |
52 | * A generic instance of the read function of struct lpc_driver_ops, used for |
53 | * the LPC EC. |
54 | */ |
55 | static u8 cros_ec_lpc_read_bytes(unsigned int offset, unsigned int length, |
56 | u8 *dest) |
57 | { |
58 | int sum = 0; |
59 | int i; |
60 | |
61 | for (i = 0; i < length; ++i) { |
62 | dest[i] = inb(port: offset + i); |
63 | sum += dest[i]; |
64 | } |
65 | |
66 | /* Return checksum of all bytes read */ |
67 | return sum; |
68 | } |
69 | |
70 | /* |
71 | * A generic instance of the write function of struct lpc_driver_ops, used for |
72 | * the LPC EC. |
73 | */ |
74 | static u8 cros_ec_lpc_write_bytes(unsigned int offset, unsigned int length, |
75 | const u8 *msg) |
76 | { |
77 | int sum = 0; |
78 | int i; |
79 | |
80 | for (i = 0; i < length; ++i) { |
81 | outb(value: msg[i], port: offset + i); |
82 | sum += msg[i]; |
83 | } |
84 | |
85 | /* Return checksum of all bytes written */ |
86 | return sum; |
87 | } |
88 | |
89 | /* |
90 | * An instance of the read function of struct lpc_driver_ops, used for the |
91 | * MEC variant of LPC EC. |
92 | */ |
93 | static u8 cros_ec_lpc_mec_read_bytes(unsigned int offset, unsigned int length, |
94 | u8 *dest) |
95 | { |
96 | int in_range = cros_ec_lpc_mec_in_range(offset, length); |
97 | |
98 | if (in_range < 0) |
99 | return 0; |
100 | |
101 | return in_range ? |
102 | cros_ec_lpc_io_bytes_mec(io_type: MEC_IO_READ, |
103 | offset: offset - EC_HOST_CMD_REGION0, |
104 | length, buf: dest) : |
105 | cros_ec_lpc_read_bytes(offset, length, dest); |
106 | } |
107 | |
108 | /* |
109 | * An instance of the write function of struct lpc_driver_ops, used for the |
110 | * MEC variant of LPC EC. |
111 | */ |
112 | static u8 cros_ec_lpc_mec_write_bytes(unsigned int offset, unsigned int length, |
113 | const u8 *msg) |
114 | { |
115 | int in_range = cros_ec_lpc_mec_in_range(offset, length); |
116 | |
117 | if (in_range < 0) |
118 | return 0; |
119 | |
120 | return in_range ? |
121 | cros_ec_lpc_io_bytes_mec(io_type: MEC_IO_WRITE, |
122 | offset: offset - EC_HOST_CMD_REGION0, |
123 | length, buf: (u8 *)msg) : |
124 | cros_ec_lpc_write_bytes(offset, length, msg); |
125 | } |
126 | |
127 | static int ec_response_timed_out(void) |
128 | { |
129 | unsigned long one_second = jiffies + HZ; |
130 | u8 data; |
131 | |
132 | usleep_range(min: 200, max: 300); |
133 | do { |
134 | if (!(cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_CMD, 1, &data) & |
135 | EC_LPC_STATUS_BUSY_MASK)) |
136 | return 0; |
137 | usleep_range(min: 100, max: 200); |
138 | } while (time_before(jiffies, one_second)); |
139 | |
140 | return 1; |
141 | } |
142 | |
143 | static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, |
144 | struct cros_ec_command *msg) |
145 | { |
146 | struct ec_host_response response; |
147 | u8 sum; |
148 | int ret = 0; |
149 | u8 *dout; |
150 | |
151 | ret = cros_ec_prepare_tx(ec_dev: ec, msg); |
152 | if (ret < 0) |
153 | goto done; |
154 | |
155 | /* Write buffer */ |
156 | cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PACKET, ret, ec->dout); |
157 | |
158 | /* Here we go */ |
159 | sum = EC_COMMAND_PROTOCOL_3; |
160 | cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum); |
161 | |
162 | if (ec_response_timed_out()) { |
163 | dev_warn(ec->dev, "EC response timed out\n" ); |
164 | ret = -EIO; |
165 | goto done; |
166 | } |
167 | |
168 | /* Check result */ |
169 | msg->result = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_DATA, 1, &sum); |
170 | ret = cros_ec_check_result(ec_dev: ec, msg); |
171 | if (ret) |
172 | goto done; |
173 | |
174 | /* Read back response */ |
175 | dout = (u8 *)&response; |
176 | sum = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PACKET, sizeof(response), |
177 | dout); |
178 | |
179 | msg->result = response.result; |
180 | |
181 | if (response.data_len > msg->insize) { |
182 | dev_err(ec->dev, |
183 | "packet too long (%d bytes, expected %d)" , |
184 | response.data_len, msg->insize); |
185 | ret = -EMSGSIZE; |
186 | goto done; |
187 | } |
188 | |
189 | /* Read response and process checksum */ |
190 | sum += cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PACKET + |
191 | sizeof(response), response.data_len, |
192 | msg->data); |
193 | |
194 | if (sum) { |
195 | dev_err(ec->dev, |
196 | "bad packet checksum %02x\n" , |
197 | response.checksum); |
198 | ret = -EBADMSG; |
199 | goto done; |
200 | } |
201 | |
202 | /* Return actual amount of data received */ |
203 | ret = response.data_len; |
204 | done: |
205 | return ret; |
206 | } |
207 | |
208 | static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, |
209 | struct cros_ec_command *msg) |
210 | { |
211 | struct ec_lpc_host_args args; |
212 | u8 sum; |
213 | int ret = 0; |
214 | |
215 | if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE || |
216 | msg->insize > EC_PROTO2_MAX_PARAM_SIZE) { |
217 | dev_err(ec->dev, |
218 | "invalid buffer sizes (out %d, in %d)\n" , |
219 | msg->outsize, msg->insize); |
220 | return -EINVAL; |
221 | } |
222 | |
223 | /* Now actually send the command to the EC and get the result */ |
224 | args.flags = EC_HOST_ARGS_FLAG_FROM_HOST; |
225 | args.command_version = msg->version; |
226 | args.data_size = msg->outsize; |
227 | |
228 | /* Initialize checksum */ |
229 | sum = msg->command + args.flags + args.command_version + args.data_size; |
230 | |
231 | /* Copy data and update checksum */ |
232 | sum += cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_PARAM, msg->outsize, |
233 | msg->data); |
234 | |
235 | /* Finalize checksum and write args */ |
236 | args.checksum = sum; |
237 | cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_ARGS, sizeof(args), |
238 | (u8 *)&args); |
239 | |
240 | /* Here we go */ |
241 | sum = msg->command; |
242 | cros_ec_lpc_ops.write(EC_LPC_ADDR_HOST_CMD, 1, &sum); |
243 | |
244 | if (ec_response_timed_out()) { |
245 | dev_warn(ec->dev, "EC response timed out\n" ); |
246 | ret = -EIO; |
247 | goto done; |
248 | } |
249 | |
250 | /* Check result */ |
251 | msg->result = cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_DATA, 1, &sum); |
252 | ret = cros_ec_check_result(ec_dev: ec, msg); |
253 | if (ret) |
254 | goto done; |
255 | |
256 | /* Read back args */ |
257 | cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_ARGS, sizeof(args), (u8 *)&args); |
258 | |
259 | if (args.data_size > msg->insize) { |
260 | dev_err(ec->dev, |
261 | "packet too long (%d bytes, expected %d)" , |
262 | args.data_size, msg->insize); |
263 | ret = -ENOSPC; |
264 | goto done; |
265 | } |
266 | |
267 | /* Start calculating response checksum */ |
268 | sum = msg->command + args.flags + args.command_version + args.data_size; |
269 | |
270 | /* Read response and update checksum */ |
271 | sum += cros_ec_lpc_ops.read(EC_LPC_ADDR_HOST_PARAM, args.data_size, |
272 | msg->data); |
273 | |
274 | /* Verify checksum */ |
275 | if (args.checksum != sum) { |
276 | dev_err(ec->dev, |
277 | "bad packet checksum, expected %02x, got %02x\n" , |
278 | args.checksum, sum); |
279 | ret = -EBADMSG; |
280 | goto done; |
281 | } |
282 | |
283 | /* Return actual amount of data received */ |
284 | ret = args.data_size; |
285 | done: |
286 | return ret; |
287 | } |
288 | |
289 | /* Returns num bytes read, or negative on error. Doesn't need locking. */ |
290 | static int cros_ec_lpc_readmem(struct cros_ec_device *ec, unsigned int offset, |
291 | unsigned int bytes, void *dest) |
292 | { |
293 | int i = offset; |
294 | char *s = dest; |
295 | int cnt = 0; |
296 | |
297 | if (offset >= EC_MEMMAP_SIZE - bytes) |
298 | return -EINVAL; |
299 | |
300 | /* fixed length */ |
301 | if (bytes) { |
302 | cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + offset, bytes, s); |
303 | return bytes; |
304 | } |
305 | |
306 | /* string */ |
307 | for (; i < EC_MEMMAP_SIZE; i++, s++) { |
308 | cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + i, 1, s); |
309 | cnt++; |
310 | if (!*s) |
311 | break; |
312 | } |
313 | |
314 | return cnt; |
315 | } |
316 | |
317 | static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data) |
318 | { |
319 | static const char *env[] = { "ERROR=PANIC" , NULL }; |
320 | struct cros_ec_device *ec_dev = data; |
321 | bool ec_has_more_events; |
322 | int ret; |
323 | |
324 | ec_dev->last_event_time = cros_ec_get_time_ns(); |
325 | |
326 | if (value == ACPI_NOTIFY_CROS_EC_PANIC) { |
327 | dev_emerg(ec_dev->dev, "CrOS EC Panic Reported. Shutdown is imminent!" ); |
328 | blocking_notifier_call_chain(nh: &ec_dev->panic_notifier, val: 0, v: ec_dev); |
329 | kobject_uevent_env(kobj: &ec_dev->dev->kobj, action: KOBJ_CHANGE, envp: (char **)env); |
330 | /* Begin orderly shutdown. EC will force reset after a short period. */ |
331 | hw_protection_shutdown(reason: "CrOS EC Panic" , ms_until_forced: -1); |
332 | /* Do not query for other events after a panic is reported */ |
333 | return; |
334 | } |
335 | |
336 | if (ec_dev->mkbp_event_supported) |
337 | do { |
338 | ret = cros_ec_get_next_event(ec_dev, NULL, |
339 | has_more_events: &ec_has_more_events); |
340 | if (ret > 0) |
341 | blocking_notifier_call_chain( |
342 | nh: &ec_dev->event_notifier, val: 0, |
343 | v: ec_dev); |
344 | } while (ec_has_more_events); |
345 | |
346 | if (value == ACPI_NOTIFY_DEVICE_WAKE) |
347 | pm_system_wakeup(); |
348 | } |
349 | |
350 | static int cros_ec_lpc_probe(struct platform_device *pdev) |
351 | { |
352 | struct device *dev = &pdev->dev; |
353 | struct acpi_device *adev; |
354 | acpi_status status; |
355 | struct cros_ec_device *ec_dev; |
356 | u8 buf[2] = {}; |
357 | int irq, ret; |
358 | |
359 | /* |
360 | * The Framework Laptop (and possibly other non-ChromeOS devices) |
361 | * only exposes the eight I/O ports that are required for the Microchip EC. |
362 | * Requesting a larger reservation will fail. |
363 | */ |
364 | if (!devm_request_region(dev, EC_HOST_CMD_REGION0, |
365 | EC_HOST_CMD_MEC_REGION_SIZE, dev_name(dev))) { |
366 | dev_err(dev, "couldn't reserve MEC region\n" ); |
367 | return -EBUSY; |
368 | } |
369 | |
370 | cros_ec_lpc_mec_init(EC_HOST_CMD_REGION0, |
371 | EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SIZE); |
372 | |
373 | /* |
374 | * Read the mapped ID twice, the first one is assuming the |
375 | * EC is a Microchip Embedded Controller (MEC) variant, if the |
376 | * protocol fails, fallback to the non MEC variant and try to |
377 | * read again the ID. |
378 | */ |
379 | cros_ec_lpc_ops.read = cros_ec_lpc_mec_read_bytes; |
380 | cros_ec_lpc_ops.write = cros_ec_lpc_mec_write_bytes; |
381 | cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, buf); |
382 | if (buf[0] != 'E' || buf[1] != 'C') { |
383 | if (!devm_request_region(dev, EC_LPC_ADDR_MEMMAP, EC_MEMMAP_SIZE, |
384 | dev_name(dev))) { |
385 | dev_err(dev, "couldn't reserve memmap region\n" ); |
386 | return -EBUSY; |
387 | } |
388 | |
389 | /* Re-assign read/write operations for the non MEC variant */ |
390 | cros_ec_lpc_ops.read = cros_ec_lpc_read_bytes; |
391 | cros_ec_lpc_ops.write = cros_ec_lpc_write_bytes; |
392 | cros_ec_lpc_ops.read(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID, 2, |
393 | buf); |
394 | if (buf[0] != 'E' || buf[1] != 'C') { |
395 | dev_err(dev, "EC ID not detected\n" ); |
396 | return -ENODEV; |
397 | } |
398 | |
399 | /* Reserve the remaining I/O ports required by the non-MEC protocol. */ |
400 | if (!devm_request_region(dev, EC_HOST_CMD_REGION0 + EC_HOST_CMD_MEC_REGION_SIZE, |
401 | EC_HOST_CMD_REGION_SIZE - EC_HOST_CMD_MEC_REGION_SIZE, |
402 | dev_name(dev))) { |
403 | dev_err(dev, "couldn't reserve remainder of region0\n" ); |
404 | return -EBUSY; |
405 | } |
406 | if (!devm_request_region(dev, EC_HOST_CMD_REGION1, |
407 | EC_HOST_CMD_REGION_SIZE, dev_name(dev))) { |
408 | dev_err(dev, "couldn't reserve region1\n" ); |
409 | return -EBUSY; |
410 | } |
411 | } |
412 | |
413 | ec_dev = devm_kzalloc(dev, size: sizeof(*ec_dev), GFP_KERNEL); |
414 | if (!ec_dev) |
415 | return -ENOMEM; |
416 | |
417 | platform_set_drvdata(pdev, data: ec_dev); |
418 | ec_dev->dev = dev; |
419 | ec_dev->phys_name = dev_name(dev); |
420 | ec_dev->cmd_xfer = cros_ec_cmd_xfer_lpc; |
421 | ec_dev->pkt_xfer = cros_ec_pkt_xfer_lpc; |
422 | ec_dev->cmd_readmem = cros_ec_lpc_readmem; |
423 | ec_dev->din_size = sizeof(struct ec_host_response) + |
424 | sizeof(struct ec_response_get_protocol_info); |
425 | ec_dev->dout_size = sizeof(struct ec_host_request); |
426 | |
427 | /* |
428 | * Some boards do not have an IRQ allotted for cros_ec_lpc, |
429 | * which makes ENXIO an expected (and safe) scenario. |
430 | */ |
431 | irq = platform_get_irq_optional(pdev, 0); |
432 | if (irq > 0) |
433 | ec_dev->irq = irq; |
434 | else if (irq != -ENXIO) { |
435 | dev_err(dev, "couldn't retrieve IRQ number (%d)\n" , irq); |
436 | return irq; |
437 | } |
438 | |
439 | ret = cros_ec_register(ec_dev); |
440 | if (ret) { |
441 | dev_err(dev, "couldn't register ec_dev (%d)\n" , ret); |
442 | return ret; |
443 | } |
444 | |
445 | /* |
446 | * Connect a notify handler to process MKBP messages if we have a |
447 | * companion ACPI device. |
448 | */ |
449 | adev = ACPI_COMPANION(dev); |
450 | if (adev) { |
451 | status = acpi_install_notify_handler(device: adev->handle, |
452 | ACPI_ALL_NOTIFY, |
453 | handler: cros_ec_lpc_acpi_notify, |
454 | context: ec_dev); |
455 | if (ACPI_FAILURE(status)) |
456 | dev_warn(dev, "Failed to register notifier %08x\n" , |
457 | status); |
458 | } |
459 | |
460 | return 0; |
461 | } |
462 | |
463 | static void cros_ec_lpc_remove(struct platform_device *pdev) |
464 | { |
465 | struct cros_ec_device *ec_dev = platform_get_drvdata(pdev); |
466 | struct acpi_device *adev; |
467 | |
468 | adev = ACPI_COMPANION(&pdev->dev); |
469 | if (adev) |
470 | acpi_remove_notify_handler(device: adev->handle, ACPI_ALL_NOTIFY, |
471 | handler: cros_ec_lpc_acpi_notify); |
472 | |
473 | cros_ec_unregister(ec_dev); |
474 | } |
475 | |
476 | static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = { |
477 | { ACPI_DRV_NAME, 0 }, |
478 | { } |
479 | }; |
480 | MODULE_DEVICE_TABLE(acpi, cros_ec_lpc_acpi_device_ids); |
481 | |
482 | static const struct dmi_system_id cros_ec_lpc_dmi_table[] __initconst = { |
483 | { |
484 | /* |
485 | * Today all Chromebooks/boxes ship with Google_* as version and |
486 | * coreboot as bios vendor. No other systems with this |
487 | * combination are known to date. |
488 | */ |
489 | .matches = { |
490 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot" ), |
491 | DMI_MATCH(DMI_BIOS_VERSION, "Google_" ), |
492 | }, |
493 | }, |
494 | { |
495 | /* |
496 | * If the box is running custom coreboot firmware then the |
497 | * DMI BIOS version string will not be matched by "Google_", |
498 | * but the system vendor string will still be matched by |
499 | * "GOOGLE". |
500 | */ |
501 | .matches = { |
502 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot" ), |
503 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE" ), |
504 | }, |
505 | }, |
506 | { |
507 | /* x86-link, the Chromebook Pixel. */ |
508 | .matches = { |
509 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE" ), |
510 | DMI_MATCH(DMI_PRODUCT_NAME, "Link" ), |
511 | }, |
512 | }, |
513 | { |
514 | /* x86-samus, the Chromebook Pixel 2. */ |
515 | .matches = { |
516 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE" ), |
517 | DMI_MATCH(DMI_PRODUCT_NAME, "Samus" ), |
518 | }, |
519 | }, |
520 | { |
521 | /* x86-peppy, the Acer C720 Chromebook. */ |
522 | .matches = { |
523 | DMI_MATCH(DMI_SYS_VENDOR, "Acer" ), |
524 | DMI_MATCH(DMI_PRODUCT_NAME, "Peppy" ), |
525 | }, |
526 | }, |
527 | { |
528 | /* x86-glimmer, the Lenovo Thinkpad Yoga 11e. */ |
529 | .matches = { |
530 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE" ), |
531 | DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer" ), |
532 | }, |
533 | }, |
534 | /* A small number of non-Chromebook/box machines also use the ChromeOS EC */ |
535 | { |
536 | /* the Framework Laptop */ |
537 | .matches = { |
538 | DMI_MATCH(DMI_SYS_VENDOR, "Framework" ), |
539 | DMI_MATCH(DMI_PRODUCT_NAME, "Laptop" ), |
540 | }, |
541 | }, |
542 | { /* sentinel */ } |
543 | }; |
544 | MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table); |
545 | |
546 | #ifdef CONFIG_PM_SLEEP |
547 | static int cros_ec_lpc_prepare(struct device *dev) |
548 | { |
549 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); |
550 | return cros_ec_suspend_prepare(ec_dev); |
551 | } |
552 | |
553 | static void cros_ec_lpc_complete(struct device *dev) |
554 | { |
555 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); |
556 | cros_ec_resume_complete(ec_dev); |
557 | } |
558 | |
559 | static int cros_ec_lpc_suspend_late(struct device *dev) |
560 | { |
561 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); |
562 | |
563 | return cros_ec_suspend_late(ec_dev); |
564 | } |
565 | |
566 | static int cros_ec_lpc_resume_early(struct device *dev) |
567 | { |
568 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); |
569 | |
570 | return cros_ec_resume_early(ec_dev); |
571 | } |
572 | #endif |
573 | |
574 | static const struct dev_pm_ops cros_ec_lpc_pm_ops = { |
575 | #ifdef CONFIG_PM_SLEEP |
576 | .prepare = cros_ec_lpc_prepare, |
577 | .complete = cros_ec_lpc_complete, |
578 | #endif |
579 | SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_lpc_suspend_late, cros_ec_lpc_resume_early) |
580 | }; |
581 | |
582 | static struct platform_driver cros_ec_lpc_driver = { |
583 | .driver = { |
584 | .name = DRV_NAME, |
585 | .acpi_match_table = cros_ec_lpc_acpi_device_ids, |
586 | .pm = &cros_ec_lpc_pm_ops, |
587 | /* |
588 | * ACPI child devices may probe before us, and they racily |
589 | * check our drvdata pointer. Force synchronous probe until |
590 | * those races are resolved. |
591 | */ |
592 | .probe_type = PROBE_FORCE_SYNCHRONOUS, |
593 | }, |
594 | .probe = cros_ec_lpc_probe, |
595 | .remove_new = cros_ec_lpc_remove, |
596 | }; |
597 | |
598 | static struct platform_device cros_ec_lpc_device = { |
599 | .name = DRV_NAME |
600 | }; |
601 | |
602 | static acpi_status cros_ec_lpc_parse_device(acpi_handle handle, u32 level, |
603 | void *context, void **retval) |
604 | { |
605 | *(bool *)context = true; |
606 | return AE_CTRL_TERMINATE; |
607 | } |
608 | |
609 | static int __init cros_ec_lpc_init(void) |
610 | { |
611 | int ret; |
612 | acpi_status status; |
613 | |
614 | status = acpi_get_devices(ACPI_DRV_NAME, user_function: cros_ec_lpc_parse_device, |
615 | context: &cros_ec_lpc_acpi_device_found, NULL); |
616 | if (ACPI_FAILURE(status)) |
617 | pr_warn(DRV_NAME ": Looking for %s failed\n" , ACPI_DRV_NAME); |
618 | |
619 | if (!cros_ec_lpc_acpi_device_found && |
620 | !dmi_check_system(list: cros_ec_lpc_dmi_table)) { |
621 | pr_err(DRV_NAME ": unsupported system.\n" ); |
622 | return -ENODEV; |
623 | } |
624 | |
625 | /* Register the driver */ |
626 | ret = platform_driver_register(&cros_ec_lpc_driver); |
627 | if (ret) { |
628 | pr_err(DRV_NAME ": can't register driver: %d\n" , ret); |
629 | return ret; |
630 | } |
631 | |
632 | if (!cros_ec_lpc_acpi_device_found) { |
633 | /* Register the device, and it'll get hooked up automatically */ |
634 | ret = platform_device_register(&cros_ec_lpc_device); |
635 | if (ret) { |
636 | pr_err(DRV_NAME ": can't register device: %d\n" , ret); |
637 | platform_driver_unregister(&cros_ec_lpc_driver); |
638 | } |
639 | } |
640 | |
641 | return ret; |
642 | } |
643 | |
644 | static void __exit cros_ec_lpc_exit(void) |
645 | { |
646 | if (!cros_ec_lpc_acpi_device_found) |
647 | platform_device_unregister(&cros_ec_lpc_device); |
648 | platform_driver_unregister(&cros_ec_lpc_driver); |
649 | } |
650 | |
651 | module_init(cros_ec_lpc_init); |
652 | module_exit(cros_ec_lpc_exit); |
653 | |
654 | MODULE_LICENSE("GPL" ); |
655 | MODULE_DESCRIPTION("ChromeOS EC LPC driver" ); |
656 | |