1 // SPDX-License-Identifier: GPL-2.0+
2 // Driver to instantiate Chromebook i2c/smbus devices.
4 // Copyright (C) 2012 Google, Inc.
5 // Author: Benson Leung <bleung@chromium.org>
7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
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
29 static const char *i2c_adapter_names
[] = {
33 "Synopsys DesignWare I2C adapter",
36 /* Keep this enum consistent with i2c_adapter_names */
37 enum i2c_adapter_type
{
38 I2C_ADAPTER_SMBUS
= 0,
41 I2C_ADAPTER_DESIGNWARE
,
44 struct i2c_peripheral
{
45 struct i2c_board_info board_info
;
46 unsigned short alt_addr
;
49 unsigned long irqflags
;
50 struct resource irq_resource
;
52 enum i2c_adapter_type type
;
55 struct i2c_client
*client
;
58 struct acpi_peripheral
{
59 char hid
[ACPI_ID_LEN
];
60 const struct property_entry
*properties
;
63 struct chromeos_laptop
{
65 * Note that we can't mark this pointer as const because
66 * i2c_new_scanned_device() changes passed in I2C board info, so.
68 struct i2c_peripheral
*i2c_peripherals
;
69 unsigned int num_i2c_peripherals
;
71 const struct acpi_peripheral
*acpi_peripherals
;
72 unsigned int num_acpi_peripherals
;
75 static const struct chromeos_laptop
*cros_laptop
;
77 static struct i2c_client
*
78 chromes_laptop_instantiate_i2c_device(struct i2c_adapter
*adapter
,
79 struct i2c_board_info
*info
,
80 unsigned short alt_addr
)
82 const unsigned short addr_list
[] = { info
->addr
, I2C_CLIENT_END
};
83 struct i2c_client
*client
;
86 * Add the i2c device. If we can't detect it at the primary
87 * address we scan secondary addresses. In any case the client
88 * structure gets assigned primary address.
90 client
= i2c_new_scanned_device(adapter
, info
, addr_list
, NULL
);
91 if (IS_ERR(client
) && alt_addr
) {
92 struct i2c_board_info dummy_info
= {
93 I2C_BOARD_INFO("dummy", info
->addr
),
95 const unsigned short alt_addr_list
[] = {
96 alt_addr
, I2C_CLIENT_END
98 struct i2c_client
*dummy
;
100 dummy
= i2c_new_scanned_device(adapter
, &dummy_info
,
101 alt_addr_list
, NULL
);
102 if (!IS_ERR(dummy
)) {
103 pr_debug("%d-%02x is probed at %02x\n",
104 adapter
->nr
, info
->addr
, dummy
->addr
);
105 i2c_unregister_device(dummy
);
106 client
= i2c_new_client_device(adapter
, info
);
110 if (IS_ERR(client
)) {
112 pr_debug("failed to register device %d-%02x\n",
113 adapter
->nr
, info
->addr
);
115 pr_debug("added i2c device %d-%02x\n",
116 adapter
->nr
, info
->addr
);
122 static bool chromeos_laptop_match_adapter_devid(struct device
*dev
, u32 devid
)
124 struct pci_dev
*pdev
;
126 if (!dev_is_pci(dev
))
129 pdev
= to_pci_dev(dev
);
130 return devid
== pci_dev_id(pdev
);
133 static void chromeos_laptop_check_adapter(struct i2c_adapter
*adapter
)
135 struct i2c_peripheral
*i2c_dev
;
138 for (i
= 0; i
< cros_laptop
->num_i2c_peripherals
; i
++) {
139 i2c_dev
= &cros_laptop
->i2c_peripherals
[i
];
141 /* Skip devices already created */
145 if (strncmp(adapter
->name
, i2c_adapter_names
[i2c_dev
->type
],
146 strlen(i2c_adapter_names
[i2c_dev
->type
])))
149 if (i2c_dev
->pci_devid
&&
150 !chromeos_laptop_match_adapter_devid(adapter
->dev
.parent
,
151 i2c_dev
->pci_devid
)) {
156 chromes_laptop_instantiate_i2c_device(adapter
,
157 &i2c_dev
->board_info
,
162 static bool chromeos_laptop_adjust_client(struct i2c_client
*client
)
164 const struct acpi_peripheral
*acpi_dev
;
165 struct acpi_device_id acpi_ids
[2] = { };
169 if (!has_acpi_companion(&client
->dev
))
172 for (i
= 0; i
< cros_laptop
->num_acpi_peripherals
; i
++) {
173 acpi_dev
= &cros_laptop
->acpi_peripherals
[i
];
175 memcpy(acpi_ids
[0].id
, acpi_dev
->hid
, ACPI_ID_LEN
);
177 if (acpi_match_device(acpi_ids
, &client
->dev
)) {
178 error
= device_add_properties(&client
->dev
,
179 acpi_dev
->properties
);
181 dev_err(&client
->dev
,
182 "failed to add properties: %d\n",
194 static void chromeos_laptop_detach_i2c_client(struct i2c_client
*client
)
196 struct i2c_peripheral
*i2c_dev
;
199 for (i
= 0; i
< cros_laptop
->num_i2c_peripherals
; i
++) {
200 i2c_dev
= &cros_laptop
->i2c_peripherals
[i
];
202 if (i2c_dev
->client
== client
)
203 i2c_dev
->client
= NULL
;
207 static int chromeos_laptop_i2c_notifier_call(struct notifier_block
*nb
,
208 unsigned long action
, void *data
)
210 struct device
*dev
= data
;
213 case BUS_NOTIFY_ADD_DEVICE
:
214 if (dev
->type
== &i2c_adapter_type
)
215 chromeos_laptop_check_adapter(to_i2c_adapter(dev
));
216 else if (dev
->type
== &i2c_client_type
)
217 chromeos_laptop_adjust_client(to_i2c_client(dev
));
220 case BUS_NOTIFY_REMOVED_DEVICE
:
221 if (dev
->type
== &i2c_client_type
)
222 chromeos_laptop_detach_i2c_client(to_i2c_client(dev
));
229 static struct notifier_block chromeos_laptop_i2c_notifier
= {
230 .notifier_call
= chromeos_laptop_i2c_notifier_call
,
233 #define DECLARE_CROS_LAPTOP(_name) \
234 static const struct chromeos_laptop _name __initconst = { \
235 .i2c_peripherals = _name##_peripherals, \
236 .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \
239 #define DECLARE_ACPI_CROS_LAPTOP(_name) \
240 static const struct chromeos_laptop _name __initconst = { \
241 .acpi_peripherals = _name##_peripherals, \
242 .num_acpi_peripherals = ARRAY_SIZE(_name##_peripherals), \
245 static struct i2c_peripheral samsung_series_5_550_peripherals
[] __initdata
= {
249 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR
),
250 .flags
= I2C_CLIENT_WAKE
,
252 .dmi_name
= "trackpad",
253 .type
= I2C_ADAPTER_SMBUS
,
258 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR
),
260 .dmi_name
= "lightsensor",
261 .type
= I2C_ADAPTER_SMBUS
,
264 DECLARE_CROS_LAPTOP(samsung_series_5_550
);
266 static struct i2c_peripheral samsung_series_5_peripherals
[] __initdata
= {
270 I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR
),
272 .type
= I2C_ADAPTER_SMBUS
,
275 DECLARE_CROS_LAPTOP(samsung_series_5
);
277 static const int chromebook_pixel_tp_keys
[] __initconst
= {
286 static const struct property_entry
287 chromebook_pixel_trackpad_props
[] __initconst
= {
288 PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
289 PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys
),
293 static const struct property_entry
294 chromebook_atmel_touchscreen_props
[] __initconst
= {
295 PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
299 static struct i2c_peripheral chromebook_pixel_peripherals
[] __initdata
= {
303 I2C_BOARD_INFO("atmel_mxt_ts",
306 chromebook_atmel_touchscreen_props
,
307 .flags
= I2C_CLIENT_WAKE
,
309 .dmi_name
= "touchscreen",
310 .irqflags
= IRQF_TRIGGER_FALLING
,
311 .type
= I2C_ADAPTER_PANEL
,
312 .alt_addr
= ATMEL_TS_I2C_BL_ADDR
,
317 I2C_BOARD_INFO("atmel_mxt_tp",
320 chromebook_pixel_trackpad_props
,
321 .flags
= I2C_CLIENT_WAKE
,
323 .dmi_name
= "trackpad",
324 .irqflags
= IRQF_TRIGGER_FALLING
,
325 .type
= I2C_ADAPTER_VGADDC
,
326 .alt_addr
= ATMEL_TP_I2C_BL_ADDR
,
331 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR
),
333 .dmi_name
= "lightsensor",
334 .type
= I2C_ADAPTER_PANEL
,
337 DECLARE_CROS_LAPTOP(chromebook_pixel
);
339 static struct i2c_peripheral hp_chromebook_14_peripherals
[] __initdata
= {
343 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR
),
344 .flags
= I2C_CLIENT_WAKE
,
346 .dmi_name
= "trackpad",
347 .type
= I2C_ADAPTER_DESIGNWARE
,
350 DECLARE_CROS_LAPTOP(hp_chromebook_14
);
352 static struct i2c_peripheral dell_chromebook_11_peripherals
[] __initdata
= {
356 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR
),
357 .flags
= I2C_CLIENT_WAKE
,
359 .dmi_name
= "trackpad",
360 .type
= I2C_ADAPTER_DESIGNWARE
,
362 /* Elan Touchpad option. */
365 I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR
),
366 .flags
= I2C_CLIENT_WAKE
,
368 .dmi_name
= "trackpad",
369 .type
= I2C_ADAPTER_DESIGNWARE
,
372 DECLARE_CROS_LAPTOP(dell_chromebook_11
);
374 static struct i2c_peripheral toshiba_cb35_peripherals
[] __initdata
= {
378 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR
),
379 .flags
= I2C_CLIENT_WAKE
,
381 .dmi_name
= "trackpad",
382 .type
= I2C_ADAPTER_DESIGNWARE
,
385 DECLARE_CROS_LAPTOP(toshiba_cb35
);
387 static struct i2c_peripheral acer_c7_chromebook_peripherals
[] __initdata
= {
391 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR
),
392 .flags
= I2C_CLIENT_WAKE
,
394 .dmi_name
= "trackpad",
395 .type
= I2C_ADAPTER_SMBUS
,
398 DECLARE_CROS_LAPTOP(acer_c7_chromebook
);
400 static struct i2c_peripheral acer_ac700_peripherals
[] __initdata
= {
404 I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR
),
406 .type
= I2C_ADAPTER_SMBUS
,
409 DECLARE_CROS_LAPTOP(acer_ac700
);
411 static struct i2c_peripheral acer_c720_peripherals
[] __initdata
= {
415 I2C_BOARD_INFO("atmel_mxt_ts",
418 chromebook_atmel_touchscreen_props
,
419 .flags
= I2C_CLIENT_WAKE
,
421 .dmi_name
= "touchscreen",
422 .irqflags
= IRQF_TRIGGER_FALLING
,
423 .type
= I2C_ADAPTER_DESIGNWARE
,
424 .pci_devid
= PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
425 .alt_addr
= ATMEL_TS_I2C_BL_ADDR
,
430 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR
),
431 .flags
= I2C_CLIENT_WAKE
,
433 .dmi_name
= "trackpad",
434 .type
= I2C_ADAPTER_DESIGNWARE
,
435 .pci_devid
= PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
437 /* Elan Touchpad option. */
440 I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR
),
441 .flags
= I2C_CLIENT_WAKE
,
443 .dmi_name
= "trackpad",
444 .type
= I2C_ADAPTER_DESIGNWARE
,
445 .pci_devid
= PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
450 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR
),
452 .dmi_name
= "lightsensor",
453 .type
= I2C_ADAPTER_DESIGNWARE
,
454 .pci_devid
= PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
457 DECLARE_CROS_LAPTOP(acer_c720
);
459 static struct i2c_peripheral
460 hp_pavilion_14_chromebook_peripherals
[] __initdata
= {
464 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR
),
465 .flags
= I2C_CLIENT_WAKE
,
467 .dmi_name
= "trackpad",
468 .type
= I2C_ADAPTER_SMBUS
,
471 DECLARE_CROS_LAPTOP(hp_pavilion_14_chromebook
);
473 static struct i2c_peripheral cr48_peripherals
[] __initdata
= {
477 I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR
),
479 .type
= I2C_ADAPTER_SMBUS
,
482 DECLARE_CROS_LAPTOP(cr48
);
484 static const u32 samus_touchpad_buttons
[] __initconst
= {
491 static const struct property_entry samus_trackpad_props
[] __initconst
= {
492 PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
493 PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons
),
497 static struct acpi_peripheral samus_peripherals
[] __initdata
= {
501 .properties
= samus_trackpad_props
,
506 .properties
= chromebook_atmel_touchscreen_props
,
509 DECLARE_ACPI_CROS_LAPTOP(samus
);
511 static struct acpi_peripheral generic_atmel_peripherals
[] __initdata
= {
515 .properties
= chromebook_pixel_trackpad_props
,
520 .properties
= chromebook_atmel_touchscreen_props
,
523 DECLARE_ACPI_CROS_LAPTOP(generic_atmel
);
525 static const struct dmi_system_id chromeos_laptop_dmi_table
[] __initconst
= {
527 .ident
= "Samsung Series 5 550",
529 DMI_MATCH(DMI_SYS_VENDOR
, "SAMSUNG"),
530 DMI_MATCH(DMI_PRODUCT_NAME
, "Lumpy"),
532 .driver_data
= (void *)&samsung_series_5_550
,
535 .ident
= "Samsung Series 5",
537 DMI_MATCH(DMI_PRODUCT_NAME
, "Alex"),
539 .driver_data
= (void *)&samsung_series_5
,
542 .ident
= "Chromebook Pixel",
544 DMI_MATCH(DMI_SYS_VENDOR
, "GOOGLE"),
545 DMI_MATCH(DMI_PRODUCT_NAME
, "Link"),
547 .driver_data
= (void *)&chromebook_pixel
,
552 DMI_MATCH(DMI_BIOS_VENDOR
, "coreboot"),
553 DMI_MATCH(DMI_PRODUCT_NAME
, "Wolf"),
555 .driver_data
= (void *)&dell_chromebook_11
,
558 .ident
= "HP Chromebook 14",
560 DMI_MATCH(DMI_BIOS_VENDOR
, "coreboot"),
561 DMI_MATCH(DMI_PRODUCT_NAME
, "Falco"),
563 .driver_data
= (void *)&hp_chromebook_14
,
566 .ident
= "Toshiba CB35",
568 DMI_MATCH(DMI_BIOS_VENDOR
, "coreboot"),
569 DMI_MATCH(DMI_PRODUCT_NAME
, "Leon"),
571 .driver_data
= (void *)&toshiba_cb35
,
574 .ident
= "Acer C7 Chromebook",
576 DMI_MATCH(DMI_PRODUCT_NAME
, "Parrot"),
578 .driver_data
= (void *)&acer_c7_chromebook
,
581 .ident
= "Acer AC700",
583 DMI_MATCH(DMI_PRODUCT_NAME
, "ZGB"),
585 .driver_data
= (void *)&acer_ac700
,
588 .ident
= "Acer C720",
590 DMI_MATCH(DMI_PRODUCT_NAME
, "Peppy"),
592 .driver_data
= (void *)&acer_c720
,
595 .ident
= "HP Pavilion 14 Chromebook",
597 DMI_MATCH(DMI_PRODUCT_NAME
, "Butterfly"),
599 .driver_data
= (void *)&hp_pavilion_14_chromebook
,
604 DMI_MATCH(DMI_PRODUCT_NAME
, "Mario"),
606 .driver_data
= (void *)&cr48
,
608 /* Devices with peripherals incompletely described in ACPI */
610 .ident
= "Chromebook Pro",
612 DMI_MATCH(DMI_SYS_VENDOR
, "Google"),
613 DMI_MATCH(DMI_PRODUCT_NAME
, "Caroline"),
615 .driver_data
= (void *)&samus
,
618 .ident
= "Google Pixel 2 (2015)",
620 DMI_MATCH(DMI_SYS_VENDOR
, "GOOGLE"),
621 DMI_MATCH(DMI_PRODUCT_NAME
, "Samus"),
623 .driver_data
= (void *)&samus
,
626 .ident
= "Samsung Chromebook 3",
628 DMI_MATCH(DMI_SYS_VENDOR
, "GOOGLE"),
629 DMI_MATCH(DMI_PRODUCT_NAME
, "Celes"),
631 .driver_data
= (void *)&samus
,
635 * Other Chromebooks with Atmel touch controllers:
637 * - Clapper, Expresso, Rambi, Glimmer (touchscreen)
639 .ident
= "Other Chromebook",
642 * This will match all Google devices, not only devices
643 * with Atmel, but we will validate that the device
644 * actually has matching peripherals.
646 DMI_MATCH(DMI_SYS_VENDOR
, "GOOGLE"),
648 .driver_data
= (void *)&generic_atmel
,
652 MODULE_DEVICE_TABLE(dmi
, chromeos_laptop_dmi_table
);
654 static int __init
chromeos_laptop_scan_peripherals(struct device
*dev
, void *data
)
658 if (dev
->type
== &i2c_adapter_type
) {
659 chromeos_laptop_check_adapter(to_i2c_adapter(dev
));
660 } else if (dev
->type
== &i2c_client_type
) {
661 if (chromeos_laptop_adjust_client(to_i2c_client(dev
))) {
663 * Now that we have needed properties re-trigger
664 * driver probe in case driver was initialized
665 * earlier and probe failed.
667 error
= device_attach(dev
);
670 "%s: device_attach() failed: %d\n",
678 static int __init
chromeos_laptop_get_irq_from_dmi(const char *dmi_name
)
680 const struct dmi_device
*dmi_dev
;
681 const struct dmi_dev_onboard
*dev_data
;
683 dmi_dev
= dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD
, dmi_name
, NULL
);
685 pr_err("failed to find DMI device '%s'\n", dmi_name
);
689 dev_data
= dmi_dev
->device_data
;
691 pr_err("failed to get data from DMI for '%s'\n", dmi_name
);
695 return dev_data
->instance
;
698 static int __init
chromeos_laptop_setup_irq(struct i2c_peripheral
*i2c_dev
)
702 if (i2c_dev
->dmi_name
) {
703 irq
= chromeos_laptop_get_irq_from_dmi(i2c_dev
->dmi_name
);
707 i2c_dev
->irq_resource
= (struct resource
)
708 DEFINE_RES_NAMED(irq
, 1, NULL
,
709 IORESOURCE_IRQ
| i2c_dev
->irqflags
);
710 i2c_dev
->board_info
.resources
= &i2c_dev
->irq_resource
;
711 i2c_dev
->board_info
.num_resources
= 1;
718 chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop
*cros_laptop
,
719 const struct chromeos_laptop
*src
)
721 struct i2c_peripheral
*i2c_dev
;
722 struct i2c_board_info
*info
;
726 if (!src
->num_i2c_peripherals
)
729 cros_laptop
->i2c_peripherals
= kmemdup(src
->i2c_peripherals
,
730 src
->num_i2c_peripherals
*
731 sizeof(*src
->i2c_peripherals
),
733 if (!cros_laptop
->i2c_peripherals
)
736 cros_laptop
->num_i2c_peripherals
= src
->num_i2c_peripherals
;
738 for (i
= 0; i
< cros_laptop
->num_i2c_peripherals
; i
++) {
739 i2c_dev
= &cros_laptop
->i2c_peripherals
[i
];
740 info
= &i2c_dev
->board_info
;
742 error
= chromeos_laptop_setup_irq(i2c_dev
);
746 /* We need to deep-copy properties */
747 if (info
->properties
) {
749 property_entries_dup(info
->properties
);
750 if (IS_ERR(info
->properties
)) {
751 error
= PTR_ERR(info
->properties
);
761 i2c_dev
= &cros_laptop
->i2c_peripherals
[i
];
762 info
= &i2c_dev
->board_info
;
763 if (info
->properties
)
764 property_entries_free(info
->properties
);
766 kfree(cros_laptop
->i2c_peripherals
);
771 chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop
*cros_laptop
,
772 const struct chromeos_laptop
*src
)
774 struct acpi_peripheral
*acpi_peripherals
;
775 struct acpi_peripheral
*acpi_dev
;
776 const struct acpi_peripheral
*src_dev
;
777 int n_peripherals
= 0;
781 for (i
= 0; i
< src
->num_acpi_peripherals
; i
++) {
782 if (acpi_dev_present(src
->acpi_peripherals
[i
].hid
, NULL
, -1))
789 acpi_peripherals
= kcalloc(n_peripherals
,
790 sizeof(*src
->acpi_peripherals
),
792 if (!acpi_peripherals
)
795 acpi_dev
= acpi_peripherals
;
796 for (i
= 0; i
< src
->num_acpi_peripherals
; i
++) {
797 src_dev
= &src
->acpi_peripherals
[i
];
798 if (!acpi_dev_present(src_dev
->hid
, NULL
, -1))
801 *acpi_dev
= *src_dev
;
803 /* We need to deep-copy properties */
804 if (src_dev
->properties
) {
805 acpi_dev
->properties
=
806 property_entries_dup(src_dev
->properties
);
807 if (IS_ERR(acpi_dev
->properties
)) {
808 error
= PTR_ERR(acpi_dev
->properties
);
816 cros_laptop
->acpi_peripherals
= acpi_peripherals
;
817 cros_laptop
->num_acpi_peripherals
= n_peripherals
;
823 acpi_dev
= &acpi_peripherals
[i
];
824 if (acpi_dev
->properties
)
825 property_entries_free(acpi_dev
->properties
);
828 kfree(acpi_peripherals
);
832 static void chromeos_laptop_destroy(const struct chromeos_laptop
*cros_laptop
)
834 const struct acpi_peripheral
*acpi_dev
;
835 struct i2c_peripheral
*i2c_dev
;
836 struct i2c_board_info
*info
;
839 for (i
= 0; i
< cros_laptop
->num_i2c_peripherals
; i
++) {
840 i2c_dev
= &cros_laptop
->i2c_peripherals
[i
];
841 info
= &i2c_dev
->board_info
;
843 i2c_unregister_device(i2c_dev
->client
);
844 property_entries_free(info
->properties
);
847 for (i
= 0; i
< cros_laptop
->num_acpi_peripherals
; i
++) {
848 acpi_dev
= &cros_laptop
->acpi_peripherals
[i
];
850 property_entries_free(acpi_dev
->properties
);
853 kfree(cros_laptop
->i2c_peripherals
);
854 kfree(cros_laptop
->acpi_peripherals
);
858 static struct chromeos_laptop
* __init
859 chromeos_laptop_prepare(const struct chromeos_laptop
*src
)
861 struct chromeos_laptop
*cros_laptop
;
864 cros_laptop
= kzalloc(sizeof(*cros_laptop
), GFP_KERNEL
);
866 return ERR_PTR(-ENOMEM
);
868 error
= chromeos_laptop_prepare_i2c_peripherals(cros_laptop
, src
);
870 error
= chromeos_laptop_prepare_acpi_peripherals(cros_laptop
,
874 chromeos_laptop_destroy(cros_laptop
);
875 return ERR_PTR(error
);
881 static int __init
chromeos_laptop_init(void)
883 const struct dmi_system_id
*dmi_id
;
886 dmi_id
= dmi_first_match(chromeos_laptop_dmi_table
);
888 pr_debug("unsupported system\n");
892 pr_debug("DMI Matched %s\n", dmi_id
->ident
);
894 cros_laptop
= chromeos_laptop_prepare((void *)dmi_id
->driver_data
);
895 if (IS_ERR(cros_laptop
))
896 return PTR_ERR(cros_laptop
);
898 if (!cros_laptop
->num_i2c_peripherals
&&
899 !cros_laptop
->num_acpi_peripherals
) {
900 pr_debug("no relevant devices detected\n");
902 goto err_destroy_cros_laptop
;
905 error
= bus_register_notifier(&i2c_bus_type
,
906 &chromeos_laptop_i2c_notifier
);
908 pr_err("failed to register i2c bus notifier: %d\n",
910 goto err_destroy_cros_laptop
;
914 * Scan adapters that have been registered and clients that have
915 * been created before we installed the notifier to make sure
916 * we do not miss any devices.
918 i2c_for_each_dev(NULL
, chromeos_laptop_scan_peripherals
);
922 err_destroy_cros_laptop
:
923 chromeos_laptop_destroy(cros_laptop
);
927 static void __exit
chromeos_laptop_exit(void)
929 bus_unregister_notifier(&i2c_bus_type
, &chromeos_laptop_i2c_notifier
);
930 chromeos_laptop_destroy(cros_laptop
);
933 module_init(chromeos_laptop_init
);
934 module_exit(chromeos_laptop_exit
);
936 MODULE_DESCRIPTION("Chrome OS Laptop driver");
937 MODULE_AUTHOR("Benson Leung <bleung@chromium.org>");
938 MODULE_LICENSE("GPL");