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#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");
 834