0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/acpi.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/property.h>
0017 #include <linux/types.h>
0018
0019 #include <linux/surface_aggregator/device.h>
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 static const struct software_node ssam_node_root = {
0038 .name = "ssam_platform_hub",
0039 };
0040
0041
0042 static const struct software_node ssam_node_hub_kip = {
0043 .name = "ssam:00:00:01:0e:00",
0044 .parent = &ssam_node_root,
0045 };
0046
0047
0048 static const struct software_node ssam_node_hub_base = {
0049 .name = "ssam:00:00:02:11:00",
0050 .parent = &ssam_node_root,
0051 };
0052
0053
0054 static const struct software_node ssam_node_bat_ac = {
0055 .name = "ssam:01:02:01:01:01",
0056 .parent = &ssam_node_root,
0057 };
0058
0059
0060 static const struct software_node ssam_node_bat_main = {
0061 .name = "ssam:01:02:01:01:00",
0062 .parent = &ssam_node_root,
0063 };
0064
0065
0066 static const struct software_node ssam_node_bat_sb3base = {
0067 .name = "ssam:01:02:02:01:00",
0068 .parent = &ssam_node_hub_base,
0069 };
0070
0071
0072 static const struct software_node ssam_node_tmp_pprof = {
0073 .name = "ssam:01:03:01:00:01",
0074 .parent = &ssam_node_root,
0075 };
0076
0077
0078 static const struct software_node ssam_node_kip_tablet_switch = {
0079 .name = "ssam:01:0e:01:00:01",
0080 .parent = &ssam_node_root,
0081 };
0082
0083
0084 static const struct software_node ssam_node_bas_dtx = {
0085 .name = "ssam:01:11:01:00:00",
0086 .parent = &ssam_node_root,
0087 };
0088
0089
0090 static const struct software_node ssam_node_hid_sam_keyboard = {
0091 .name = "ssam:01:15:01:01:00",
0092 .parent = &ssam_node_root,
0093 };
0094
0095
0096 static const struct software_node ssam_node_hid_sam_penstash = {
0097 .name = "ssam:01:15:01:02:00",
0098 .parent = &ssam_node_root,
0099 };
0100
0101
0102 static const struct software_node ssam_node_hid_sam_touchpad = {
0103 .name = "ssam:01:15:01:03:00",
0104 .parent = &ssam_node_root,
0105 };
0106
0107
0108 static const struct software_node ssam_node_hid_sam_sensors = {
0109 .name = "ssam:01:15:01:06:00",
0110 .parent = &ssam_node_root,
0111 };
0112
0113
0114 static const struct software_node ssam_node_hid_sam_ucm_ucsi = {
0115 .name = "ssam:01:15:01:07:00",
0116 .parent = &ssam_node_root,
0117 };
0118
0119
0120 static const struct software_node ssam_node_hid_sam_sysctrl = {
0121 .name = "ssam:01:15:01:08:00",
0122 .parent = &ssam_node_root,
0123 };
0124
0125
0126 static const struct software_node ssam_node_hid_main_keyboard = {
0127 .name = "ssam:01:15:02:01:00",
0128 .parent = &ssam_node_root,
0129 };
0130
0131
0132 static const struct software_node ssam_node_hid_main_touchpad = {
0133 .name = "ssam:01:15:02:03:00",
0134 .parent = &ssam_node_root,
0135 };
0136
0137
0138 static const struct software_node ssam_node_hid_main_iid5 = {
0139 .name = "ssam:01:15:02:05:00",
0140 .parent = &ssam_node_root,
0141 };
0142
0143
0144 static const struct software_node ssam_node_hid_base_keyboard = {
0145 .name = "ssam:01:15:02:01:00",
0146 .parent = &ssam_node_hub_base,
0147 };
0148
0149
0150 static const struct software_node ssam_node_hid_base_touchpad = {
0151 .name = "ssam:01:15:02:03:00",
0152 .parent = &ssam_node_hub_base,
0153 };
0154
0155
0156 static const struct software_node ssam_node_hid_base_iid5 = {
0157 .name = "ssam:01:15:02:05:00",
0158 .parent = &ssam_node_hub_base,
0159 };
0160
0161
0162 static const struct software_node ssam_node_hid_base_iid6 = {
0163 .name = "ssam:01:15:02:06:00",
0164 .parent = &ssam_node_hub_base,
0165 };
0166
0167
0168 static const struct software_node ssam_node_hid_kip_keyboard = {
0169 .name = "ssam:01:15:02:01:00",
0170 .parent = &ssam_node_hub_kip,
0171 };
0172
0173
0174 static const struct software_node ssam_node_hid_kip_penstash = {
0175 .name = "ssam:01:15:02:02:00",
0176 .parent = &ssam_node_hub_kip,
0177 };
0178
0179
0180 static const struct software_node ssam_node_hid_kip_touchpad = {
0181 .name = "ssam:01:15:02:03:00",
0182 .parent = &ssam_node_hub_kip,
0183 };
0184
0185
0186 static const struct software_node ssam_node_hid_kip_fwupd = {
0187 .name = "ssam:01:15:02:05:00",
0188 .parent = &ssam_node_hub_kip,
0189 };
0190
0191
0192 static const struct software_node ssam_node_pos_tablet_switch = {
0193 .name = "ssam:01:26:01:00:01",
0194 .parent = &ssam_node_root,
0195 };
0196
0197
0198
0199
0200
0201
0202
0203 static const struct software_node *ssam_node_group_gen5[] = {
0204 &ssam_node_root,
0205 &ssam_node_tmp_pprof,
0206 NULL,
0207 };
0208
0209
0210 static const struct software_node *ssam_node_group_sb3[] = {
0211 &ssam_node_root,
0212 &ssam_node_hub_base,
0213 &ssam_node_bat_ac,
0214 &ssam_node_bat_main,
0215 &ssam_node_bat_sb3base,
0216 &ssam_node_tmp_pprof,
0217 &ssam_node_bas_dtx,
0218 &ssam_node_hid_base_keyboard,
0219 &ssam_node_hid_base_touchpad,
0220 &ssam_node_hid_base_iid5,
0221 &ssam_node_hid_base_iid6,
0222 NULL,
0223 };
0224
0225
0226 static const struct software_node *ssam_node_group_sl3[] = {
0227 &ssam_node_root,
0228 &ssam_node_bat_ac,
0229 &ssam_node_bat_main,
0230 &ssam_node_tmp_pprof,
0231 &ssam_node_hid_main_keyboard,
0232 &ssam_node_hid_main_touchpad,
0233 &ssam_node_hid_main_iid5,
0234 NULL,
0235 };
0236
0237
0238 static const struct software_node *ssam_node_group_sls[] = {
0239 &ssam_node_root,
0240 &ssam_node_bat_ac,
0241 &ssam_node_bat_main,
0242 &ssam_node_tmp_pprof,
0243 &ssam_node_pos_tablet_switch,
0244 &ssam_node_hid_sam_keyboard,
0245 &ssam_node_hid_sam_penstash,
0246 &ssam_node_hid_sam_touchpad,
0247 &ssam_node_hid_sam_sensors,
0248 &ssam_node_hid_sam_ucm_ucsi,
0249 &ssam_node_hid_sam_sysctrl,
0250 NULL,
0251 };
0252
0253
0254 static const struct software_node *ssam_node_group_slg1[] = {
0255 &ssam_node_root,
0256 &ssam_node_bat_ac,
0257 &ssam_node_bat_main,
0258 &ssam_node_tmp_pprof,
0259 NULL,
0260 };
0261
0262
0263 static const struct software_node *ssam_node_group_sp7[] = {
0264 &ssam_node_root,
0265 &ssam_node_bat_ac,
0266 &ssam_node_bat_main,
0267 &ssam_node_tmp_pprof,
0268 NULL,
0269 };
0270
0271 static const struct software_node *ssam_node_group_sp8[] = {
0272 &ssam_node_root,
0273 &ssam_node_hub_kip,
0274 &ssam_node_bat_ac,
0275 &ssam_node_bat_main,
0276 &ssam_node_tmp_pprof,
0277 &ssam_node_kip_tablet_switch,
0278 &ssam_node_hid_kip_keyboard,
0279 &ssam_node_hid_kip_penstash,
0280 &ssam_node_hid_kip_touchpad,
0281 &ssam_node_hid_kip_fwupd,
0282 &ssam_node_hid_sam_sensors,
0283 &ssam_node_hid_sam_ucm_ucsi,
0284 NULL,
0285 };
0286
0287
0288
0289
0290 static const struct acpi_device_id ssam_platform_hub_match[] = {
0291
0292 { "MSHW0081", (unsigned long)ssam_node_group_gen5 },
0293
0294
0295 { "MSHW0111", (unsigned long)ssam_node_group_gen5 },
0296
0297
0298 { "MSHW0116", (unsigned long)ssam_node_group_sp7 },
0299
0300
0301 { "MSHW0119", (unsigned long)ssam_node_group_sp7 },
0302
0303
0304 { "MSHW0263", (unsigned long)ssam_node_group_sp8 },
0305
0306
0307 { "MSHW0107", (unsigned long)ssam_node_group_gen5 },
0308
0309
0310 { "MSHW0117", (unsigned long)ssam_node_group_sb3 },
0311
0312
0313 { "MSHW0086", (unsigned long)ssam_node_group_gen5 },
0314
0315
0316 { "MSHW0112", (unsigned long)ssam_node_group_gen5 },
0317
0318
0319 { "MSHW0114", (unsigned long)ssam_node_group_sl3 },
0320
0321
0322 { "MSHW0110", (unsigned long)ssam_node_group_sl3 },
0323
0324
0325 { "MSHW0250", (unsigned long)ssam_node_group_sl3 },
0326
0327
0328 { "MSHW0118", (unsigned long)ssam_node_group_slg1 },
0329
0330
0331 { "MSHW0290", (unsigned long)ssam_node_group_slg1 },
0332
0333
0334 { "MSHW0123", (unsigned long)ssam_node_group_sls },
0335
0336 { },
0337 };
0338 MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_match);
0339
0340 static int ssam_platform_hub_probe(struct platform_device *pdev)
0341 {
0342 const struct software_node **nodes;
0343 struct ssam_controller *ctrl;
0344 struct fwnode_handle *root;
0345 int status;
0346
0347 nodes = (const struct software_node **)acpi_device_get_match_data(&pdev->dev);
0348 if (!nodes)
0349 return -ENODEV;
0350
0351
0352
0353
0354
0355
0356
0357
0358 ctrl = ssam_client_bind(&pdev->dev);
0359 if (IS_ERR(ctrl))
0360 return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
0361
0362 status = software_node_register_node_group(nodes);
0363 if (status)
0364 return status;
0365
0366 root = software_node_fwnode(&ssam_node_root);
0367 if (!root) {
0368 software_node_unregister_node_group(nodes);
0369 return -ENOENT;
0370 }
0371
0372 set_secondary_fwnode(&pdev->dev, root);
0373
0374 status = __ssam_register_clients(&pdev->dev, ctrl, root);
0375 if (status) {
0376 set_secondary_fwnode(&pdev->dev, NULL);
0377 software_node_unregister_node_group(nodes);
0378 }
0379
0380 platform_set_drvdata(pdev, nodes);
0381 return status;
0382 }
0383
0384 static int ssam_platform_hub_remove(struct platform_device *pdev)
0385 {
0386 const struct software_node **nodes = platform_get_drvdata(pdev);
0387
0388 ssam_remove_clients(&pdev->dev);
0389 set_secondary_fwnode(&pdev->dev, NULL);
0390 software_node_unregister_node_group(nodes);
0391 return 0;
0392 }
0393
0394 static struct platform_driver ssam_platform_hub_driver = {
0395 .probe = ssam_platform_hub_probe,
0396 .remove = ssam_platform_hub_remove,
0397 .driver = {
0398 .name = "surface_aggregator_platform_hub",
0399 .acpi_match_table = ssam_platform_hub_match,
0400 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0401 },
0402 };
0403 module_platform_driver(ssam_platform_hub_driver);
0404
0405 MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
0406 MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module");
0407 MODULE_LICENSE("GPL");