Linux Audio

Check our new training course

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