8dc2c267bcd68f10a192f3acb337d6dddf2376df
[linux-2.6-microblaze.git] / drivers / platform / surface / aggregator / core.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Surface Serial Hub (SSH) driver for communication with the Surface/System
4  * Aggregator Module (SSAM/SAM).
5  *
6  * Provides access to a SAM-over-SSH connected EC via a controller device.
7  * Handles communication via requests as well as enabling, disabling, and
8  * relaying of events.
9  *
10  * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
11  */
12
13 #include <linux/acpi.h>
14 #include <linux/atomic.h>
15 #include <linux/completion.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/kernel.h>
18 #include <linux/kref.h>
19 #include <linux/module.h>
20 #include <linux/pm.h>
21 #include <linux/serdev.h>
22 #include <linux/sysfs.h>
23
24 #include <linux/surface_aggregator/controller.h>
25
26 #include "bus.h"
27 #include "controller.h"
28
29 #define CREATE_TRACE_POINTS
30 #include "trace.h"
31
32
33 /* -- Static controller reference. ------------------------------------------ */
34
35 /*
36  * Main controller reference. The corresponding lock must be held while
37  * accessing (reading/writing) the reference.
38  */
39 static struct ssam_controller *__ssam_controller;
40 static DEFINE_SPINLOCK(__ssam_controller_lock);
41
42 /**
43  * ssam_get_controller() - Get reference to SSAM controller.
44  *
45  * Returns a reference to the SSAM controller of the system or %NULL if there
46  * is none, it hasn't been set up yet, or it has already been unregistered.
47  * This function automatically increments the reference count of the
48  * controller, thus the calling party must ensure that ssam_controller_put()
49  * is called when it doesn't need the controller any more.
50  */
51 struct ssam_controller *ssam_get_controller(void)
52 {
53         struct ssam_controller *ctrl;
54
55         spin_lock(&__ssam_controller_lock);
56
57         ctrl = __ssam_controller;
58         if (!ctrl)
59                 goto out;
60
61         if (WARN_ON(!kref_get_unless_zero(&ctrl->kref)))
62                 ctrl = NULL;
63
64 out:
65         spin_unlock(&__ssam_controller_lock);
66         return ctrl;
67 }
68 EXPORT_SYMBOL_GPL(ssam_get_controller);
69
70 /**
71  * ssam_try_set_controller() - Try to set the main controller reference.
72  * @ctrl: The controller to which the reference should point.
73  *
74  * Set the main controller reference to the given pointer if the reference
75  * hasn't been set already.
76  *
77  * Return: Returns zero on success or %-EEXIST if the reference has already
78  * been set.
79  */
80 static int ssam_try_set_controller(struct ssam_controller *ctrl)
81 {
82         int status = 0;
83
84         spin_lock(&__ssam_controller_lock);
85         if (!__ssam_controller)
86                 __ssam_controller = ctrl;
87         else
88                 status = -EEXIST;
89         spin_unlock(&__ssam_controller_lock);
90
91         return status;
92 }
93
94 /**
95  * ssam_clear_controller() - Remove/clear the main controller reference.
96  *
97  * Clears the main controller reference, i.e. sets it to %NULL. This function
98  * should be called before the controller is shut down.
99  */
100 static void ssam_clear_controller(void)
101 {
102         spin_lock(&__ssam_controller_lock);
103         __ssam_controller = NULL;
104         spin_unlock(&__ssam_controller_lock);
105 }
106
107 /**
108  * ssam_client_link() - Link an arbitrary client device to the controller.
109  * @c: The controller to link to.
110  * @client: The client device.
111  *
112  * Link an arbitrary client device to the controller by creating a device link
113  * between it as consumer and the controller device as provider. This function
114  * can be used for non-SSAM devices (or SSAM devices not registered as child
115  * under the controller) to guarantee that the controller is valid for as long
116  * as the driver of the client device is bound, and that proper suspend and
117  * resume ordering is guaranteed.
118  *
119  * The device link does not have to be destructed manually. It is removed
120  * automatically once the driver of the client device unbinds.
121  *
122  * Return: Returns zero on success, %-ENODEV if the controller is not ready or
123  * going to be removed soon, or %-ENOMEM if the device link could not be
124  * created for other reasons.
125  */
126 int ssam_client_link(struct ssam_controller *c, struct device *client)
127 {
128         const u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER;
129         struct device_link *link;
130         struct device *ctrldev;
131
132         ssam_controller_statelock(c);
133
134         if (c->state != SSAM_CONTROLLER_STARTED) {
135                 ssam_controller_stateunlock(c);
136                 return -ENODEV;
137         }
138
139         ctrldev = ssam_controller_device(c);
140         if (!ctrldev) {
141                 ssam_controller_stateunlock(c);
142                 return -ENODEV;
143         }
144
145         link = device_link_add(client, ctrldev, flags);
146         if (!link) {
147                 ssam_controller_stateunlock(c);
148                 return -ENOMEM;
149         }
150
151         /*
152          * Return -ENODEV if supplier driver is on its way to be removed. In
153          * this case, the controller won't be around for much longer and the
154          * device link is not going to save us any more, as unbinding is
155          * already in progress.
156          */
157         if (READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND) {
158                 ssam_controller_stateunlock(c);
159                 return -ENODEV;
160         }
161
162         ssam_controller_stateunlock(c);
163         return 0;
164 }
165 EXPORT_SYMBOL_GPL(ssam_client_link);
166
167 /**
168  * ssam_client_bind() - Bind an arbitrary client device to the controller.
169  * @client: The client device.
170  *
171  * Link an arbitrary client device to the controller by creating a device link
172  * between it as consumer and the main controller device as provider. This
173  * function can be used for non-SSAM devices to guarantee that the controller
174  * returned by this function is valid for as long as the driver of the client
175  * device is bound, and that proper suspend and resume ordering is guaranteed.
176  *
177  * This function does essentially the same as ssam_client_link(), except that
178  * it first fetches the main controller reference, then creates the link, and
179  * finally returns this reference. Note that this function does not increment
180  * the reference counter of the controller, as, due to the link, the
181  * controller lifetime is assured as long as the driver of the client device
182  * is bound.
183  *
184  * It is not valid to use the controller reference obtained by this method
185  * outside of the driver bound to the client device at the time of calling
186  * this function, without first incrementing the reference count of the
187  * controller via ssam_controller_get(). Even after doing this, care must be
188  * taken that requests are only submitted and notifiers are only
189  * (un-)registered when the controller is active and not suspended. In other
190  * words: The device link only lives as long as the client driver is bound and
191  * any guarantees enforced by this link (e.g. active controller state) can
192  * only be relied upon as long as this link exists and may need to be enforced
193  * in other ways afterwards.
194  *
195  * The created device link does not have to be destructed manually. It is
196  * removed automatically once the driver of the client device unbinds.
197  *
198  * Return: Returns the controller on success, an error pointer with %-ENODEV
199  * if the controller is not present, not ready or going to be removed soon, or
200  * %-ENOMEM if the device link could not be created for other reasons.
201  */
202 struct ssam_controller *ssam_client_bind(struct device *client)
203 {
204         struct ssam_controller *c;
205         int status;
206
207         c = ssam_get_controller();
208         if (!c)
209                 return ERR_PTR(-ENODEV);
210
211         status = ssam_client_link(c, client);
212
213         /*
214          * Note that we can drop our controller reference in both success and
215          * failure cases: On success, we have bound the controller lifetime
216          * inherently to the client driver lifetime, i.e. it the controller is
217          * now guaranteed to outlive the client driver. On failure, we're not
218          * going to use the controller any more.
219          */
220         ssam_controller_put(c);
221
222         return status >= 0 ? c : ERR_PTR(status);
223 }
224 EXPORT_SYMBOL_GPL(ssam_client_bind);
225
226
227 /* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */
228
229 static int ssam_receive_buf(struct serdev_device *dev, const unsigned char *buf,
230                             size_t n)
231 {
232         struct ssam_controller *ctrl;
233
234         ctrl = serdev_device_get_drvdata(dev);
235         return ssam_controller_receive_buf(ctrl, buf, n);
236 }
237
238 static void ssam_write_wakeup(struct serdev_device *dev)
239 {
240         ssam_controller_write_wakeup(serdev_device_get_drvdata(dev));
241 }
242
243 static const struct serdev_device_ops ssam_serdev_ops = {
244         .receive_buf = ssam_receive_buf,
245         .write_wakeup = ssam_write_wakeup,
246 };
247
248
249 /* -- SysFS and misc. ------------------------------------------------------- */
250
251 static int ssam_log_firmware_version(struct ssam_controller *ctrl)
252 {
253         u32 version, a, b, c;
254         int status;
255
256         status = ssam_get_firmware_version(ctrl, &version);
257         if (status)
258                 return status;
259
260         a = (version >> 24) & 0xff;
261         b = ((version >> 8) & 0xffff);
262         c = version & 0xff;
263
264         ssam_info(ctrl, "SAM firmware version: %u.%u.%u\n", a, b, c);
265         return 0;
266 }
267
268 static ssize_t firmware_version_show(struct device *dev,
269                                      struct device_attribute *attr, char *buf)
270 {
271         struct ssam_controller *ctrl = dev_get_drvdata(dev);
272         u32 version, a, b, c;
273         int status;
274
275         status = ssam_get_firmware_version(ctrl, &version);
276         if (status < 0)
277                 return status;
278
279         a = (version >> 24) & 0xff;
280         b = ((version >> 8) & 0xffff);
281         c = version & 0xff;
282
283         return sysfs_emit(buf, "%u.%u.%u\n", a, b, c);
284 }
285 static DEVICE_ATTR_RO(firmware_version);
286
287 static struct attribute *ssam_sam_attrs[] = {
288         &dev_attr_firmware_version.attr,
289         NULL
290 };
291
292 static const struct attribute_group ssam_sam_group = {
293         .name = "sam",
294         .attrs = ssam_sam_attrs,
295 };
296
297
298 /* -- ACPI based device setup. ---------------------------------------------- */
299
300 static acpi_status ssam_serdev_setup_via_acpi_crs(struct acpi_resource *rsc,
301                                                   void *ctx)
302 {
303         struct serdev_device *serdev = ctx;
304         struct acpi_resource_common_serialbus *serial;
305         struct acpi_resource_uart_serialbus *uart;
306         bool flow_control;
307         int status = 0;
308
309         if (rsc->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
310                 return AE_OK;
311
312         serial = &rsc->data.common_serial_bus;
313         if (serial->type != ACPI_RESOURCE_SERIAL_TYPE_UART)
314                 return AE_OK;
315
316         uart = &rsc->data.uart_serial_bus;
317
318         /* Set up serdev device. */
319         serdev_device_set_baudrate(serdev, uart->default_baud_rate);
320
321         /* serdev currently only supports RTSCTS flow control. */
322         if (uart->flow_control & (~((u8)ACPI_UART_FLOW_CONTROL_HW))) {
323                 dev_warn(&serdev->dev, "setup: unsupported flow control (value: %#04x)\n",
324                          uart->flow_control);
325         }
326
327         /* Set RTSCTS flow control. */
328         flow_control = uart->flow_control & ACPI_UART_FLOW_CONTROL_HW;
329         serdev_device_set_flow_control(serdev, flow_control);
330
331         /* serdev currently only supports EVEN/ODD parity. */
332         switch (uart->parity) {
333         case ACPI_UART_PARITY_NONE:
334                 status = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
335                 break;
336         case ACPI_UART_PARITY_EVEN:
337                 status = serdev_device_set_parity(serdev, SERDEV_PARITY_EVEN);
338                 break;
339         case ACPI_UART_PARITY_ODD:
340                 status = serdev_device_set_parity(serdev, SERDEV_PARITY_ODD);
341                 break;
342         default:
343                 dev_warn(&serdev->dev, "setup: unsupported parity (value: %#04x)\n",
344                          uart->parity);
345                 break;
346         }
347
348         if (status) {
349                 dev_err(&serdev->dev, "setup: failed to set parity (value: %#04x, error: %d)\n",
350                         uart->parity, status);
351                 return AE_ERROR;
352         }
353
354         /* We've found the resource and are done. */
355         return AE_CTRL_TERMINATE;
356 }
357
358 static acpi_status ssam_serdev_setup_via_acpi(acpi_handle handle,
359                                               struct serdev_device *serdev)
360 {
361         return acpi_walk_resources(handle, METHOD_NAME__CRS,
362                                    ssam_serdev_setup_via_acpi_crs, serdev);
363 }
364
365
366 /* -- Power management. ----------------------------------------------------- */
367
368 static void ssam_serial_hub_shutdown(struct device *dev)
369 {
370         struct ssam_controller *c = dev_get_drvdata(dev);
371         int status;
372
373         /*
374          * Try to disable notifiers, signal display-off and D0-exit, ignore any
375          * errors.
376          *
377          * Note: It has not been established yet if this is actually
378          * necessary/useful for shutdown.
379          */
380
381         status = ssam_notifier_disable_registered(c);
382         if (status) {
383                 ssam_err(c, "pm: failed to disable notifiers for shutdown: %d\n",
384                          status);
385         }
386
387         status = ssam_ctrl_notif_display_off(c);
388         if (status)
389                 ssam_err(c, "pm: display-off notification failed: %d\n", status);
390
391         status = ssam_ctrl_notif_d0_exit(c);
392         if (status)
393                 ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
394 }
395
396 #ifdef CONFIG_PM_SLEEP
397
398 static int ssam_serial_hub_pm_prepare(struct device *dev)
399 {
400         struct ssam_controller *c = dev_get_drvdata(dev);
401         int status;
402
403         /*
404          * Try to signal display-off, This will quiesce events.
405          *
406          * Note: Signaling display-off/display-on should normally be done from
407          * some sort of display state notifier. As that is not available,
408          * signal it here.
409          */
410
411         status = ssam_ctrl_notif_display_off(c);
412         if (status)
413                 ssam_err(c, "pm: display-off notification failed: %d\n", status);
414
415         return status;
416 }
417
418 static void ssam_serial_hub_pm_complete(struct device *dev)
419 {
420         struct ssam_controller *c = dev_get_drvdata(dev);
421         int status;
422
423         /*
424          * Try to signal display-on. This will restore events.
425          *
426          * Note: Signaling display-off/display-on should normally be done from
427          * some sort of display state notifier. As that is not available,
428          * signal it here.
429          */
430
431         status = ssam_ctrl_notif_display_on(c);
432         if (status)
433                 ssam_err(c, "pm: display-on notification failed: %d\n", status);
434 }
435
436 static int ssam_serial_hub_pm_suspend(struct device *dev)
437 {
438         struct ssam_controller *c = dev_get_drvdata(dev);
439         int status;
440
441         /*
442          * Try to signal D0-exit, enable IRQ wakeup if specified. Abort on
443          * error.
444          */
445
446         status = ssam_ctrl_notif_d0_exit(c);
447         if (status) {
448                 ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
449                 goto err_notif;
450         }
451
452         status = ssam_irq_arm_for_wakeup(c);
453         if (status)
454                 goto err_irq;
455
456         WARN_ON(ssam_controller_suspend(c));
457         return 0;
458
459 err_irq:
460         ssam_ctrl_notif_d0_entry(c);
461 err_notif:
462         ssam_ctrl_notif_display_on(c);
463         return status;
464 }
465
466 static int ssam_serial_hub_pm_resume(struct device *dev)
467 {
468         struct ssam_controller *c = dev_get_drvdata(dev);
469         int status;
470
471         WARN_ON(ssam_controller_resume(c));
472
473         /*
474          * Try to disable IRQ wakeup (if specified) and signal D0-entry. In
475          * case of errors, log them and try to restore normal operation state
476          * as far as possible.
477          *
478          * Note: Signaling display-off/display-on should normally be done from
479          * some sort of display state notifier. As that is not available,
480          * signal it here.
481          */
482
483         ssam_irq_disarm_wakeup(c);
484
485         status = ssam_ctrl_notif_d0_entry(c);
486         if (status)
487                 ssam_err(c, "pm: D0-entry notification failed: %d\n", status);
488
489         return 0;
490 }
491
492 static int ssam_serial_hub_pm_freeze(struct device *dev)
493 {
494         struct ssam_controller *c = dev_get_drvdata(dev);
495         int status;
496
497         /*
498          * During hibernation image creation, we only have to ensure that the
499          * EC doesn't send us any events. This is done via the display-off
500          * and D0-exit notifications. Note that this sets up the wakeup IRQ
501          * on the EC side, however, we have disabled it by default on our side
502          * and won't enable it here.
503          *
504          * See ssam_serial_hub_poweroff() for more details on the hibernation
505          * process.
506          */
507
508         status = ssam_ctrl_notif_d0_exit(c);
509         if (status) {
510                 ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
511                 ssam_ctrl_notif_display_on(c);
512                 return status;
513         }
514
515         WARN_ON(ssam_controller_suspend(c));
516         return 0;
517 }
518
519 static int ssam_serial_hub_pm_thaw(struct device *dev)
520 {
521         struct ssam_controller *c = dev_get_drvdata(dev);
522         int status;
523
524         WARN_ON(ssam_controller_resume(c));
525
526         status = ssam_ctrl_notif_d0_entry(c);
527         if (status)
528                 ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
529
530         return status;
531 }
532
533 static int ssam_serial_hub_pm_poweroff(struct device *dev)
534 {
535         struct ssam_controller *c = dev_get_drvdata(dev);
536         int status;
537
538         /*
539          * When entering hibernation and powering off the system, the EC, at
540          * least on some models, may disable events. Without us taking care of
541          * that, this leads to events not being enabled/restored when the
542          * system resumes from hibernation, resulting SAM-HID subsystem devices
543          * (i.e. keyboard, touchpad) not working, AC-plug/AC-unplug events being
544          * gone, etc.
545          *
546          * To avoid these issues, we disable all registered events here (this is
547          * likely not actually required) and restore them during the drivers PM
548          * restore callback.
549          *
550          * Wakeup from the EC interrupt is not supported during hibernation,
551          * so don't arm the IRQ here.
552          */
553
554         status = ssam_notifier_disable_registered(c);
555         if (status) {
556                 ssam_err(c, "pm: failed to disable notifiers for hibernation: %d\n",
557                          status);
558                 return status;
559         }
560
561         status = ssam_ctrl_notif_d0_exit(c);
562         if (status) {
563                 ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
564                 ssam_notifier_restore_registered(c);
565                 return status;
566         }
567
568         WARN_ON(ssam_controller_suspend(c));
569         return 0;
570 }
571
572 static int ssam_serial_hub_pm_restore(struct device *dev)
573 {
574         struct ssam_controller *c = dev_get_drvdata(dev);
575         int status;
576
577         /*
578          * Ignore but log errors, try to restore state as much as possible in
579          * case of failures. See ssam_serial_hub_poweroff() for more details on
580          * the hibernation process.
581          */
582
583         WARN_ON(ssam_controller_resume(c));
584
585         status = ssam_ctrl_notif_d0_entry(c);
586         if (status)
587                 ssam_err(c, "pm: D0-entry notification failed: %d\n", status);
588
589         ssam_notifier_restore_registered(c);
590         return 0;
591 }
592
593 static const struct dev_pm_ops ssam_serial_hub_pm_ops = {
594         .prepare  = ssam_serial_hub_pm_prepare,
595         .complete = ssam_serial_hub_pm_complete,
596         .suspend  = ssam_serial_hub_pm_suspend,
597         .resume   = ssam_serial_hub_pm_resume,
598         .freeze   = ssam_serial_hub_pm_freeze,
599         .thaw     = ssam_serial_hub_pm_thaw,
600         .poweroff = ssam_serial_hub_pm_poweroff,
601         .restore  = ssam_serial_hub_pm_restore,
602 };
603
604 #else /* CONFIG_PM_SLEEP */
605
606 static const struct dev_pm_ops ssam_serial_hub_pm_ops = { };
607
608 #endif /* CONFIG_PM_SLEEP */
609
610
611 /* -- Device/driver setup. -------------------------------------------------- */
612
613 static const struct acpi_gpio_params gpio_ssam_wakeup_int = { 0, 0, false };
614 static const struct acpi_gpio_params gpio_ssam_wakeup     = { 1, 0, false };
615
616 static const struct acpi_gpio_mapping ssam_acpi_gpios[] = {
617         { "ssam_wakeup-int-gpio", &gpio_ssam_wakeup_int, 1 },
618         { "ssam_wakeup-gpio",     &gpio_ssam_wakeup,     1 },
619         { },
620 };
621
622 static int ssam_serial_hub_probe(struct serdev_device *serdev)
623 {
624         struct ssam_controller *ctrl;
625         acpi_handle *ssh = ACPI_HANDLE(&serdev->dev);
626         acpi_status astatus;
627         int status;
628
629         if (gpiod_count(&serdev->dev, NULL) < 0)
630                 return -ENODEV;
631
632         status = devm_acpi_dev_add_driver_gpios(&serdev->dev, ssam_acpi_gpios);
633         if (status)
634                 return status;
635
636         /* Allocate controller. */
637         ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
638         if (!ctrl)
639                 return -ENOMEM;
640
641         /* Initialize controller. */
642         status = ssam_controller_init(ctrl, serdev);
643         if (status)
644                 goto err_ctrl_init;
645
646         ssam_controller_lock(ctrl);
647
648         /* Set up serdev device. */
649         serdev_device_set_drvdata(serdev, ctrl);
650         serdev_device_set_client_ops(serdev, &ssam_serdev_ops);
651         status = serdev_device_open(serdev);
652         if (status)
653                 goto err_devopen;
654
655         astatus = ssam_serdev_setup_via_acpi(ssh, serdev);
656         if (ACPI_FAILURE(astatus)) {
657                 status = -ENXIO;
658                 goto err_devinit;
659         }
660
661         /* Start controller. */
662         status = ssam_controller_start(ctrl);
663         if (status)
664                 goto err_devinit;
665
666         ssam_controller_unlock(ctrl);
667
668         /*
669          * Initial SAM requests: Log version and notify default/init power
670          * states.
671          */
672         status = ssam_log_firmware_version(ctrl);
673         if (status)
674                 goto err_initrq;
675
676         status = ssam_ctrl_notif_d0_entry(ctrl);
677         if (status)
678                 goto err_initrq;
679
680         status = ssam_ctrl_notif_display_on(ctrl);
681         if (status)
682                 goto err_initrq;
683
684         status = sysfs_create_group(&serdev->dev.kobj, &ssam_sam_group);
685         if (status)
686                 goto err_initrq;
687
688         /* Set up IRQ. */
689         status = ssam_irq_setup(ctrl);
690         if (status)
691                 goto err_irq;
692
693         /* Finally, set main controller reference. */
694         status = ssam_try_set_controller(ctrl);
695         if (WARN_ON(status))    /* Currently, we're the only provider. */
696                 goto err_mainref;
697
698         /*
699          * TODO: The EC can wake up the system via the associated GPIO interrupt
700          *       in multiple situations. One of which is the remaining battery
701          *       capacity falling below a certain threshold. Normally, we should
702          *       use the device_init_wakeup function, however, the EC also seems
703          *       to have other reasons for waking up the system and it seems
704          *       that Windows has additional checks whether the system should be
705          *       resumed. In short, this causes some spurious unwanted wake-ups.
706          *       For now let's thus default power/wakeup to false.
707          */
708         device_set_wakeup_capable(&serdev->dev, true);
709         acpi_walk_dep_device_list(ssh);
710
711         return 0;
712
713 err_mainref:
714         ssam_irq_free(ctrl);
715 err_irq:
716         sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
717 err_initrq:
718         ssam_controller_lock(ctrl);
719         ssam_controller_shutdown(ctrl);
720 err_devinit:
721         serdev_device_close(serdev);
722 err_devopen:
723         ssam_controller_destroy(ctrl);
724         ssam_controller_unlock(ctrl);
725 err_ctrl_init:
726         kfree(ctrl);
727         return status;
728 }
729
730 static void ssam_serial_hub_remove(struct serdev_device *serdev)
731 {
732         struct ssam_controller *ctrl = serdev_device_get_drvdata(serdev);
733         int status;
734
735         /* Clear static reference so that no one else can get a new one. */
736         ssam_clear_controller();
737
738         /* Disable and free IRQ. */
739         ssam_irq_free(ctrl);
740
741         sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
742         ssam_controller_lock(ctrl);
743
744         /* Remove all client devices. */
745         ssam_controller_remove_clients(ctrl);
746
747         /* Act as if suspending to silence events. */
748         status = ssam_ctrl_notif_display_off(ctrl);
749         if (status) {
750                 dev_err(&serdev->dev, "display-off notification failed: %d\n",
751                         status);
752         }
753
754         status = ssam_ctrl_notif_d0_exit(ctrl);
755         if (status) {
756                 dev_err(&serdev->dev, "D0-exit notification failed: %d\n",
757                         status);
758         }
759
760         /* Shut down controller and remove serdev device reference from it. */
761         ssam_controller_shutdown(ctrl);
762
763         /* Shut down actual transport. */
764         serdev_device_wait_until_sent(serdev, 0);
765         serdev_device_close(serdev);
766
767         /* Drop our controller reference. */
768         ssam_controller_unlock(ctrl);
769         ssam_controller_put(ctrl);
770
771         device_set_wakeup_capable(&serdev->dev, false);
772 }
773
774 static const struct acpi_device_id ssam_serial_hub_match[] = {
775         { "MSHW0084", 0 },
776         { },
777 };
778 MODULE_DEVICE_TABLE(acpi, ssam_serial_hub_match);
779
780 static struct serdev_device_driver ssam_serial_hub = {
781         .probe = ssam_serial_hub_probe,
782         .remove = ssam_serial_hub_remove,
783         .driver = {
784                 .name = "surface_serial_hub",
785                 .acpi_match_table = ssam_serial_hub_match,
786                 .pm = &ssam_serial_hub_pm_ops,
787                 .shutdown = ssam_serial_hub_shutdown,
788                 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
789         },
790 };
791
792
793 /* -- Module setup. --------------------------------------------------------- */
794
795 static int __init ssam_core_init(void)
796 {
797         int status;
798
799         status = ssam_bus_register();
800         if (status)
801                 goto err_bus;
802
803         status = ssh_ctrl_packet_cache_init();
804         if (status)
805                 goto err_cpkg;
806
807         status = ssam_event_item_cache_init();
808         if (status)
809                 goto err_evitem;
810
811         status = serdev_device_driver_register(&ssam_serial_hub);
812         if (status)
813                 goto err_register;
814
815         return 0;
816
817 err_register:
818         ssam_event_item_cache_destroy();
819 err_evitem:
820         ssh_ctrl_packet_cache_destroy();
821 err_cpkg:
822         ssam_bus_unregister();
823 err_bus:
824         return status;
825 }
826 module_init(ssam_core_init);
827
828 static void __exit ssam_core_exit(void)
829 {
830         serdev_device_driver_unregister(&ssam_serial_hub);
831         ssam_event_item_cache_destroy();
832         ssh_ctrl_packet_cache_destroy();
833         ssam_bus_unregister();
834 }
835 module_exit(ssam_core_exit);
836
837 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
838 MODULE_DESCRIPTION("Subsystem and Surface Serial Hub driver for Surface System Aggregator Module");
839 MODULE_LICENSE("GPL");