0001
0002
0003
0004
0005
0006
0007 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0008
0009 #include <linux/acpi.h>
0010 #include <linux/dmi.h>
0011 #include <linux/i2c.h>
0012 #include <linux/input.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/ioport.h>
0015 #include <linux/module.h>
0016 #include <linux/pci.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/property.h>
0019
0020 #define ATMEL_TP_I2C_ADDR 0x4b
0021 #define ATMEL_TP_I2C_BL_ADDR 0x25
0022 #define ATMEL_TS_I2C_ADDR 0x4a
0023 #define ATMEL_TS_I2C_BL_ADDR 0x26
0024 #define CYAPA_TP_I2C_ADDR 0x67
0025 #define ELAN_TP_I2C_ADDR 0x15
0026 #define ISL_ALS_I2C_ADDR 0x44
0027 #define TAOS_ALS_I2C_ADDR 0x29
0028
0029 static const char *i2c_adapter_names[] = {
0030 "SMBus I801 adapter",
0031 "i915 gmbus vga",
0032 "i915 gmbus panel",
0033 "Synopsys DesignWare I2C adapter",
0034 };
0035
0036
0037 enum i2c_adapter_type {
0038 I2C_ADAPTER_SMBUS = 0,
0039 I2C_ADAPTER_VGADDC,
0040 I2C_ADAPTER_PANEL,
0041 I2C_ADAPTER_DESIGNWARE,
0042 };
0043
0044 struct i2c_peripheral {
0045 struct i2c_board_info board_info;
0046 unsigned short alt_addr;
0047
0048 const char *dmi_name;
0049 unsigned long irqflags;
0050 struct resource irq_resource;
0051
0052 enum i2c_adapter_type type;
0053 u32 pci_devid;
0054
0055 const struct property_entry *properties;
0056
0057 struct i2c_client *client;
0058 };
0059
0060 struct acpi_peripheral {
0061 char hid[ACPI_ID_LEN];
0062 struct software_node swnode;
0063 struct i2c_client *client;
0064 };
0065
0066 struct chromeos_laptop {
0067
0068
0069
0070
0071 struct i2c_peripheral *i2c_peripherals;
0072 unsigned int num_i2c_peripherals;
0073
0074 struct acpi_peripheral *acpi_peripherals;
0075 unsigned int num_acpi_peripherals;
0076 };
0077
0078 static const struct chromeos_laptop *cros_laptop;
0079
0080 static struct i2c_client *
0081 chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter,
0082 struct i2c_board_info *info,
0083 unsigned short alt_addr)
0084 {
0085 const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
0086 struct i2c_client *client;
0087
0088
0089
0090
0091
0092
0093 client = i2c_new_scanned_device(adapter, info, addr_list, NULL);
0094 if (IS_ERR(client) && alt_addr) {
0095 struct i2c_board_info dummy_info = {
0096 I2C_BOARD_INFO("dummy", info->addr),
0097 };
0098 const unsigned short alt_addr_list[] = {
0099 alt_addr, I2C_CLIENT_END
0100 };
0101 struct i2c_client *dummy;
0102
0103 dummy = i2c_new_scanned_device(adapter, &dummy_info,
0104 alt_addr_list, NULL);
0105 if (!IS_ERR(dummy)) {
0106 pr_debug("%d-%02x is probed at %02x\n",
0107 adapter->nr, info->addr, dummy->addr);
0108 i2c_unregister_device(dummy);
0109 client = i2c_new_client_device(adapter, info);
0110 }
0111 }
0112
0113 if (IS_ERR(client)) {
0114 client = NULL;
0115 pr_debug("failed to register device %d-%02x\n",
0116 adapter->nr, info->addr);
0117 } else {
0118 pr_debug("added i2c device %d-%02x\n",
0119 adapter->nr, info->addr);
0120 }
0121
0122 return client;
0123 }
0124
0125 static bool chromeos_laptop_match_adapter_devid(struct device *dev, u32 devid)
0126 {
0127 struct pci_dev *pdev;
0128
0129 if (!dev_is_pci(dev))
0130 return false;
0131
0132 pdev = to_pci_dev(dev);
0133 return devid == pci_dev_id(pdev);
0134 }
0135
0136 static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
0137 {
0138 struct i2c_peripheral *i2c_dev;
0139 int i;
0140
0141 for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
0142 i2c_dev = &cros_laptop->i2c_peripherals[i];
0143
0144
0145 if (i2c_dev->client)
0146 continue;
0147
0148 if (strncmp(adapter->name, i2c_adapter_names[i2c_dev->type],
0149 strlen(i2c_adapter_names[i2c_dev->type])))
0150 continue;
0151
0152 if (i2c_dev->pci_devid &&
0153 !chromeos_laptop_match_adapter_devid(adapter->dev.parent,
0154 i2c_dev->pci_devid)) {
0155 continue;
0156 }
0157
0158 i2c_dev->client =
0159 chromes_laptop_instantiate_i2c_device(adapter,
0160 &i2c_dev->board_info,
0161 i2c_dev->alt_addr);
0162 }
0163 }
0164
0165 static bool chromeos_laptop_adjust_client(struct i2c_client *client)
0166 {
0167 struct acpi_peripheral *acpi_dev;
0168 struct acpi_device_id acpi_ids[2] = { };
0169 int i;
0170 int error;
0171
0172 if (!has_acpi_companion(&client->dev))
0173 return false;
0174
0175 for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
0176 acpi_dev = &cros_laptop->acpi_peripherals[i];
0177
0178 memcpy(acpi_ids[0].id, acpi_dev->hid, ACPI_ID_LEN);
0179
0180 if (acpi_match_device(acpi_ids, &client->dev)) {
0181 error = device_add_software_node(&client->dev, &acpi_dev->swnode);
0182 if (error) {
0183 dev_err(&client->dev,
0184 "failed to add properties: %d\n",
0185 error);
0186 break;
0187 }
0188
0189 acpi_dev->client = client;
0190
0191 return true;
0192 }
0193 }
0194
0195 return false;
0196 }
0197
0198 static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
0199 {
0200 struct acpi_peripheral *acpi_dev;
0201 struct i2c_peripheral *i2c_dev;
0202 int i;
0203
0204 if (has_acpi_companion(&client->dev))
0205 for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
0206 acpi_dev = &cros_laptop->acpi_peripherals[i];
0207
0208 if (acpi_dev->client == client) {
0209 acpi_dev->client = NULL;
0210 return;
0211 }
0212 }
0213 else
0214 for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
0215 i2c_dev = &cros_laptop->i2c_peripherals[i];
0216
0217 if (i2c_dev->client == client) {
0218 i2c_dev->client = NULL;
0219 return;
0220 }
0221 }
0222 }
0223
0224 static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb,
0225 unsigned long action, void *data)
0226 {
0227 struct device *dev = data;
0228
0229 switch (action) {
0230 case BUS_NOTIFY_ADD_DEVICE:
0231 if (dev->type == &i2c_adapter_type)
0232 chromeos_laptop_check_adapter(to_i2c_adapter(dev));
0233 else if (dev->type == &i2c_client_type)
0234 chromeos_laptop_adjust_client(to_i2c_client(dev));
0235 break;
0236
0237 case BUS_NOTIFY_REMOVED_DEVICE:
0238 if (dev->type == &i2c_client_type)
0239 chromeos_laptop_detach_i2c_client(to_i2c_client(dev));
0240 break;
0241 }
0242
0243 return 0;
0244 }
0245
0246 static struct notifier_block chromeos_laptop_i2c_notifier = {
0247 .notifier_call = chromeos_laptop_i2c_notifier_call,
0248 };
0249
0250 #define DECLARE_CROS_LAPTOP(_name) \
0251 static const struct chromeos_laptop _name __initconst = { \
0252 .i2c_peripherals = _name##_peripherals, \
0253 .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \
0254 }
0255
0256 #define DECLARE_ACPI_CROS_LAPTOP(_name) \
0257 static const struct chromeos_laptop _name __initconst = { \
0258 .acpi_peripherals = _name##_peripherals, \
0259 .num_acpi_peripherals = ARRAY_SIZE(_name##_peripherals), \
0260 }
0261
0262 static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = {
0263
0264 {
0265 .board_info = {
0266 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
0267 .flags = I2C_CLIENT_WAKE,
0268 },
0269 .dmi_name = "trackpad",
0270 .type = I2C_ADAPTER_SMBUS,
0271 },
0272
0273 {
0274 .board_info = {
0275 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
0276 },
0277 .dmi_name = "lightsensor",
0278 .type = I2C_ADAPTER_SMBUS,
0279 },
0280 };
0281 DECLARE_CROS_LAPTOP(samsung_series_5_550);
0282
0283 static struct i2c_peripheral samsung_series_5_peripherals[] __initdata = {
0284
0285 {
0286 .board_info = {
0287 I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
0288 },
0289 .type = I2C_ADAPTER_SMBUS,
0290 },
0291 };
0292 DECLARE_CROS_LAPTOP(samsung_series_5);
0293
0294 static const int chromebook_pixel_tp_keys[] __initconst = {
0295 KEY_RESERVED,
0296 KEY_RESERVED,
0297 KEY_RESERVED,
0298 KEY_RESERVED,
0299 KEY_RESERVED,
0300 BTN_LEFT
0301 };
0302
0303 static const struct property_entry
0304 chromebook_pixel_trackpad_props[] __initconst = {
0305 PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
0306 PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys),
0307 { }
0308 };
0309
0310 static const struct property_entry
0311 chromebook_atmel_touchscreen_props[] __initconst = {
0312 PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
0313 { }
0314 };
0315
0316 static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = {
0317
0318 {
0319 .board_info = {
0320 I2C_BOARD_INFO("atmel_mxt_ts",
0321 ATMEL_TS_I2C_ADDR),
0322 .flags = I2C_CLIENT_WAKE,
0323 },
0324 .dmi_name = "touchscreen",
0325 .irqflags = IRQF_TRIGGER_FALLING,
0326 .type = I2C_ADAPTER_PANEL,
0327 .alt_addr = ATMEL_TS_I2C_BL_ADDR,
0328 .properties = chromebook_atmel_touchscreen_props,
0329 },
0330
0331 {
0332 .board_info = {
0333 I2C_BOARD_INFO("atmel_mxt_tp",
0334 ATMEL_TP_I2C_ADDR),
0335 .flags = I2C_CLIENT_WAKE,
0336 },
0337 .dmi_name = "trackpad",
0338 .irqflags = IRQF_TRIGGER_FALLING,
0339 .type = I2C_ADAPTER_VGADDC,
0340 .alt_addr = ATMEL_TP_I2C_BL_ADDR,
0341 .properties = chromebook_pixel_trackpad_props,
0342 },
0343
0344 {
0345 .board_info = {
0346 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
0347 },
0348 .dmi_name = "lightsensor",
0349 .type = I2C_ADAPTER_PANEL,
0350 },
0351 };
0352 DECLARE_CROS_LAPTOP(chromebook_pixel);
0353
0354 static struct i2c_peripheral hp_chromebook_14_peripherals[] __initdata = {
0355
0356 {
0357 .board_info = {
0358 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
0359 .flags = I2C_CLIENT_WAKE,
0360 },
0361 .dmi_name = "trackpad",
0362 .type = I2C_ADAPTER_DESIGNWARE,
0363 },
0364 };
0365 DECLARE_CROS_LAPTOP(hp_chromebook_14);
0366
0367 static struct i2c_peripheral dell_chromebook_11_peripherals[] __initdata = {
0368
0369 {
0370 .board_info = {
0371 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
0372 .flags = I2C_CLIENT_WAKE,
0373 },
0374 .dmi_name = "trackpad",
0375 .type = I2C_ADAPTER_DESIGNWARE,
0376 },
0377
0378 {
0379 .board_info = {
0380 I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
0381 .flags = I2C_CLIENT_WAKE,
0382 },
0383 .dmi_name = "trackpad",
0384 .type = I2C_ADAPTER_DESIGNWARE,
0385 },
0386 };
0387 DECLARE_CROS_LAPTOP(dell_chromebook_11);
0388
0389 static struct i2c_peripheral toshiba_cb35_peripherals[] __initdata = {
0390
0391 {
0392 .board_info = {
0393 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
0394 .flags = I2C_CLIENT_WAKE,
0395 },
0396 .dmi_name = "trackpad",
0397 .type = I2C_ADAPTER_DESIGNWARE,
0398 },
0399 };
0400 DECLARE_CROS_LAPTOP(toshiba_cb35);
0401
0402 static struct i2c_peripheral acer_c7_chromebook_peripherals[] __initdata = {
0403
0404 {
0405 .board_info = {
0406 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
0407 .flags = I2C_CLIENT_WAKE,
0408 },
0409 .dmi_name = "trackpad",
0410 .type = I2C_ADAPTER_SMBUS,
0411 },
0412 };
0413 DECLARE_CROS_LAPTOP(acer_c7_chromebook);
0414
0415 static struct i2c_peripheral acer_ac700_peripherals[] __initdata = {
0416
0417 {
0418 .board_info = {
0419 I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
0420 },
0421 .type = I2C_ADAPTER_SMBUS,
0422 },
0423 };
0424 DECLARE_CROS_LAPTOP(acer_ac700);
0425
0426 static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
0427
0428 {
0429 .board_info = {
0430 I2C_BOARD_INFO("atmel_mxt_ts",
0431 ATMEL_TS_I2C_ADDR),
0432 .flags = I2C_CLIENT_WAKE,
0433 },
0434 .dmi_name = "touchscreen",
0435 .irqflags = IRQF_TRIGGER_FALLING,
0436 .type = I2C_ADAPTER_DESIGNWARE,
0437 .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
0438 .alt_addr = ATMEL_TS_I2C_BL_ADDR,
0439 .properties = chromebook_atmel_touchscreen_props,
0440 },
0441
0442 {
0443 .board_info = {
0444 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
0445 .flags = I2C_CLIENT_WAKE,
0446 },
0447 .dmi_name = "trackpad",
0448 .type = I2C_ADAPTER_DESIGNWARE,
0449 .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
0450 },
0451
0452 {
0453 .board_info = {
0454 I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
0455 .flags = I2C_CLIENT_WAKE,
0456 },
0457 .dmi_name = "trackpad",
0458 .type = I2C_ADAPTER_DESIGNWARE,
0459 .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
0460 },
0461
0462 {
0463 .board_info = {
0464 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
0465 },
0466 .dmi_name = "lightsensor",
0467 .type = I2C_ADAPTER_DESIGNWARE,
0468 .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
0469 },
0470 };
0471 DECLARE_CROS_LAPTOP(acer_c720);
0472
0473 static struct i2c_peripheral
0474 hp_pavilion_14_chromebook_peripherals[] __initdata = {
0475
0476 {
0477 .board_info = {
0478 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
0479 .flags = I2C_CLIENT_WAKE,
0480 },
0481 .dmi_name = "trackpad",
0482 .type = I2C_ADAPTER_SMBUS,
0483 },
0484 };
0485 DECLARE_CROS_LAPTOP(hp_pavilion_14_chromebook);
0486
0487 static struct i2c_peripheral cr48_peripherals[] __initdata = {
0488
0489 {
0490 .board_info = {
0491 I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
0492 },
0493 .type = I2C_ADAPTER_SMBUS,
0494 },
0495 };
0496 DECLARE_CROS_LAPTOP(cr48);
0497
0498 static const u32 samus_touchpad_buttons[] __initconst = {
0499 KEY_RESERVED,
0500 KEY_RESERVED,
0501 KEY_RESERVED,
0502 BTN_LEFT
0503 };
0504
0505 static const struct property_entry samus_trackpad_props[] __initconst = {
0506 PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
0507 PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons),
0508 { }
0509 };
0510
0511 static struct acpi_peripheral samus_peripherals[] __initdata = {
0512
0513 {
0514 .hid = "ATML0000",
0515 .swnode = {
0516 .properties = samus_trackpad_props,
0517 },
0518 },
0519
0520 {
0521 .hid = "ATML0001",
0522 .swnode = {
0523 .properties = chromebook_atmel_touchscreen_props,
0524 },
0525 },
0526 };
0527 DECLARE_ACPI_CROS_LAPTOP(samus);
0528
0529 static struct acpi_peripheral generic_atmel_peripherals[] __initdata = {
0530
0531 {
0532 .hid = "ATML0000",
0533 .swnode = {
0534 .properties = chromebook_pixel_trackpad_props,
0535 },
0536 },
0537
0538 {
0539 .hid = "ATML0001",
0540 .swnode = {
0541 .properties = chromebook_atmel_touchscreen_props,
0542 },
0543 },
0544 };
0545 DECLARE_ACPI_CROS_LAPTOP(generic_atmel);
0546
0547 static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
0548 {
0549 .ident = "Samsung Series 5 550",
0550 .matches = {
0551 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
0552 DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
0553 },
0554 .driver_data = (void *)&samsung_series_5_550,
0555 },
0556 {
0557 .ident = "Samsung Series 5",
0558 .matches = {
0559 DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
0560 },
0561 .driver_data = (void *)&samsung_series_5,
0562 },
0563 {
0564 .ident = "Chromebook Pixel",
0565 .matches = {
0566 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
0567 DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
0568 },
0569 .driver_data = (void *)&chromebook_pixel,
0570 },
0571 {
0572 .ident = "Wolf",
0573 .matches = {
0574 DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
0575 DMI_MATCH(DMI_PRODUCT_NAME, "Wolf"),
0576 },
0577 .driver_data = (void *)&dell_chromebook_11,
0578 },
0579 {
0580 .ident = "HP Chromebook 14",
0581 .matches = {
0582 DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
0583 DMI_MATCH(DMI_PRODUCT_NAME, "Falco"),
0584 },
0585 .driver_data = (void *)&hp_chromebook_14,
0586 },
0587 {
0588 .ident = "Toshiba CB35",
0589 .matches = {
0590 DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
0591 DMI_MATCH(DMI_PRODUCT_NAME, "Leon"),
0592 },
0593 .driver_data = (void *)&toshiba_cb35,
0594 },
0595 {
0596 .ident = "Acer C7 Chromebook",
0597 .matches = {
0598 DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
0599 },
0600 .driver_data = (void *)&acer_c7_chromebook,
0601 },
0602 {
0603 .ident = "Acer AC700",
0604 .matches = {
0605 DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
0606 },
0607 .driver_data = (void *)&acer_ac700,
0608 },
0609 {
0610 .ident = "Acer C720",
0611 .matches = {
0612 DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"),
0613 },
0614 .driver_data = (void *)&acer_c720,
0615 },
0616 {
0617 .ident = "HP Pavilion 14 Chromebook",
0618 .matches = {
0619 DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
0620 },
0621 .driver_data = (void *)&hp_pavilion_14_chromebook,
0622 },
0623 {
0624 .ident = "Cr-48",
0625 .matches = {
0626 DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
0627 },
0628 .driver_data = (void *)&cr48,
0629 },
0630
0631 {
0632 .ident = "Chromebook Pro",
0633 .matches = {
0634 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
0635 DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"),
0636 },
0637 .driver_data = (void *)&samus,
0638 },
0639 {
0640 .ident = "Google Pixel 2 (2015)",
0641 .matches = {
0642 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
0643 DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
0644 },
0645 .driver_data = (void *)&samus,
0646 },
0647 {
0648 .ident = "Samsung Chromebook 3",
0649 .matches = {
0650 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
0651 DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
0652 },
0653 .driver_data = (void *)&samus,
0654 },
0655 {
0656
0657
0658
0659
0660
0661 .ident = "Other Chromebook",
0662 .matches = {
0663
0664
0665
0666
0667
0668 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
0669 },
0670 .driver_data = (void *)&generic_atmel,
0671 },
0672 { }
0673 };
0674 MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
0675
0676 static int __init chromeos_laptop_scan_peripherals(struct device *dev, void *data)
0677 {
0678 int error;
0679
0680 if (dev->type == &i2c_adapter_type) {
0681 chromeos_laptop_check_adapter(to_i2c_adapter(dev));
0682 } else if (dev->type == &i2c_client_type) {
0683 if (chromeos_laptop_adjust_client(to_i2c_client(dev))) {
0684
0685
0686
0687
0688
0689 error = device_attach(dev);
0690 if (error < 0)
0691 dev_warn(dev,
0692 "%s: device_attach() failed: %d\n",
0693 __func__, error);
0694 }
0695 }
0696
0697 return 0;
0698 }
0699
0700 static int __init chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
0701 {
0702 const struct dmi_device *dmi_dev;
0703 const struct dmi_dev_onboard *dev_data;
0704
0705 dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, dmi_name, NULL);
0706 if (!dmi_dev) {
0707 pr_err("failed to find DMI device '%s'\n", dmi_name);
0708 return -ENOENT;
0709 }
0710
0711 dev_data = dmi_dev->device_data;
0712 if (!dev_data) {
0713 pr_err("failed to get data from DMI for '%s'\n", dmi_name);
0714 return -EINVAL;
0715 }
0716
0717 return dev_data->instance;
0718 }
0719
0720 static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev)
0721 {
0722 int irq;
0723
0724 if (i2c_dev->dmi_name) {
0725 irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name);
0726 if (irq < 0)
0727 return irq;
0728
0729 i2c_dev->irq_resource = (struct resource)
0730 DEFINE_RES_NAMED(irq, 1, NULL,
0731 IORESOURCE_IRQ | i2c_dev->irqflags);
0732 i2c_dev->board_info.resources = &i2c_dev->irq_resource;
0733 i2c_dev->board_info.num_resources = 1;
0734 }
0735
0736 return 0;
0737 }
0738
0739 static int __init
0740 chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop *cros_laptop,
0741 const struct chromeos_laptop *src)
0742 {
0743 struct i2c_peripheral *i2c_dev;
0744 struct i2c_board_info *info;
0745 int i;
0746 int error;
0747
0748 if (!src->num_i2c_peripherals)
0749 return 0;
0750
0751 cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals,
0752 src->num_i2c_peripherals *
0753 sizeof(*src->i2c_peripherals),
0754 GFP_KERNEL);
0755 if (!cros_laptop->i2c_peripherals)
0756 return -ENOMEM;
0757
0758 cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals;
0759
0760 for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
0761 i2c_dev = &cros_laptop->i2c_peripherals[i];
0762 info = &i2c_dev->board_info;
0763
0764 error = chromeos_laptop_setup_irq(i2c_dev);
0765 if (error)
0766 goto err_out;
0767
0768
0769 if (i2c_dev->properties) {
0770 info->fwnode = fwnode_create_software_node(i2c_dev->properties, NULL);
0771 if (IS_ERR(info->fwnode)) {
0772 error = PTR_ERR(info->fwnode);
0773 goto err_out;
0774 }
0775 }
0776 }
0777
0778 return 0;
0779
0780 err_out:
0781 while (--i >= 0) {
0782 i2c_dev = &cros_laptop->i2c_peripherals[i];
0783 info = &i2c_dev->board_info;
0784 if (!IS_ERR_OR_NULL(info->fwnode))
0785 fwnode_remove_software_node(info->fwnode);
0786 }
0787 kfree(cros_laptop->i2c_peripherals);
0788 return error;
0789 }
0790
0791 static int __init
0792 chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop,
0793 const struct chromeos_laptop *src)
0794 {
0795 struct acpi_peripheral *acpi_peripherals;
0796 struct acpi_peripheral *acpi_dev;
0797 const struct acpi_peripheral *src_dev;
0798 int n_peripherals = 0;
0799 int i;
0800 int error;
0801
0802 for (i = 0; i < src->num_acpi_peripherals; i++) {
0803 if (acpi_dev_present(src->acpi_peripherals[i].hid, NULL, -1))
0804 n_peripherals++;
0805 }
0806
0807 if (!n_peripherals)
0808 return 0;
0809
0810 acpi_peripherals = kcalloc(n_peripherals,
0811 sizeof(*src->acpi_peripherals),
0812 GFP_KERNEL);
0813 if (!acpi_peripherals)
0814 return -ENOMEM;
0815
0816 acpi_dev = acpi_peripherals;
0817 for (i = 0; i < src->num_acpi_peripherals; i++) {
0818 src_dev = &src->acpi_peripherals[i];
0819 if (!acpi_dev_present(src_dev->hid, NULL, -1))
0820 continue;
0821
0822 *acpi_dev = *src_dev;
0823
0824
0825 if (src_dev->swnode.properties) {
0826 acpi_dev->swnode.properties =
0827 property_entries_dup(src_dev->swnode.properties);
0828 if (IS_ERR(acpi_dev->swnode.properties)) {
0829 error = PTR_ERR(acpi_dev->swnode.properties);
0830 goto err_out;
0831 }
0832 }
0833
0834 acpi_dev++;
0835 }
0836
0837 cros_laptop->acpi_peripherals = acpi_peripherals;
0838 cros_laptop->num_acpi_peripherals = n_peripherals;
0839
0840 return 0;
0841
0842 err_out:
0843 while (--i >= 0) {
0844 acpi_dev = &acpi_peripherals[i];
0845 if (!IS_ERR_OR_NULL(acpi_dev->swnode.properties))
0846 property_entries_free(acpi_dev->swnode.properties);
0847 }
0848
0849 kfree(acpi_peripherals);
0850 return error;
0851 }
0852
0853 static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
0854 {
0855 const struct acpi_peripheral *acpi_dev;
0856 struct i2c_peripheral *i2c_dev;
0857 int i;
0858
0859 for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
0860 i2c_dev = &cros_laptop->i2c_peripherals[i];
0861 i2c_unregister_device(i2c_dev->client);
0862 }
0863
0864 for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
0865 acpi_dev = &cros_laptop->acpi_peripherals[i];
0866
0867 if (acpi_dev->client)
0868 device_remove_software_node(&acpi_dev->client->dev);
0869
0870 property_entries_free(acpi_dev->swnode.properties);
0871 }
0872
0873 kfree(cros_laptop->i2c_peripherals);
0874 kfree(cros_laptop->acpi_peripherals);
0875 kfree(cros_laptop);
0876 }
0877
0878 static struct chromeos_laptop * __init
0879 chromeos_laptop_prepare(const struct chromeos_laptop *src)
0880 {
0881 struct chromeos_laptop *cros_laptop;
0882 int error;
0883
0884 cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
0885 if (!cros_laptop)
0886 return ERR_PTR(-ENOMEM);
0887
0888 error = chromeos_laptop_prepare_i2c_peripherals(cros_laptop, src);
0889 if (!error)
0890 error = chromeos_laptop_prepare_acpi_peripherals(cros_laptop,
0891 src);
0892
0893 if (error) {
0894 chromeos_laptop_destroy(cros_laptop);
0895 return ERR_PTR(error);
0896 }
0897
0898 return cros_laptop;
0899 }
0900
0901 static int __init chromeos_laptop_init(void)
0902 {
0903 const struct dmi_system_id *dmi_id;
0904 int error;
0905
0906 dmi_id = dmi_first_match(chromeos_laptop_dmi_table);
0907 if (!dmi_id) {
0908 pr_debug("unsupported system\n");
0909 return -ENODEV;
0910 }
0911
0912 pr_debug("DMI Matched %s\n", dmi_id->ident);
0913
0914 cros_laptop = chromeos_laptop_prepare((void *)dmi_id->driver_data);
0915 if (IS_ERR(cros_laptop))
0916 return PTR_ERR(cros_laptop);
0917
0918 if (!cros_laptop->num_i2c_peripherals &&
0919 !cros_laptop->num_acpi_peripherals) {
0920 pr_debug("no relevant devices detected\n");
0921 error = -ENODEV;
0922 goto err_destroy_cros_laptop;
0923 }
0924
0925 error = bus_register_notifier(&i2c_bus_type,
0926 &chromeos_laptop_i2c_notifier);
0927 if (error) {
0928 pr_err("failed to register i2c bus notifier: %d\n",
0929 error);
0930 goto err_destroy_cros_laptop;
0931 }
0932
0933
0934
0935
0936
0937
0938 i2c_for_each_dev(NULL, chromeos_laptop_scan_peripherals);
0939
0940 return 0;
0941
0942 err_destroy_cros_laptop:
0943 chromeos_laptop_destroy(cros_laptop);
0944 return error;
0945 }
0946
0947 static void __exit chromeos_laptop_exit(void)
0948 {
0949 bus_unregister_notifier(&i2c_bus_type, &chromeos_laptop_i2c_notifier);
0950 chromeos_laptop_destroy(cros_laptop);
0951 }
0952
0953 module_init(chromeos_laptop_init);
0954 module_exit(chromeos_laptop_exit);
0955
0956 MODULE_DESCRIPTION("Chrome OS Laptop driver");
0957 MODULE_AUTHOR("Benson Leung <bleung@chromium.org>");
0958 MODULE_LICENSE("GPL");