GNU Linux-libre 5.15.54-gnu
[releases.git] / drivers / platform / chrome / chromeos_laptop.c
1 // SPDX-License-Identifier: GPL-2.0+
2 // Driver to instantiate Chromebook i2c/smbus devices.
3 //
4 // Copyright (C) 2012 Google, Inc.
5 // Author: Benson Leung <bleung@chromium.org>
6
7 #define pr_fmt(fmt)             KBUILD_MODNAME ": " fmt
8
9 #include <linux/acpi.h>
10 #include <linux/dmi.h>
11 #include <linux/i2c.h>
12 #include <linux/input.h>
13 #include <linux/interrupt.h>
14 #include <linux/ioport.h>
15 #include <linux/module.h>
16 #include <linux/pci.h>
17 #include <linux/platform_device.h>
18 #include <linux/property.h>
19
20 #define ATMEL_TP_I2C_ADDR       0x4b
21 #define ATMEL_TP_I2C_BL_ADDR    0x25
22 #define ATMEL_TS_I2C_ADDR       0x4a
23 #define ATMEL_TS_I2C_BL_ADDR    0x26
24 #define CYAPA_TP_I2C_ADDR       0x67
25 #define ELAN_TP_I2C_ADDR        0x15
26 #define ISL_ALS_I2C_ADDR        0x44
27 #define TAOS_ALS_I2C_ADDR       0x29
28
29 static const char *i2c_adapter_names[] = {
30         "SMBus I801 adapter",
31         "i915 gmbus vga",
32         "i915 gmbus panel",
33         "Synopsys DesignWare I2C adapter",
34 };
35
36 /* Keep this enum consistent with i2c_adapter_names */
37 enum i2c_adapter_type {
38         I2C_ADAPTER_SMBUS = 0,
39         I2C_ADAPTER_VGADDC,
40         I2C_ADAPTER_PANEL,
41         I2C_ADAPTER_DESIGNWARE,
42 };
43
44 struct i2c_peripheral {
45         struct i2c_board_info board_info;
46         unsigned short alt_addr;
47
48         const char *dmi_name;
49         unsigned long irqflags;
50         struct resource irq_resource;
51
52         enum i2c_adapter_type type;
53         u32 pci_devid;
54
55         const struct property_entry *properties;
56
57         struct i2c_client *client;
58 };
59
60 struct acpi_peripheral {
61         char hid[ACPI_ID_LEN];
62         struct software_node swnode;
63         struct i2c_client *client;
64 };
65
66 struct chromeos_laptop {
67         /*
68          * Note that we can't mark this pointer as const because
69          * i2c_new_scanned_device() changes passed in I2C board info, so.
70          */
71         struct i2c_peripheral *i2c_peripherals;
72         unsigned int num_i2c_peripherals;
73
74         struct acpi_peripheral *acpi_peripherals;
75         unsigned int num_acpi_peripherals;
76 };
77
78 static const struct chromeos_laptop *cros_laptop;
79
80 static struct i2c_client *
81 chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter,
82                                       struct i2c_board_info *info,
83                                       unsigned short alt_addr)
84 {
85         const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
86         struct i2c_client *client;
87
88         /*
89          * Add the i2c device. If we can't detect it at the primary
90          * address we scan secondary addresses. In any case the client
91          * structure gets assigned primary address.
92          */
93         client = i2c_new_scanned_device(adapter, info, addr_list, NULL);
94         if (IS_ERR(client) && alt_addr) {
95                 struct i2c_board_info dummy_info = {
96                         I2C_BOARD_INFO("dummy", info->addr),
97                 };
98                 const unsigned short alt_addr_list[] = {
99                         alt_addr, I2C_CLIENT_END
100                 };
101                 struct i2c_client *dummy;
102
103                 dummy = i2c_new_scanned_device(adapter, &dummy_info,
104                                                alt_addr_list, NULL);
105                 if (!IS_ERR(dummy)) {
106                         pr_debug("%d-%02x is probed at %02x\n",
107                                  adapter->nr, info->addr, dummy->addr);
108                         i2c_unregister_device(dummy);
109                         client = i2c_new_client_device(adapter, info);
110                 }
111         }
112
113         if (IS_ERR(client)) {
114                 client = NULL;
115                 pr_debug("failed to register device %d-%02x\n",
116                          adapter->nr, info->addr);
117         } else {
118                 pr_debug("added i2c device %d-%02x\n",
119                          adapter->nr, info->addr);
120         }
121
122         return client;
123 }
124
125 static bool chromeos_laptop_match_adapter_devid(struct device *dev, u32 devid)
126 {
127         struct pci_dev *pdev;
128
129         if (!dev_is_pci(dev))
130                 return false;
131
132         pdev = to_pci_dev(dev);
133         return devid == pci_dev_id(pdev);
134 }
135
136 static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
137 {
138         struct i2c_peripheral *i2c_dev;
139         int i;
140
141         for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
142                 i2c_dev = &cros_laptop->i2c_peripherals[i];
143
144                 /* Skip devices already created */
145                 if (i2c_dev->client)
146                         continue;
147
148                 if (strncmp(adapter->name, i2c_adapter_names[i2c_dev->type],
149                             strlen(i2c_adapter_names[i2c_dev->type])))
150                         continue;
151
152                 if (i2c_dev->pci_devid &&
153                     !chromeos_laptop_match_adapter_devid(adapter->dev.parent,
154                                                          i2c_dev->pci_devid)) {
155                         continue;
156                 }
157
158                 i2c_dev->client =
159                         chromes_laptop_instantiate_i2c_device(adapter,
160                                                         &i2c_dev->board_info,
161                                                         i2c_dev->alt_addr);
162         }
163 }
164
165 static bool chromeos_laptop_adjust_client(struct i2c_client *client)
166 {
167         struct acpi_peripheral *acpi_dev;
168         struct acpi_device_id acpi_ids[2] = { };
169         int i;
170         int error;
171
172         if (!has_acpi_companion(&client->dev))
173                 return false;
174
175         for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
176                 acpi_dev = &cros_laptop->acpi_peripherals[i];
177
178                 memcpy(acpi_ids[0].id, acpi_dev->hid, ACPI_ID_LEN);
179
180                 if (acpi_match_device(acpi_ids, &client->dev)) {
181                         error = device_add_software_node(&client->dev, &acpi_dev->swnode);
182                         if (error) {
183                                 dev_err(&client->dev,
184                                         "failed to add properties: %d\n",
185                                         error);
186                                 break;
187                         }
188
189                         acpi_dev->client = client;
190
191                         return true;
192                 }
193         }
194
195         return false;
196 }
197
198 static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
199 {
200         struct acpi_peripheral *acpi_dev;
201         struct i2c_peripheral *i2c_dev;
202         int i;
203
204         if (has_acpi_companion(&client->dev))
205                 for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
206                         acpi_dev = &cros_laptop->acpi_peripherals[i];
207
208                         if (acpi_dev->client == client) {
209                                 acpi_dev->client = NULL;
210                                 return;
211                         }
212                 }
213         else
214                 for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
215                         i2c_dev = &cros_laptop->i2c_peripherals[i];
216
217                         if (i2c_dev->client == client) {
218                                 i2c_dev->client = NULL;
219                                 return;
220                         }
221                 }
222 }
223
224 static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb,
225                                              unsigned long action, void *data)
226 {
227         struct device *dev = data;
228
229         switch (action) {
230         case BUS_NOTIFY_ADD_DEVICE:
231                 if (dev->type == &i2c_adapter_type)
232                         chromeos_laptop_check_adapter(to_i2c_adapter(dev));
233                 else if (dev->type == &i2c_client_type)
234                         chromeos_laptop_adjust_client(to_i2c_client(dev));
235                 break;
236
237         case BUS_NOTIFY_REMOVED_DEVICE:
238                 if (dev->type == &i2c_client_type)
239                         chromeos_laptop_detach_i2c_client(to_i2c_client(dev));
240                 break;
241         }
242
243         return 0;
244 }
245
246 static struct notifier_block chromeos_laptop_i2c_notifier = {
247         .notifier_call = chromeos_laptop_i2c_notifier_call,
248 };
249
250 #define DECLARE_CROS_LAPTOP(_name)                                      \
251 static const struct chromeos_laptop _name __initconst = {               \
252         .i2c_peripherals        = _name##_peripherals,                  \
253         .num_i2c_peripherals    = ARRAY_SIZE(_name##_peripherals),      \
254 }
255
256 #define DECLARE_ACPI_CROS_LAPTOP(_name)                                 \
257 static const struct chromeos_laptop _name __initconst = {               \
258         .acpi_peripherals       = _name##_peripherals,                  \
259         .num_acpi_peripherals   = ARRAY_SIZE(_name##_peripherals),      \
260 }
261
262 static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = {
263         /* Touchpad. */
264         {
265                 .board_info     = {
266                         I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
267                         .flags          = I2C_CLIENT_WAKE,
268                 },
269                 .dmi_name       = "trackpad",
270                 .type           = I2C_ADAPTER_SMBUS,
271         },
272         /* Light Sensor. */
273         {
274                 .board_info     = {
275                         I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
276                 },
277                 .dmi_name       = "lightsensor",
278                 .type           = I2C_ADAPTER_SMBUS,
279         },
280 };
281 DECLARE_CROS_LAPTOP(samsung_series_5_550);
282
283 static struct i2c_peripheral samsung_series_5_peripherals[] __initdata = {
284         /* Light Sensor. */
285         {
286                 .board_info     = {
287                         I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
288                 },
289                 .type           = I2C_ADAPTER_SMBUS,
290         },
291 };
292 DECLARE_CROS_LAPTOP(samsung_series_5);
293
294 static const int chromebook_pixel_tp_keys[] __initconst = {
295         KEY_RESERVED,
296         KEY_RESERVED,
297         KEY_RESERVED,
298         KEY_RESERVED,
299         KEY_RESERVED,
300         BTN_LEFT
301 };
302
303 static const struct property_entry
304 chromebook_pixel_trackpad_props[] __initconst = {
305         PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
306         PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys),
307         { }
308 };
309
310 static const struct property_entry
311 chromebook_atmel_touchscreen_props[] __initconst = {
312         PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
313         { }
314 };
315
316 static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = {
317         /* Touch Screen. */
318         {
319                 .board_info     = {
320                         I2C_BOARD_INFO("atmel_mxt_ts",
321                                         ATMEL_TS_I2C_ADDR),
322                         .flags          = I2C_CLIENT_WAKE,
323                 },
324                 .dmi_name       = "touchscreen",
325                 .irqflags       = IRQF_TRIGGER_FALLING,
326                 .type           = I2C_ADAPTER_PANEL,
327                 .alt_addr       = ATMEL_TS_I2C_BL_ADDR,
328                 .properties     = chromebook_atmel_touchscreen_props,
329         },
330         /* Touchpad. */
331         {
332                 .board_info     = {
333                         I2C_BOARD_INFO("atmel_mxt_tp",
334                                         ATMEL_TP_I2C_ADDR),
335                         .flags          = I2C_CLIENT_WAKE,
336                 },
337                 .dmi_name       = "trackpad",
338                 .irqflags       = IRQF_TRIGGER_FALLING,
339                 .type           = I2C_ADAPTER_VGADDC,
340                 .alt_addr       = ATMEL_TP_I2C_BL_ADDR,
341                 .properties     = chromebook_pixel_trackpad_props,
342         },
343         /* Light Sensor. */
344         {
345                 .board_info     = {
346                         I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
347                 },
348                 .dmi_name       = "lightsensor",
349                 .type           = I2C_ADAPTER_PANEL,
350         },
351 };
352 DECLARE_CROS_LAPTOP(chromebook_pixel);
353
354 static struct i2c_peripheral hp_chromebook_14_peripherals[] __initdata = {
355         /* Touchpad. */
356         {
357                 .board_info     = {
358                         I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
359                         .flags          = I2C_CLIENT_WAKE,
360                 },
361                 .dmi_name       = "trackpad",
362                 .type           = I2C_ADAPTER_DESIGNWARE,
363         },
364 };
365 DECLARE_CROS_LAPTOP(hp_chromebook_14);
366
367 static struct i2c_peripheral dell_chromebook_11_peripherals[] __initdata = {
368         /* Touchpad. */
369         {
370                 .board_info     = {
371                         I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
372                         .flags          = I2C_CLIENT_WAKE,
373                 },
374                 .dmi_name       = "trackpad",
375                 .type           = I2C_ADAPTER_DESIGNWARE,
376         },
377         /* Elan Touchpad option. */
378         {
379                 .board_info     = {
380                         I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
381                         .flags          = I2C_CLIENT_WAKE,
382                 },
383                 .dmi_name       = "trackpad",
384                 .type           = I2C_ADAPTER_DESIGNWARE,
385         },
386 };
387 DECLARE_CROS_LAPTOP(dell_chromebook_11);
388
389 static struct i2c_peripheral toshiba_cb35_peripherals[] __initdata = {
390         /* Touchpad. */
391         {
392                 .board_info     = {
393                         I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
394                         .flags          = I2C_CLIENT_WAKE,
395                 },
396                 .dmi_name       = "trackpad",
397                 .type           = I2C_ADAPTER_DESIGNWARE,
398         },
399 };
400 DECLARE_CROS_LAPTOP(toshiba_cb35);
401
402 static struct i2c_peripheral acer_c7_chromebook_peripherals[] __initdata = {
403         /* Touchpad. */
404         {
405                 .board_info     = {
406                         I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
407                         .flags          = I2C_CLIENT_WAKE,
408                 },
409                 .dmi_name       = "trackpad",
410                 .type           = I2C_ADAPTER_SMBUS,
411         },
412 };
413 DECLARE_CROS_LAPTOP(acer_c7_chromebook);
414
415 static struct i2c_peripheral acer_ac700_peripherals[] __initdata = {
416         /* Light Sensor. */
417         {
418                 .board_info     = {
419                         I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
420                 },
421                 .type           = I2C_ADAPTER_SMBUS,
422         },
423 };
424 DECLARE_CROS_LAPTOP(acer_ac700);
425
426 static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
427         /* Touchscreen. */
428         {
429                 .board_info     = {
430                         I2C_BOARD_INFO("atmel_mxt_ts",
431                                         ATMEL_TS_I2C_ADDR),
432                         .flags          = I2C_CLIENT_WAKE,
433                 },
434                 .dmi_name       = "touchscreen",
435                 .irqflags       = IRQF_TRIGGER_FALLING,
436                 .type           = I2C_ADAPTER_DESIGNWARE,
437                 .pci_devid      = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
438                 .alt_addr       = ATMEL_TS_I2C_BL_ADDR,
439                 .properties     = chromebook_atmel_touchscreen_props,
440         },
441         /* Touchpad. */
442         {
443                 .board_info     = {
444                         I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
445                         .flags          = I2C_CLIENT_WAKE,
446                 },
447                 .dmi_name       = "trackpad",
448                 .type           = I2C_ADAPTER_DESIGNWARE,
449                 .pci_devid      = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
450         },
451         /* Elan Touchpad option. */
452         {
453                 .board_info     = {
454                         I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
455                         .flags          = I2C_CLIENT_WAKE,
456                 },
457                 .dmi_name       = "trackpad",
458                 .type           = I2C_ADAPTER_DESIGNWARE,
459                 .pci_devid      = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
460         },
461         /* Light Sensor. */
462         {
463                 .board_info     = {
464                         I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
465                 },
466                 .dmi_name       = "lightsensor",
467                 .type           = I2C_ADAPTER_DESIGNWARE,
468                 .pci_devid      = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
469         },
470 };
471 DECLARE_CROS_LAPTOP(acer_c720);
472
473 static struct i2c_peripheral
474 hp_pavilion_14_chromebook_peripherals[] __initdata = {
475         /* Touchpad. */
476         {
477                 .board_info     = {
478                         I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
479                         .flags          = I2C_CLIENT_WAKE,
480                 },
481                 .dmi_name       = "trackpad",
482                 .type           = I2C_ADAPTER_SMBUS,
483         },
484 };
485 DECLARE_CROS_LAPTOP(hp_pavilion_14_chromebook);
486
487 static struct i2c_peripheral cr48_peripherals[] __initdata = {
488         /* Light Sensor. */
489         {
490                 .board_info     = {
491                         I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
492                 },
493                 .type           = I2C_ADAPTER_SMBUS,
494         },
495 };
496 DECLARE_CROS_LAPTOP(cr48);
497
498 static const u32 samus_touchpad_buttons[] __initconst = {
499         KEY_RESERVED,
500         KEY_RESERVED,
501         KEY_RESERVED,
502         BTN_LEFT
503 };
504
505 static const struct property_entry samus_trackpad_props[] __initconst = {
506         PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
507         PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons),
508         { }
509 };
510
511 static struct acpi_peripheral samus_peripherals[] __initdata = {
512         /* Touchpad */
513         {
514                 .hid            = "ATML0000",
515                 .swnode         = {
516                         .properties = samus_trackpad_props,
517                 },
518         },
519         /* Touchsceen */
520         {
521                 .hid            = "ATML0001",
522                 .swnode         = {
523                         .properties = chromebook_atmel_touchscreen_props,
524                 },
525         },
526 };
527 DECLARE_ACPI_CROS_LAPTOP(samus);
528
529 static struct acpi_peripheral generic_atmel_peripherals[] __initdata = {
530         /* Touchpad */
531         {
532                 .hid            = "ATML0000",
533                 .swnode         = {
534                         .properties = chromebook_pixel_trackpad_props,
535                 },
536         },
537         /* Touchsceen */
538         {
539                 .hid            = "ATML0001",
540                 .swnode         = {
541                         .properties = chromebook_atmel_touchscreen_props,
542                 },
543         },
544 };
545 DECLARE_ACPI_CROS_LAPTOP(generic_atmel);
546
547 static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
548         {
549                 .ident = "Samsung Series 5 550",
550                 .matches = {
551                         DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
552                         DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
553                 },
554                 .driver_data = (void *)&samsung_series_5_550,
555         },
556         {
557                 .ident = "Samsung Series 5",
558                 .matches = {
559                         DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
560                 },
561                 .driver_data = (void *)&samsung_series_5,
562         },
563         {
564                 .ident = "Chromebook Pixel",
565                 .matches = {
566                         DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
567                         DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
568                 },
569                 .driver_data = (void *)&chromebook_pixel,
570         },
571         {
572                 .ident = "Wolf",
573                 .matches = {
574                         DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
575                         DMI_MATCH(DMI_PRODUCT_NAME, "Wolf"),
576                 },
577                 .driver_data = (void *)&dell_chromebook_11,
578         },
579         {
580                 .ident = "HP Chromebook 14",
581                 .matches = {
582                         DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
583                         DMI_MATCH(DMI_PRODUCT_NAME, "Falco"),
584                 },
585                 .driver_data = (void *)&hp_chromebook_14,
586         },
587         {
588                 .ident = "Toshiba CB35",
589                 .matches = {
590                         DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
591                         DMI_MATCH(DMI_PRODUCT_NAME, "Leon"),
592                 },
593                 .driver_data = (void *)&toshiba_cb35,
594         },
595         {
596                 .ident = "Acer C7 Chromebook",
597                 .matches = {
598                         DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
599                 },
600                 .driver_data = (void *)&acer_c7_chromebook,
601         },
602         {
603                 .ident = "Acer AC700",
604                 .matches = {
605                         DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
606                 },
607                 .driver_data = (void *)&acer_ac700,
608         },
609         {
610                 .ident = "Acer C720",
611                 .matches = {
612                         DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"),
613                 },
614                 .driver_data = (void *)&acer_c720,
615         },
616         {
617                 .ident = "HP Pavilion 14 Chromebook",
618                 .matches = {
619                         DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
620                 },
621                 .driver_data = (void *)&hp_pavilion_14_chromebook,
622         },
623         {
624                 .ident = "Cr-48",
625                 .matches = {
626                         DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
627                 },
628                 .driver_data = (void *)&cr48,
629         },
630         /* Devices with peripherals incompletely described in ACPI */
631         {
632                 .ident = "Chromebook Pro",
633                 .matches = {
634                         DMI_MATCH(DMI_SYS_VENDOR, "Google"),
635                         DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"),
636                 },
637                 .driver_data = (void *)&samus,
638         },
639         {
640                 .ident = "Google Pixel 2 (2015)",
641                 .matches = {
642                         DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
643                         DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
644                 },
645                 .driver_data = (void *)&samus,
646         },
647         {
648                 .ident = "Samsung Chromebook 3",
649                 .matches = {
650                         DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
651                         DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
652                 },
653                 .driver_data = (void *)&samus,
654         },
655         {
656                 /*
657                  * Other Chromebooks with Atmel touch controllers:
658                  * - Winky (touchpad)
659                  * - Clapper, Expresso, Rambi, Glimmer (touchscreen)
660                  */
661                 .ident = "Other Chromebook",
662                 .matches = {
663                         /*
664                          * This will match all Google devices, not only devices
665                          * with Atmel, but we will validate that the device
666                          * actually has matching peripherals.
667                          */
668                         DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
669                 },
670                 .driver_data = (void *)&generic_atmel,
671         },
672         { }
673 };
674 MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
675
676 static int __init chromeos_laptop_scan_peripherals(struct device *dev, void *data)
677 {
678         int error;
679
680         if (dev->type == &i2c_adapter_type) {
681                 chromeos_laptop_check_adapter(to_i2c_adapter(dev));
682         } else if (dev->type == &i2c_client_type) {
683                 if (chromeos_laptop_adjust_client(to_i2c_client(dev))) {
684                         /*
685                          * Now that we have needed properties re-trigger
686                          * driver probe in case driver was initialized
687                          * earlier and probe failed.
688                          */
689                         error = device_attach(dev);
690                         if (error < 0)
691                                 dev_warn(dev,
692                                          "%s: device_attach() failed: %d\n",
693                                          __func__, error);
694                 }
695         }
696
697         return 0;
698 }
699
700 static int __init chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
701 {
702         const struct dmi_device *dmi_dev;
703         const struct dmi_dev_onboard *dev_data;
704
705         dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, dmi_name, NULL);
706         if (!dmi_dev) {
707                 pr_err("failed to find DMI device '%s'\n", dmi_name);
708                 return -ENOENT;
709         }
710
711         dev_data = dmi_dev->device_data;
712         if (!dev_data) {
713                 pr_err("failed to get data from DMI for '%s'\n", dmi_name);
714                 return -EINVAL;
715         }
716
717         return dev_data->instance;
718 }
719
720 static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev)
721 {
722         int irq;
723
724         if (i2c_dev->dmi_name) {
725                 irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name);
726                 if (irq < 0)
727                         return irq;
728
729                 i2c_dev->irq_resource  = (struct resource)
730                         DEFINE_RES_NAMED(irq, 1, NULL,
731                                          IORESOURCE_IRQ | i2c_dev->irqflags);
732                 i2c_dev->board_info.resources = &i2c_dev->irq_resource;
733                 i2c_dev->board_info.num_resources = 1;
734         }
735
736         return 0;
737 }
738
739 static int __init
740 chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop *cros_laptop,
741                                         const struct chromeos_laptop *src)
742 {
743         struct i2c_peripheral *i2c_dev;
744         struct i2c_board_info *info;
745         int i;
746         int error;
747
748         if (!src->num_i2c_peripherals)
749                 return 0;
750
751         cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals,
752                                                src->num_i2c_peripherals *
753                                                 sizeof(*src->i2c_peripherals),
754                                                GFP_KERNEL);
755         if (!cros_laptop->i2c_peripherals)
756                 return -ENOMEM;
757
758         cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals;
759
760         for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
761                 i2c_dev = &cros_laptop->i2c_peripherals[i];
762                 info = &i2c_dev->board_info;
763
764                 error = chromeos_laptop_setup_irq(i2c_dev);
765                 if (error)
766                         goto err_out;
767
768                 /* Create primary fwnode for the device - copies everything */
769                 if (i2c_dev->properties) {
770                         info->fwnode = fwnode_create_software_node(i2c_dev->properties, NULL);
771                         if (IS_ERR(info->fwnode)) {
772                                 error = PTR_ERR(info->fwnode);
773                                 goto err_out;
774                         }
775                 }
776         }
777
778         return 0;
779
780 err_out:
781         while (--i >= 0) {
782                 i2c_dev = &cros_laptop->i2c_peripherals[i];
783                 info = &i2c_dev->board_info;
784                 if (!IS_ERR_OR_NULL(info->fwnode))
785                         fwnode_remove_software_node(info->fwnode);
786         }
787         kfree(cros_laptop->i2c_peripherals);
788         return error;
789 }
790
791 static int __init
792 chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop,
793                                         const struct chromeos_laptop *src)
794 {
795         struct acpi_peripheral *acpi_peripherals;
796         struct acpi_peripheral *acpi_dev;
797         const struct acpi_peripheral *src_dev;
798         int n_peripherals = 0;
799         int i;
800         int error;
801
802         for (i = 0; i < src->num_acpi_peripherals; i++) {
803                 if (acpi_dev_present(src->acpi_peripherals[i].hid, NULL, -1))
804                         n_peripherals++;
805         }
806
807         if (!n_peripherals)
808                 return 0;
809
810         acpi_peripherals = kcalloc(n_peripherals,
811                                    sizeof(*src->acpi_peripherals),
812                                    GFP_KERNEL);
813         if (!acpi_peripherals)
814                 return -ENOMEM;
815
816         acpi_dev = acpi_peripherals;
817         for (i = 0; i < src->num_acpi_peripherals; i++) {
818                 src_dev = &src->acpi_peripherals[i];
819                 if (!acpi_dev_present(src_dev->hid, NULL, -1))
820                         continue;
821
822                 *acpi_dev = *src_dev;
823
824                 /* We need to deep-copy properties */
825                 if (src_dev->swnode.properties) {
826                         acpi_dev->swnode.properties =
827                                 property_entries_dup(src_dev->swnode.properties);
828                         if (IS_ERR(acpi_dev->swnode.properties)) {
829                                 error = PTR_ERR(acpi_dev->swnode.properties);
830                                 goto err_out;
831                         }
832                 }
833
834                 acpi_dev++;
835         }
836
837         cros_laptop->acpi_peripherals = acpi_peripherals;
838         cros_laptop->num_acpi_peripherals = n_peripherals;
839
840         return 0;
841
842 err_out:
843         while (--i >= 0) {
844                 acpi_dev = &acpi_peripherals[i];
845                 if (!IS_ERR_OR_NULL(acpi_dev->swnode.properties))
846                         property_entries_free(acpi_dev->swnode.properties);
847         }
848
849         kfree(acpi_peripherals);
850         return error;
851 }
852
853 static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
854 {
855         const struct acpi_peripheral *acpi_dev;
856         struct i2c_peripheral *i2c_dev;
857         int i;
858
859         for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
860                 i2c_dev = &cros_laptop->i2c_peripherals[i];
861                 i2c_unregister_device(i2c_dev->client);
862         }
863
864         for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
865                 acpi_dev = &cros_laptop->acpi_peripherals[i];
866
867                 if (acpi_dev->client)
868                         device_remove_software_node(&acpi_dev->client->dev);
869
870                 property_entries_free(acpi_dev->swnode.properties);
871         }
872
873         kfree(cros_laptop->i2c_peripherals);
874         kfree(cros_laptop->acpi_peripherals);
875         kfree(cros_laptop);
876 }
877
878 static struct chromeos_laptop * __init
879 chromeos_laptop_prepare(const struct chromeos_laptop *src)
880 {
881         struct chromeos_laptop *cros_laptop;
882         int error;
883
884         cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
885         if (!cros_laptop)
886                 return ERR_PTR(-ENOMEM);
887
888         error = chromeos_laptop_prepare_i2c_peripherals(cros_laptop, src);
889         if (!error)
890                 error = chromeos_laptop_prepare_acpi_peripherals(cros_laptop,
891                                                                  src);
892
893         if (error) {
894                 chromeos_laptop_destroy(cros_laptop);
895                 return ERR_PTR(error);
896         }
897
898         return cros_laptop;
899 }
900
901 static int __init chromeos_laptop_init(void)
902 {
903         const struct dmi_system_id *dmi_id;
904         int error;
905
906         dmi_id = dmi_first_match(chromeos_laptop_dmi_table);
907         if (!dmi_id) {
908                 pr_debug("unsupported system\n");
909                 return -ENODEV;
910         }
911
912         pr_debug("DMI Matched %s\n", dmi_id->ident);
913
914         cros_laptop = chromeos_laptop_prepare((void *)dmi_id->driver_data);
915         if (IS_ERR(cros_laptop))
916                 return PTR_ERR(cros_laptop);
917
918         if (!cros_laptop->num_i2c_peripherals &&
919             !cros_laptop->num_acpi_peripherals) {
920                 pr_debug("no relevant devices detected\n");
921                 error = -ENODEV;
922                 goto err_destroy_cros_laptop;
923         }
924
925         error = bus_register_notifier(&i2c_bus_type,
926                                       &chromeos_laptop_i2c_notifier);
927         if (error) {
928                 pr_err("failed to register i2c bus notifier: %d\n",
929                        error);
930                 goto err_destroy_cros_laptop;
931         }
932
933         /*
934          * Scan adapters that have been registered and clients that have
935          * been created before we installed the notifier to make sure
936          * we do not miss any devices.
937          */
938         i2c_for_each_dev(NULL, chromeos_laptop_scan_peripherals);
939
940         return 0;
941
942 err_destroy_cros_laptop:
943         chromeos_laptop_destroy(cros_laptop);
944         return error;
945 }
946
947 static void __exit chromeos_laptop_exit(void)
948 {
949         bus_unregister_notifier(&i2c_bus_type, &chromeos_laptop_i2c_notifier);
950         chromeos_laptop_destroy(cros_laptop);
951 }
952
953 module_init(chromeos_laptop_init);
954 module_exit(chromeos_laptop_exit);
955
956 MODULE_DESCRIPTION("Chrome OS Laptop driver");
957 MODULE_AUTHOR("Benson Leung <bleung@chromium.org>");
958 MODULE_LICENSE("GPL");