1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Surface System Aggregator Module (SSAM) client device registry. 4 * 5 * Registry for non-platform/non-ACPI SSAM client devices, i.e. devices that 6 * cannot be auto-detected. Provides device-hubs and performs instantiation 7 * for these devices. 8 * 9 * Copyright (C) 2020-2022 Maximilian Luz <luzmaximilian@gmail.com> 10 */ 11 12 #include <linux/acpi.h> 13 #include <linux/kernel.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/platform_device.h> 17 #include <linux/property.h> 18 #include <linux/types.h> 19 20 #include <linux/surface_aggregator/device.h> 21 22 23 /* -- Device registry. ------------------------------------------------------ */ 24 25 /* 26 * SSAM device names follow the SSAM module alias, meaning they are prefixed 27 * with 'ssam:', followed by domain, category, target ID, instance ID, and 28 * function, each encoded as two-digit hexadecimal, separated by ':'. In other 29 * words, it follows the scheme 30 * 31 * ssam:dd:cc:tt:ii:ff 32 * 33 * Where, 'dd', 'cc', 'tt', 'ii', and 'ff' are the two-digit hexadecimal 34 * values mentioned above, respectively. 35 */ 36 37 /* Root node. */ 38 static const struct software_node ssam_node_root = { 39 .name = "ssam_platform_hub", 40 }; 41 42 /* KIP device hub (connects keyboard cover devices on Surface Pro 8). */ 43 static const struct software_node ssam_node_hub_kip = { 44 .name = "ssam:00:00:01:0e:00", 45 .parent = &ssam_node_root, 46 }; 47 48 /* Base device hub (devices attached to Surface Book 3 base). */ 49 static const struct software_node ssam_node_hub_base = { 50 .name = "ssam:00:00:01:11:00", 51 .parent = &ssam_node_root, 52 }; 53 54 /* AC adapter. */ 55 static const struct software_node ssam_node_bat_ac = { 56 .name = "ssam:01:02:01:01:01", 57 .parent = &ssam_node_root, 58 }; 59 60 /* Primary battery. */ 61 static const struct software_node ssam_node_bat_main = { 62 .name = "ssam:01:02:01:01:00", 63 .parent = &ssam_node_root, 64 }; 65 66 /* Secondary battery (Surface Book 3). */ 67 static const struct software_node ssam_node_bat_sb3base = { 68 .name = "ssam:01:02:02:01:00", 69 .parent = &ssam_node_hub_base, 70 }; 71 72 /* Platform profile / performance-mode device without a fan. */ 73 static const struct software_node ssam_node_tmp_perf_profile = { 74 .name = "ssam:01:03:01:00:01", 75 .parent = &ssam_node_root, 76 }; 77 78 /* Platform profile / performance-mode device with a fan, such that 79 * the fan controller profile can also be switched. 80 */ 81 static const struct property_entry ssam_node_tmp_perf_profile_has_fan[] = { 82 PROPERTY_ENTRY_BOOL("has_fan"), 83 { } 84 }; 85 86 static const struct software_node ssam_node_tmp_perf_profile_with_fan = { 87 .name = "ssam:01:03:01:00:01", 88 .parent = &ssam_node_root, 89 .properties = ssam_node_tmp_perf_profile_has_fan, 90 }; 91 92 /* Thermal sensors. */ 93 static const struct software_node ssam_node_tmp_sensors = { 94 .name = "ssam:01:03:01:00:02", 95 .parent = &ssam_node_root, 96 }; 97 98 /* Fan speed function. */ 99 static const struct software_node ssam_node_fan_speed = { 100 .name = "ssam:01:05:01:01:01", 101 .parent = &ssam_node_root, 102 }; 103 104 /* Tablet-mode switch via KIP subsystem. */ 105 static const struct software_node ssam_node_kip_tablet_switch = { 106 .name = "ssam:01:0e:01:00:01", 107 .parent = &ssam_node_root, 108 }; 109 110 /* DTX / detachment-system device (Surface Book 3). */ 111 static const struct software_node ssam_node_bas_dtx = { 112 .name = "ssam:01:11:01:00:00", 113 .parent = &ssam_node_root, 114 }; 115 116 /* HID keyboard (SAM, TID=1). */ 117 static const struct software_node ssam_node_hid_sam_keyboard = { 118 .name = "ssam:01:15:01:01:00", 119 .parent = &ssam_node_root, 120 }; 121 122 /* HID pen stash (SAM, TID=1; pen taken / stashed away evens). */ 123 static const struct software_node ssam_node_hid_sam_penstash = { 124 .name = "ssam:01:15:01:02:00", 125 .parent = &ssam_node_root, 126 }; 127 128 /* HID touchpad (SAM, TID=1). */ 129 static const struct software_node ssam_node_hid_sam_touchpad = { 130 .name = "ssam:01:15:01:03:00", 131 .parent = &ssam_node_root, 132 }; 133 134 /* HID device instance 6 (SAM, TID=1, HID sensor collection). */ 135 static const struct software_node ssam_node_hid_sam_sensors = { 136 .name = "ssam:01:15:01:06:00", 137 .parent = &ssam_node_root, 138 }; 139 140 /* HID device instance 7 (SAM, TID=1, UCM UCSI HID client). */ 141 static const struct software_node ssam_node_hid_sam_ucm_ucsi = { 142 .name = "ssam:01:15:01:07:00", 143 .parent = &ssam_node_root, 144 }; 145 146 /* HID system controls (SAM, TID=1). */ 147 static const struct software_node ssam_node_hid_sam_sysctrl = { 148 .name = "ssam:01:15:01:08:00", 149 .parent = &ssam_node_root, 150 }; 151 152 /* HID keyboard. */ 153 static const struct software_node ssam_node_hid_main_keyboard = { 154 .name = "ssam:01:15:02:01:00", 155 .parent = &ssam_node_root, 156 }; 157 158 /* HID touchpad. */ 159 static const struct software_node ssam_node_hid_main_touchpad = { 160 .name = "ssam:01:15:02:03:00", 161 .parent = &ssam_node_root, 162 }; 163 164 /* HID device instance 5 (unknown HID device). */ 165 static const struct software_node ssam_node_hid_main_iid5 = { 166 .name = "ssam:01:15:02:05:00", 167 .parent = &ssam_node_root, 168 }; 169 170 /* HID keyboard (base hub). */ 171 static const struct software_node ssam_node_hid_base_keyboard = { 172 .name = "ssam:01:15:02:01:00", 173 .parent = &ssam_node_hub_base, 174 }; 175 176 /* HID touchpad (base hub). */ 177 static const struct software_node ssam_node_hid_base_touchpad = { 178 .name = "ssam:01:15:02:03:00", 179 .parent = &ssam_node_hub_base, 180 }; 181 182 /* HID device instance 5 (unknown HID device, base hub). */ 183 static const struct software_node ssam_node_hid_base_iid5 = { 184 .name = "ssam:01:15:02:05:00", 185 .parent = &ssam_node_hub_base, 186 }; 187 188 /* HID device instance 6 (unknown HID device, base hub). */ 189 static const struct software_node ssam_node_hid_base_iid6 = { 190 .name = "ssam:01:15:02:06:00", 191 .parent = &ssam_node_hub_base, 192 }; 193 194 /* HID keyboard (KIP hub). */ 195 static const struct software_node ssam_node_hid_kip_keyboard = { 196 .name = "ssam:01:15:02:01:00", 197 .parent = &ssam_node_hub_kip, 198 }; 199 200 /* HID pen stash (KIP hub; pen taken / stashed away evens). */ 201 static const struct software_node ssam_node_hid_kip_penstash = { 202 .name = "ssam:01:15:02:02:00", 203 .parent = &ssam_node_hub_kip, 204 }; 205 206 /* HID touchpad (KIP hub). */ 207 static const struct software_node ssam_node_hid_kip_touchpad = { 208 .name = "ssam:01:15:02:03:00", 209 .parent = &ssam_node_hub_kip, 210 }; 211 212 /* HID device instance 5 (KIP hub, type-cover firmware update). */ 213 static const struct software_node ssam_node_hid_kip_fwupd = { 214 .name = "ssam:01:15:02:05:00", 215 .parent = &ssam_node_hub_kip, 216 }; 217 218 /* Tablet-mode switch via POS subsystem. */ 219 static const struct software_node ssam_node_pos_tablet_switch = { 220 .name = "ssam:01:26:01:00:01", 221 .parent = &ssam_node_root, 222 }; 223 224 /* 225 * Devices for 5th- and 6th-generations models: 226 * - Surface Book 2, 227 * - Surface Laptop 1 and 2, 228 * - Surface Pro 5 and 6. 229 */ 230 static const struct software_node *ssam_node_group_gen5[] = { 231 &ssam_node_root, 232 &ssam_node_tmp_perf_profile, 233 NULL, 234 }; 235 236 /* Devices for Surface Book 3. */ 237 static const struct software_node *ssam_node_group_sb3[] = { 238 &ssam_node_root, 239 &ssam_node_hub_base, 240 &ssam_node_bat_ac, 241 &ssam_node_bat_main, 242 &ssam_node_bat_sb3base, 243 &ssam_node_tmp_perf_profile, 244 &ssam_node_bas_dtx, 245 &ssam_node_hid_base_keyboard, 246 &ssam_node_hid_base_touchpad, 247 &ssam_node_hid_base_iid5, 248 &ssam_node_hid_base_iid6, 249 NULL, 250 }; 251 252 /* Devices for Surface Laptop 3 and 4. */ 253 static const struct software_node *ssam_node_group_sl3[] = { 254 &ssam_node_root, 255 &ssam_node_bat_ac, 256 &ssam_node_bat_main, 257 &ssam_node_tmp_perf_profile, 258 &ssam_node_hid_main_keyboard, 259 &ssam_node_hid_main_touchpad, 260 &ssam_node_hid_main_iid5, 261 NULL, 262 }; 263 264 /* Devices for Surface Laptop 5. */ 265 static const struct software_node *ssam_node_group_sl5[] = { 266 &ssam_node_root, 267 &ssam_node_bat_ac, 268 &ssam_node_bat_main, 269 &ssam_node_tmp_perf_profile_with_fan, 270 &ssam_node_tmp_sensors, 271 &ssam_node_fan_speed, 272 &ssam_node_hid_main_keyboard, 273 &ssam_node_hid_main_touchpad, 274 &ssam_node_hid_main_iid5, 275 &ssam_node_hid_sam_ucm_ucsi, 276 NULL, 277 }; 278 279 /* Devices for Surface Laptop 6. */ 280 static const struct software_node *ssam_node_group_sl6[] = { 281 &ssam_node_root, 282 &ssam_node_bat_ac, 283 &ssam_node_bat_main, 284 &ssam_node_tmp_perf_profile_with_fan, 285 &ssam_node_tmp_sensors, 286 &ssam_node_fan_speed, 287 &ssam_node_hid_main_keyboard, 288 &ssam_node_hid_main_touchpad, 289 &ssam_node_hid_main_iid5, 290 &ssam_node_hid_sam_sensors, 291 &ssam_node_hid_sam_ucm_ucsi, 292 NULL, 293 }; 294 295 /* Devices for Surface Laptop 7. */ 296 static const struct software_node *ssam_node_group_sl7[] = { 297 &ssam_node_root, 298 &ssam_node_tmp_perf_profile_with_fan, 299 &ssam_node_fan_speed, 300 &ssam_node_hid_sam_keyboard, 301 /* TODO: evaluate thermal sensors devices when we get a driver for that */ 302 NULL, 303 }; 304 305 /* Devices for Surface Laptop Studio 1. */ 306 static const struct software_node *ssam_node_group_sls1[] = { 307 &ssam_node_root, 308 &ssam_node_bat_ac, 309 &ssam_node_bat_main, 310 &ssam_node_tmp_perf_profile, 311 &ssam_node_pos_tablet_switch, 312 &ssam_node_hid_sam_keyboard, 313 &ssam_node_hid_sam_penstash, 314 &ssam_node_hid_sam_touchpad, 315 &ssam_node_hid_sam_sensors, 316 &ssam_node_hid_sam_ucm_ucsi, 317 &ssam_node_hid_sam_sysctrl, 318 NULL, 319 }; 320 321 /* Devices for Surface Laptop Studio 2. */ 322 static const struct software_node *ssam_node_group_sls2[] = { 323 &ssam_node_root, 324 &ssam_node_bat_ac, 325 &ssam_node_bat_main, 326 &ssam_node_tmp_perf_profile_with_fan, 327 &ssam_node_tmp_sensors, 328 &ssam_node_fan_speed, 329 &ssam_node_pos_tablet_switch, 330 &ssam_node_hid_sam_keyboard, 331 &ssam_node_hid_sam_penstash, 332 &ssam_node_hid_sam_sensors, 333 &ssam_node_hid_sam_ucm_ucsi, 334 NULL, 335 }; 336 337 /* Devices for Surface Laptop Go. */ 338 static const struct software_node *ssam_node_group_slg1[] = { 339 &ssam_node_root, 340 &ssam_node_bat_ac, 341 &ssam_node_bat_main, 342 &ssam_node_tmp_perf_profile, 343 NULL, 344 }; 345 346 /* Devices for Surface Pro 7 and Surface Pro 7+. */ 347 static const struct software_node *ssam_node_group_sp7[] = { 348 &ssam_node_root, 349 &ssam_node_bat_ac, 350 &ssam_node_bat_main, 351 &ssam_node_tmp_perf_profile, 352 NULL, 353 }; 354 355 /* Devices for Surface Pro 8 */ 356 static const struct software_node *ssam_node_group_sp8[] = { 357 &ssam_node_root, 358 &ssam_node_hub_kip, 359 &ssam_node_bat_ac, 360 &ssam_node_bat_main, 361 &ssam_node_tmp_perf_profile, 362 &ssam_node_kip_tablet_switch, 363 &ssam_node_hid_kip_keyboard, 364 &ssam_node_hid_kip_penstash, 365 &ssam_node_hid_kip_touchpad, 366 &ssam_node_hid_kip_fwupd, 367 &ssam_node_hid_sam_sensors, 368 &ssam_node_hid_sam_ucm_ucsi, 369 NULL, 370 }; 371 372 /* Devices for Surface Pro 9, 10 and 11 (Intel/x86) */ 373 static const struct software_node *ssam_node_group_sp9[] = { 374 &ssam_node_root, 375 &ssam_node_hub_kip, 376 &ssam_node_bat_ac, 377 &ssam_node_bat_main, 378 &ssam_node_tmp_perf_profile_with_fan, 379 &ssam_node_tmp_sensors, 380 &ssam_node_fan_speed, 381 &ssam_node_pos_tablet_switch, 382 &ssam_node_hid_kip_keyboard, 383 &ssam_node_hid_kip_penstash, 384 &ssam_node_hid_kip_touchpad, 385 &ssam_node_hid_kip_fwupd, 386 &ssam_node_hid_sam_sensors, 387 &ssam_node_hid_sam_ucm_ucsi, 388 NULL, 389 }; 390 391 /* Devices for Surface Pro 9 5G (ARM/QCOM) */ 392 static const struct software_node *ssam_node_group_sp9_5g[] = { 393 &ssam_node_root, 394 &ssam_node_hub_kip, 395 &ssam_node_bat_ac, 396 &ssam_node_bat_main, 397 &ssam_node_tmp_sensors, 398 &ssam_node_hid_kip_keyboard, 399 &ssam_node_hid_kip_penstash, 400 &ssam_node_hid_kip_touchpad, 401 &ssam_node_hid_kip_fwupd, 402 &ssam_node_hid_sam_sensors, 403 &ssam_node_kip_tablet_switch, 404 NULL, 405 }; 406 407 /* Devices for Surface Pro 11 (ARM/QCOM) */ 408 static const struct software_node *ssam_node_group_sp11[] = { 409 &ssam_node_root, 410 &ssam_node_hub_kip, 411 &ssam_node_bat_ac, 412 &ssam_node_bat_main, 413 &ssam_node_tmp_sensors, 414 &ssam_node_hid_kip_keyboard, 415 &ssam_node_hid_kip_penstash, 416 &ssam_node_hid_kip_touchpad, 417 &ssam_node_hid_kip_fwupd, 418 &ssam_node_hid_sam_sensors, 419 &ssam_node_kip_tablet_switch, 420 NULL, 421 }; 422 423 /* -- SSAM platform/meta-hub driver. ---------------------------------------- */ 424 425 static const struct acpi_device_id ssam_platform_hub_acpi_match[] = { 426 /* Surface Pro 4, 5, and 6 (OMBR < 0x10) */ 427 { "MSHW0081", (unsigned long)ssam_node_group_gen5 }, 428 429 /* Surface Pro 6 (OMBR >= 0x10) */ 430 { "MSHW0111", (unsigned long)ssam_node_group_gen5 }, 431 432 /* Surface Pro 7 */ 433 { "MSHW0116", (unsigned long)ssam_node_group_sp7 }, 434 435 /* Surface Pro 7+ */ 436 { "MSHW0119", (unsigned long)ssam_node_group_sp7 }, 437 438 /* Surface Pro 8 */ 439 { "MSHW0263", (unsigned long)ssam_node_group_sp8 }, 440 441 /* Surface Pro 9 */ 442 { "MSHW0343", (unsigned long)ssam_node_group_sp9 }, 443 444 /* Surface Pro 10 */ 445 { "MSHW0510", (unsigned long)ssam_node_group_sp9 }, 446 447 /* Surface Pro 11 */ 448 { "MSHW0583", (unsigned long)ssam_node_group_sp9 }, 449 450 /* Surface Book 2 */ 451 { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, 452 453 /* Surface Book 3 */ 454 { "MSHW0117", (unsigned long)ssam_node_group_sb3 }, 455 456 /* Surface Laptop 1 */ 457 { "MSHW0086", (unsigned long)ssam_node_group_gen5 }, 458 459 /* Surface Laptop 2 */ 460 { "MSHW0112", (unsigned long)ssam_node_group_gen5 }, 461 462 /* Surface Laptop 3 (13", Intel) */ 463 { "MSHW0114", (unsigned long)ssam_node_group_sl3 }, 464 465 /* Surface Laptop 3 (15", AMD) and 4 (15", AMD) */ 466 { "MSHW0110", (unsigned long)ssam_node_group_sl3 }, 467 468 /* Surface Laptop 4 (13", Intel) */ 469 { "MSHW0250", (unsigned long)ssam_node_group_sl3 }, 470 471 /* Surface Laptop 5 */ 472 { "MSHW0350", (unsigned long)ssam_node_group_sl5 }, 473 474 /* Surface Laptop 6 */ 475 { "MSHW0530", (unsigned long)ssam_node_group_sl6 }, 476 477 /* Surface Laptop Go 1 */ 478 { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, 479 480 /* Surface Laptop Go 2 */ 481 { "MSHW0290", (unsigned long)ssam_node_group_slg1 }, 482 483 /* Surface Laptop Go 3 */ 484 { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, 485 486 /* Surface Laptop Studio 1 */ 487 { "MSHW0123", (unsigned long)ssam_node_group_sls1 }, 488 489 /* Surface Laptop Studio 2 */ 490 { "MSHW0360", (unsigned long)ssam_node_group_sls2 }, 491 492 { }, 493 }; 494 MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_acpi_match); 495 496 static const struct of_device_id ssam_platform_hub_of_match[] __maybe_unused = { 497 /* Surface Pro 9 5G (ARM/QCOM) */ 498 { .compatible = "microsoft,arcata", (void *)ssam_node_group_sp9_5g }, 499 /* Surface Pro 11 (ARM/QCOM) */ 500 { .compatible = "microsoft,denali", (void *)ssam_node_group_sp11 }, 501 /* Surface Laptop 7 */ 502 { .compatible = "microsoft,romulus13", (void *)ssam_node_group_sl7 }, 503 { .compatible = "microsoft,romulus15", (void *)ssam_node_group_sl7 }, 504 { }, 505 }; 506 507 static int ssam_platform_hub_probe(struct platform_device *pdev) 508 { 509 const struct software_node **nodes; 510 struct ssam_controller *ctrl; 511 struct fwnode_handle *root; 512 int status; 513 514 nodes = (const struct software_node **)acpi_device_get_match_data(&pdev->dev); 515 if (!nodes) { 516 nodes = (const struct software_node **)of_machine_get_match_data(ssam_platform_hub_of_match); 517 if (!nodes) 518 return -ENODEV; 519 } 520 521 /* 522 * As we're adding the SSAM client devices as children under this device 523 * and not the SSAM controller, we need to add a device link to the 524 * controller to ensure that we remove all of our devices before the 525 * controller is removed. This also guarantees proper ordering for 526 * suspend/resume of the devices on this hub. 527 */ 528 ctrl = ssam_client_bind(&pdev->dev); 529 if (IS_ERR(ctrl)) 530 return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); 531 532 status = software_node_register_node_group(nodes); 533 if (status) 534 return status; 535 536 root = software_node_fwnode(&ssam_node_root); 537 if (!root) { 538 software_node_unregister_node_group(nodes); 539 return -ENOENT; 540 } 541 542 set_secondary_fwnode(&pdev->dev, root); 543 544 status = __ssam_register_clients(&pdev->dev, ctrl, root); 545 if (status) { 546 set_secondary_fwnode(&pdev->dev, NULL); 547 software_node_unregister_node_group(nodes); 548 } 549 550 platform_set_drvdata(pdev, nodes); 551 return status; 552 } 553 554 static void ssam_platform_hub_remove(struct platform_device *pdev) 555 { 556 const struct software_node **nodes = platform_get_drvdata(pdev); 557 558 ssam_remove_clients(&pdev->dev); 559 set_secondary_fwnode(&pdev->dev, NULL); 560 software_node_unregister_node_group(nodes); 561 } 562 563 static struct platform_driver ssam_platform_hub_driver = { 564 .probe = ssam_platform_hub_probe, 565 .remove = ssam_platform_hub_remove, 566 .driver = { 567 .name = "surface_aggregator_platform_hub", 568 .acpi_match_table = ssam_platform_hub_acpi_match, 569 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 570 }, 571 }; 572 module_platform_driver(ssam_platform_hub_driver); 573 574 MODULE_ALIAS("platform:surface_aggregator_platform_hub"); 575 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); 576 MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module"); 577 MODULE_LICENSE("GPL"); 578