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