linux/drivers/platform/surface/aggregator/core.c
<<
>>
Prefs
   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-2021 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 */
  39static struct ssam_controller *__ssam_controller;
  40static 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 */
  51struct 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
  64out:
  65        spin_unlock(&__ssam_controller_lock);
  66        return ctrl;
  67}
  68EXPORT_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 */
  80static 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 */
 100static 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 */
 126int 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}
 165EXPORT_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 */
 202struct 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}
 224EXPORT_SYMBOL_GPL(ssam_client_bind);
 225
 226
 227/* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */
 228
 229static 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
 238static void ssam_write_wakeup(struct serdev_device *dev)
 239{
 240        ssam_controller_write_wakeup(serdev_device_get_drvdata(dev));
 241}
 242
 243static 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
 251static 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
 268static 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}
 285static DEVICE_ATTR_RO(firmware_version);
 286
 287static struct attribute *ssam_sam_attrs[] = {
 288        &dev_attr_firmware_version.attr,
 289        NULL
 290};
 291
 292static const struct attribute_group ssam_sam_group = {
 293        .name = "sam",
 294        .attrs = ssam_sam_attrs,
 295};
 296
 297
 298/* -- ACPI based device setup. ---------------------------------------------- */
 299
 300static 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_uart_serialbus *uart;
 305        bool flow_control;
 306        int status = 0;
 307
 308        if (!serdev_acpi_get_uart_resource(rsc, &uart))
 309                return AE_OK;
 310
 311        /* Set up serdev device. */
 312        serdev_device_set_baudrate(serdev, uart->default_baud_rate);
 313
 314        /* serdev currently only supports RTSCTS flow control. */
 315        if (uart->flow_control & (~((u8)ACPI_UART_FLOW_CONTROL_HW))) {
 316                dev_warn(&serdev->dev, "setup: unsupported flow control (value: %#04x)\n",
 317                         uart->flow_control);
 318        }
 319
 320        /* Set RTSCTS flow control. */
 321        flow_control = uart->flow_control & ACPI_UART_FLOW_CONTROL_HW;
 322        serdev_device_set_flow_control(serdev, flow_control);
 323
 324        /* serdev currently only supports EVEN/ODD parity. */
 325        switch (uart->parity) {
 326        case ACPI_UART_PARITY_NONE:
 327                status = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
 328                break;
 329        case ACPI_UART_PARITY_EVEN:
 330                status = serdev_device_set_parity(serdev, SERDEV_PARITY_EVEN);
 331                break;
 332        case ACPI_UART_PARITY_ODD:
 333                status = serdev_device_set_parity(serdev, SERDEV_PARITY_ODD);
 334                break;
 335        default:
 336                dev_warn(&serdev->dev, "setup: unsupported parity (value: %#04x)\n",
 337                         uart->parity);
 338                break;
 339        }
 340
 341        if (status) {
 342                dev_err(&serdev->dev, "setup: failed to set parity (value: %#04x, error: %d)\n",
 343                        uart->parity, status);
 344                return AE_ERROR;
 345        }
 346
 347        /* We've found the resource and are done. */
 348        return AE_CTRL_TERMINATE;
 349}
 350
 351static acpi_status ssam_serdev_setup_via_acpi(acpi_handle handle,
 352                                              struct serdev_device *serdev)
 353{
 354        return acpi_walk_resources(handle, METHOD_NAME__CRS,
 355                                   ssam_serdev_setup_via_acpi_crs, serdev);
 356}
 357
 358
 359/* -- Power management. ----------------------------------------------------- */
 360
 361static void ssam_serial_hub_shutdown(struct device *dev)
 362{
 363        struct ssam_controller *c = dev_get_drvdata(dev);
 364        int status;
 365
 366        /*
 367         * Try to disable notifiers, signal display-off and D0-exit, ignore any
 368         * errors.
 369         *
 370         * Note: It has not been established yet if this is actually
 371         * necessary/useful for shutdown.
 372         */
 373
 374        status = ssam_notifier_disable_registered(c);
 375        if (status) {
 376                ssam_err(c, "pm: failed to disable notifiers for shutdown: %d\n",
 377                         status);
 378        }
 379
 380        status = ssam_ctrl_notif_display_off(c);
 381        if (status)
 382                ssam_err(c, "pm: display-off notification failed: %d\n", status);
 383
 384        status = ssam_ctrl_notif_d0_exit(c);
 385        if (status)
 386                ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
 387}
 388
 389#ifdef CONFIG_PM_SLEEP
 390
 391static int ssam_serial_hub_pm_prepare(struct device *dev)
 392{
 393        struct ssam_controller *c = dev_get_drvdata(dev);
 394        int status;
 395
 396        /*
 397         * Try to signal display-off, This will quiesce events.
 398         *
 399         * Note: Signaling display-off/display-on should normally be done from
 400         * some sort of display state notifier. As that is not available,
 401         * signal it here.
 402         */
 403
 404        status = ssam_ctrl_notif_display_off(c);
 405        if (status)
 406                ssam_err(c, "pm: display-off notification failed: %d\n", status);
 407
 408        return status;
 409}
 410
 411static void ssam_serial_hub_pm_complete(struct device *dev)
 412{
 413        struct ssam_controller *c = dev_get_drvdata(dev);
 414        int status;
 415
 416        /*
 417         * Try to signal display-on. This will restore events.
 418         *
 419         * Note: Signaling display-off/display-on should normally be done from
 420         * some sort of display state notifier. As that is not available,
 421         * signal it here.
 422         */
 423
 424        status = ssam_ctrl_notif_display_on(c);
 425        if (status)
 426                ssam_err(c, "pm: display-on notification failed: %d\n", status);
 427}
 428
 429static int ssam_serial_hub_pm_suspend(struct device *dev)
 430{
 431        struct ssam_controller *c = dev_get_drvdata(dev);
 432        int status;
 433
 434        /*
 435         * Try to signal D0-exit, enable IRQ wakeup if specified. Abort on
 436         * error.
 437         */
 438
 439        status = ssam_ctrl_notif_d0_exit(c);
 440        if (status) {
 441                ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
 442                goto err_notif;
 443        }
 444
 445        status = ssam_irq_arm_for_wakeup(c);
 446        if (status)
 447                goto err_irq;
 448
 449        WARN_ON(ssam_controller_suspend(c));
 450        return 0;
 451
 452err_irq:
 453        ssam_ctrl_notif_d0_entry(c);
 454err_notif:
 455        ssam_ctrl_notif_display_on(c);
 456        return status;
 457}
 458
 459static int ssam_serial_hub_pm_resume(struct device *dev)
 460{
 461        struct ssam_controller *c = dev_get_drvdata(dev);
 462        int status;
 463
 464        WARN_ON(ssam_controller_resume(c));
 465
 466        /*
 467         * Try to disable IRQ wakeup (if specified) and signal D0-entry. In
 468         * case of errors, log them and try to restore normal operation state
 469         * as far as possible.
 470         *
 471         * Note: Signaling display-off/display-on should normally be done from
 472         * some sort of display state notifier. As that is not available,
 473         * signal it here.
 474         */
 475
 476        ssam_irq_disarm_wakeup(c);
 477
 478        status = ssam_ctrl_notif_d0_entry(c);
 479        if (status)
 480                ssam_err(c, "pm: D0-entry notification failed: %d\n", status);
 481
 482        return 0;
 483}
 484
 485static int ssam_serial_hub_pm_freeze(struct device *dev)
 486{
 487        struct ssam_controller *c = dev_get_drvdata(dev);
 488        int status;
 489
 490        /*
 491         * During hibernation image creation, we only have to ensure that the
 492         * EC doesn't send us any events. This is done via the display-off
 493         * and D0-exit notifications. Note that this sets up the wakeup IRQ
 494         * on the EC side, however, we have disabled it by default on our side
 495         * and won't enable it here.
 496         *
 497         * See ssam_serial_hub_poweroff() for more details on the hibernation
 498         * process.
 499         */
 500
 501        status = ssam_ctrl_notif_d0_exit(c);
 502        if (status) {
 503                ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
 504                ssam_ctrl_notif_display_on(c);
 505                return status;
 506        }
 507
 508        WARN_ON(ssam_controller_suspend(c));
 509        return 0;
 510}
 511
 512static int ssam_serial_hub_pm_thaw(struct device *dev)
 513{
 514        struct ssam_controller *c = dev_get_drvdata(dev);
 515        int status;
 516
 517        WARN_ON(ssam_controller_resume(c));
 518
 519        status = ssam_ctrl_notif_d0_entry(c);
 520        if (status)
 521                ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
 522
 523        return status;
 524}
 525
 526static int ssam_serial_hub_pm_poweroff(struct device *dev)
 527{
 528        struct ssam_controller *c = dev_get_drvdata(dev);
 529        int status;
 530
 531        /*
 532         * When entering hibernation and powering off the system, the EC, at
 533         * least on some models, may disable events. Without us taking care of
 534         * that, this leads to events not being enabled/restored when the
 535         * system resumes from hibernation, resulting SAM-HID subsystem devices
 536         * (i.e. keyboard, touchpad) not working, AC-plug/AC-unplug events being
 537         * gone, etc.
 538         *
 539         * To avoid these issues, we disable all registered events here (this is
 540         * likely not actually required) and restore them during the drivers PM
 541         * restore callback.
 542         *
 543         * Wakeup from the EC interrupt is not supported during hibernation,
 544         * so don't arm the IRQ here.
 545         */
 546
 547        status = ssam_notifier_disable_registered(c);
 548        if (status) {
 549                ssam_err(c, "pm: failed to disable notifiers for hibernation: %d\n",
 550                         status);
 551                return status;
 552        }
 553
 554        status = ssam_ctrl_notif_d0_exit(c);
 555        if (status) {
 556                ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
 557                ssam_notifier_restore_registered(c);
 558                return status;
 559        }
 560
 561        WARN_ON(ssam_controller_suspend(c));
 562        return 0;
 563}
 564
 565static int ssam_serial_hub_pm_restore(struct device *dev)
 566{
 567        struct ssam_controller *c = dev_get_drvdata(dev);
 568        int status;
 569
 570        /*
 571         * Ignore but log errors, try to restore state as much as possible in
 572         * case of failures. See ssam_serial_hub_poweroff() for more details on
 573         * the hibernation process.
 574         */
 575
 576        WARN_ON(ssam_controller_resume(c));
 577
 578        status = ssam_ctrl_notif_d0_entry(c);
 579        if (status)
 580                ssam_err(c, "pm: D0-entry notification failed: %d\n", status);
 581
 582        ssam_notifier_restore_registered(c);
 583        return 0;
 584}
 585
 586static const struct dev_pm_ops ssam_serial_hub_pm_ops = {
 587        .prepare  = ssam_serial_hub_pm_prepare,
 588        .complete = ssam_serial_hub_pm_complete,
 589        .suspend  = ssam_serial_hub_pm_suspend,
 590        .resume   = ssam_serial_hub_pm_resume,
 591        .freeze   = ssam_serial_hub_pm_freeze,
 592        .thaw     = ssam_serial_hub_pm_thaw,
 593        .poweroff = ssam_serial_hub_pm_poweroff,
 594        .restore  = ssam_serial_hub_pm_restore,
 595};
 596
 597#else /* CONFIG_PM_SLEEP */
 598
 599static const struct dev_pm_ops ssam_serial_hub_pm_ops = { };
 600
 601#endif /* CONFIG_PM_SLEEP */
 602
 603
 604/* -- Device/driver setup. -------------------------------------------------- */
 605
 606static const struct acpi_gpio_params gpio_ssam_wakeup_int = { 0, 0, false };
 607static const struct acpi_gpio_params gpio_ssam_wakeup     = { 1, 0, false };
 608
 609static const struct acpi_gpio_mapping ssam_acpi_gpios[] = {
 610        { "ssam_wakeup-int-gpio", &gpio_ssam_wakeup_int, 1 },
 611        { "ssam_wakeup-gpio",     &gpio_ssam_wakeup,     1 },
 612        { },
 613};
 614
 615static int ssam_serial_hub_probe(struct serdev_device *serdev)
 616{
 617        struct acpi_device *ssh = ACPI_COMPANION(&serdev->dev);
 618        struct ssam_controller *ctrl;
 619        acpi_status astatus;
 620        int status;
 621
 622        if (gpiod_count(&serdev->dev, NULL) < 0)
 623                return -ENODEV;
 624
 625        status = devm_acpi_dev_add_driver_gpios(&serdev->dev, ssam_acpi_gpios);
 626        if (status)
 627                return status;
 628
 629        /* Allocate controller. */
 630        ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
 631        if (!ctrl)
 632                return -ENOMEM;
 633
 634        /* Initialize controller. */
 635        status = ssam_controller_init(ctrl, serdev);
 636        if (status)
 637                goto err_ctrl_init;
 638
 639        ssam_controller_lock(ctrl);
 640
 641        /* Set up serdev device. */
 642        serdev_device_set_drvdata(serdev, ctrl);
 643        serdev_device_set_client_ops(serdev, &ssam_serdev_ops);
 644        status = serdev_device_open(serdev);
 645        if (status)
 646                goto err_devopen;
 647
 648        astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev);
 649        if (ACPI_FAILURE(astatus)) {
 650                status = -ENXIO;
 651                goto err_devinit;
 652        }
 653
 654        /* Start controller. */
 655        status = ssam_controller_start(ctrl);
 656        if (status)
 657                goto err_devinit;
 658
 659        ssam_controller_unlock(ctrl);
 660
 661        /*
 662         * Initial SAM requests: Log version and notify default/init power
 663         * states.
 664         */
 665        status = ssam_log_firmware_version(ctrl);
 666        if (status)
 667                goto err_initrq;
 668
 669        status = ssam_ctrl_notif_d0_entry(ctrl);
 670        if (status)
 671                goto err_initrq;
 672
 673        status = ssam_ctrl_notif_display_on(ctrl);
 674        if (status)
 675                goto err_initrq;
 676
 677        status = sysfs_create_group(&serdev->dev.kobj, &ssam_sam_group);
 678        if (status)
 679                goto err_initrq;
 680
 681        /* Set up IRQ. */
 682        status = ssam_irq_setup(ctrl);
 683        if (status)
 684                goto err_irq;
 685
 686        /* Finally, set main controller reference. */
 687        status = ssam_try_set_controller(ctrl);
 688        if (WARN_ON(status))    /* Currently, we're the only provider. */
 689                goto err_mainref;
 690
 691        /*
 692         * TODO: The EC can wake up the system via the associated GPIO interrupt
 693         *       in multiple situations. One of which is the remaining battery
 694         *       capacity falling below a certain threshold. Normally, we should
 695         *       use the device_init_wakeup function, however, the EC also seems
 696         *       to have other reasons for waking up the system and it seems
 697         *       that Windows has additional checks whether the system should be
 698         *       resumed. In short, this causes some spurious unwanted wake-ups.
 699         *       For now let's thus default power/wakeup to false.
 700         */
 701        device_set_wakeup_capable(&serdev->dev, true);
 702        acpi_dev_clear_dependencies(ssh);
 703
 704        return 0;
 705
 706err_mainref:
 707        ssam_irq_free(ctrl);
 708err_irq:
 709        sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
 710err_initrq:
 711        ssam_controller_lock(ctrl);
 712        ssam_controller_shutdown(ctrl);
 713err_devinit:
 714        serdev_device_close(serdev);
 715err_devopen:
 716        ssam_controller_destroy(ctrl);
 717        ssam_controller_unlock(ctrl);
 718err_ctrl_init:
 719        kfree(ctrl);
 720        return status;
 721}
 722
 723static void ssam_serial_hub_remove(struct serdev_device *serdev)
 724{
 725        struct ssam_controller *ctrl = serdev_device_get_drvdata(serdev);
 726        int status;
 727
 728        /* Clear static reference so that no one else can get a new one. */
 729        ssam_clear_controller();
 730
 731        /* Disable and free IRQ. */
 732        ssam_irq_free(ctrl);
 733
 734        sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
 735        ssam_controller_lock(ctrl);
 736
 737        /* Remove all client devices. */
 738        ssam_controller_remove_clients(ctrl);
 739
 740        /* Act as if suspending to silence events. */
 741        status = ssam_ctrl_notif_display_off(ctrl);
 742        if (status) {
 743                dev_err(&serdev->dev, "display-off notification failed: %d\n",
 744                        status);
 745        }
 746
 747        status = ssam_ctrl_notif_d0_exit(ctrl);
 748        if (status) {
 749                dev_err(&serdev->dev, "D0-exit notification failed: %d\n",
 750                        status);
 751        }
 752
 753        /* Shut down controller and remove serdev device reference from it. */
 754        ssam_controller_shutdown(ctrl);
 755
 756        /* Shut down actual transport. */
 757        serdev_device_wait_until_sent(serdev, 0);
 758        serdev_device_close(serdev);
 759
 760        /* Drop our controller reference. */
 761        ssam_controller_unlock(ctrl);
 762        ssam_controller_put(ctrl);
 763
 764        device_set_wakeup_capable(&serdev->dev, false);
 765}
 766
 767static const struct acpi_device_id ssam_serial_hub_match[] = {
 768        { "MSHW0084", 0 },
 769        { },
 770};
 771MODULE_DEVICE_TABLE(acpi, ssam_serial_hub_match);
 772
 773static struct serdev_device_driver ssam_serial_hub = {
 774        .probe = ssam_serial_hub_probe,
 775        .remove = ssam_serial_hub_remove,
 776        .driver = {
 777                .name = "surface_serial_hub",
 778                .acpi_match_table = ssam_serial_hub_match,
 779                .pm = &ssam_serial_hub_pm_ops,
 780                .shutdown = ssam_serial_hub_shutdown,
 781                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
 782        },
 783};
 784
 785
 786/* -- Module setup. --------------------------------------------------------- */
 787
 788static int __init ssam_core_init(void)
 789{
 790        int status;
 791
 792        status = ssam_bus_register();
 793        if (status)
 794                goto err_bus;
 795
 796        status = ssh_ctrl_packet_cache_init();
 797        if (status)
 798                goto err_cpkg;
 799
 800        status = ssam_event_item_cache_init();
 801        if (status)
 802                goto err_evitem;
 803
 804        status = serdev_device_driver_register(&ssam_serial_hub);
 805        if (status)
 806                goto err_register;
 807
 808        return 0;
 809
 810err_register:
 811        ssam_event_item_cache_destroy();
 812err_evitem:
 813        ssh_ctrl_packet_cache_destroy();
 814err_cpkg:
 815        ssam_bus_unregister();
 816err_bus:
 817        return status;
 818}
 819module_init(ssam_core_init);
 820
 821static void __exit ssam_core_exit(void)
 822{
 823        serdev_device_driver_unregister(&ssam_serial_hub);
 824        ssam_event_item_cache_destroy();
 825        ssh_ctrl_packet_cache_destroy();
 826        ssam_bus_unregister();
 827}
 828module_exit(ssam_core_exit);
 829
 830MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
 831MODULE_DESCRIPTION("Subsystem and Surface Serial Hub driver for Surface System Aggregator Module");
 832MODULE_LICENSE("GPL");
 833