Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 // Driver to instantiate Chromebook i2c/smbus devices.
0003 //
0004 // Copyright (C) 2012 Google, Inc.
0005 // Author: Benson Leung <bleung@chromium.org>
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 /* Keep this enum consistent with i2c_adapter_names */
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      * Note that we can't mark this pointer as const because
0069      * i2c_new_scanned_device() changes passed in I2C board info, so.
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      * Add the i2c device. If we can't detect it at the primary
0090      * address we scan secondary addresses. In any case the client
0091      * structure gets assigned primary address.
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         /* Skip devices already created */
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     /* Touchpad. */
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     /* Light Sensor. */
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     /* Light Sensor. */
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     /* Touch Screen. */
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     /* Touchpad. */
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     /* Light Sensor. */
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     /* Touchpad. */
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     /* Touchpad. */
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     /* Elan Touchpad option. */
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     /* Touchpad. */
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     /* Touchpad. */
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     /* Light Sensor. */
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     /* Touchscreen. */
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     /* Touchpad. */
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     /* Elan Touchpad option. */
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     /* Light Sensor. */
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     /* Touchpad. */
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     /* Light Sensor. */
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     /* Touchpad */
0513     {
0514         .hid        = "ATML0000",
0515         .swnode     = {
0516             .properties = samus_trackpad_props,
0517         },
0518     },
0519     /* Touchsceen */
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     /* Touchpad */
0531     {
0532         .hid        = "ATML0000",
0533         .swnode     = {
0534             .properties = chromebook_pixel_trackpad_props,
0535         },
0536     },
0537     /* Touchsceen */
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     /* Devices with peripherals incompletely described in ACPI */
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          * Other Chromebooks with Atmel touch controllers:
0658          * - Winky (touchpad)
0659          * - Clapper, Expresso, Rambi, Glimmer (touchscreen)
0660          */
0661         .ident = "Other Chromebook",
0662         .matches = {
0663             /*
0664              * This will match all Google devices, not only devices
0665              * with Atmel, but we will validate that the device
0666              * actually has matching peripherals.
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              * Now that we have needed properties re-trigger
0686              * driver probe in case driver was initialized
0687              * earlier and probe failed.
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         /* Create primary fwnode for the device - copies everything */
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         /* We need to deep-copy properties */
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      * Scan adapters that have been registered and clients that have
0935      * been created before we installed the notifier to make sure
0936      * we do not miss any devices.
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");