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/dmi.h>
10 #include <linux/i2c.h>
11 #include <linux/input.h>
12 #include <linux/interrupt.h>
13 #include <linux/ioport.h>
14 #include <linux/module.h>
15 #include <linux/pci.h>
16 #include <linux/platform_device.h>
17 #include <linux/property.h>
18 
19 #define ATMEL_TP_I2C_ADDR	0x4b
20 #define ATMEL_TP_I2C_BL_ADDR	0x25
21 #define ATMEL_TS_I2C_ADDR	0x4a
22 #define ATMEL_TS_I2C_BL_ADDR	0x26
23 #define CYAPA_TP_I2C_ADDR	0x67
24 #define ELAN_TP_I2C_ADDR	0x15
25 #define ISL_ALS_I2C_ADDR	0x44
26 #define TAOS_ALS_I2C_ADDR	0x29
27 
28 static const char *i2c_adapter_names[] = {
29 	"SMBus I801 adapter",
30 	"i915 gmbus vga",
31 	"i915 gmbus panel",
32 	"Synopsys DesignWare I2C adapter",
33 };
34 
35 /* Keep this enum consistent with i2c_adapter_names */
36 enum i2c_adapter_type {
37 	I2C_ADAPTER_SMBUS = 0,
38 	I2C_ADAPTER_VGADDC,
39 	I2C_ADAPTER_PANEL,
40 	I2C_ADAPTER_DESIGNWARE,
41 };
42 
43 struct i2c_peripheral {
44 	struct i2c_board_info board_info;
45 	unsigned short alt_addr;
46 
47 	const char *dmi_name;
48 	unsigned long irqflags;
49 	struct resource irq_resource;
50 
51 	enum i2c_adapter_type type;
52 	u32 pci_devid;
53 
54 	struct i2c_client *client;
55 };
56 
57 struct chromeos_laptop {
58 	/*
59 	 * Note that we can't mark this pointer as const because
60 	 * i2c_new_probed_device() changes passed in I2C board info, so.
61 	 */
62 	struct i2c_peripheral *i2c_peripherals;
63 	unsigned int num_i2c_peripherals;
64 };
65 
66 static const struct chromeos_laptop *cros_laptop;
67 
68 static struct i2c_client *
69 chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter,
70 				      struct i2c_board_info *info,
71 				      unsigned short alt_addr)
72 {
73 	const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
74 	struct i2c_client *client;
75 
76 	/*
77 	 * Add the i2c device. If we can't detect it at the primary
78 	 * address we scan secondary addresses. In any case the client
79 	 * structure gets assigned primary address.
80 	 */
81 	client = i2c_new_probed_device(adapter, info, addr_list, NULL);
82 	if (!client && alt_addr) {
83 		struct i2c_board_info dummy_info = {
84 			I2C_BOARD_INFO("dummy", info->addr),
85 		};
86 		const unsigned short alt_addr_list[] = {
87 			alt_addr, I2C_CLIENT_END
88 		};
89 		struct i2c_client *dummy;
90 
91 		dummy = i2c_new_probed_device(adapter, &dummy_info,
92 					      alt_addr_list, NULL);
93 		if (dummy) {
94 			pr_debug("%d-%02x is probed at %02x\n",
95 				 adapter->nr, info->addr, dummy->addr);
96 			i2c_unregister_device(dummy);
97 			client = i2c_new_device(adapter, info);
98 		}
99 	}
100 
101 	if (!client)
102 		pr_debug("failed to register device %d-%02x\n",
103 			 adapter->nr, info->addr);
104 	else
105 		pr_debug("added i2c device %d-%02x\n",
106 			 adapter->nr, info->addr);
107 
108 	return client;
109 }
110 
111 static bool chromeos_laptop_match_adapter_devid(struct device *dev, u32 devid)
112 {
113 	struct pci_dev *pdev;
114 
115 	if (!dev_is_pci(dev))
116 		return false;
117 
118 	pdev = to_pci_dev(dev);
119 	return devid == PCI_DEVID(pdev->bus->number, pdev->devfn);
120 }
121 
122 static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
123 {
124 	struct i2c_peripheral *i2c_dev;
125 	int i;
126 
127 	for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
128 		i2c_dev = &cros_laptop->i2c_peripherals[i];
129 
130 		/* Skip devices already created */
131 		if (i2c_dev->client)
132 			continue;
133 
134 		if (strncmp(adapter->name, i2c_adapter_names[i2c_dev->type],
135 			    strlen(i2c_adapter_names[i2c_dev->type])))
136 			continue;
137 
138 		if (i2c_dev->pci_devid &&
139 		    !chromeos_laptop_match_adapter_devid(adapter->dev.parent,
140 							 i2c_dev->pci_devid)) {
141 			continue;
142 		}
143 
144 		i2c_dev->client =
145 			chromes_laptop_instantiate_i2c_device(adapter,
146 							&i2c_dev->board_info,
147 							i2c_dev->alt_addr);
148 	}
149 }
150 
151 static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
152 {
153 	struct i2c_peripheral *i2c_dev;
154 	int i;
155 
156 	for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
157 		i2c_dev = &cros_laptop->i2c_peripherals[i];
158 
159 		if (i2c_dev->client == client)
160 			i2c_dev->client = NULL;
161 	}
162 }
163 
164 static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb,
165 					     unsigned long action, void *data)
166 {
167 	struct device *dev = data;
168 
169 	switch (action) {
170 	case BUS_NOTIFY_ADD_DEVICE:
171 		if (dev->type == &i2c_adapter_type)
172 			chromeos_laptop_check_adapter(to_i2c_adapter(dev));
173 		break;
174 
175 	case BUS_NOTIFY_REMOVED_DEVICE:
176 		if (dev->type == &i2c_client_type)
177 			chromeos_laptop_detach_i2c_client(to_i2c_client(dev));
178 		break;
179 	}
180 
181 	return 0;
182 }
183 
184 static struct notifier_block chromeos_laptop_i2c_notifier = {
185 	.notifier_call = chromeos_laptop_i2c_notifier_call,
186 };
187 
188 #define DECLARE_CROS_LAPTOP(_name)					\
189 static const struct chromeos_laptop _name __initconst = {		\
190 	.i2c_peripherals	= _name##_peripherals,			\
191 	.num_i2c_peripherals	= ARRAY_SIZE(_name##_peripherals),	\
192 }
193 
194 static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = {
195 	/* Touchpad. */
196 	{
197 		.board_info	= {
198 			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
199 			.flags		= I2C_CLIENT_WAKE,
200 		},
201 		.dmi_name	= "trackpad",
202 		.type		= I2C_ADAPTER_SMBUS,
203 	},
204 	/* Light Sensor. */
205 	{
206 		.board_info	= {
207 			I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
208 		},
209 		.dmi_name	= "lightsensor",
210 		.type		= I2C_ADAPTER_SMBUS,
211 	},
212 };
213 DECLARE_CROS_LAPTOP(samsung_series_5_550);
214 
215 static struct i2c_peripheral samsung_series_5_peripherals[] __initdata = {
216 	/* Light Sensor. */
217 	{
218 		.board_info	= {
219 			I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
220 		},
221 		.type		= I2C_ADAPTER_SMBUS,
222 	},
223 };
224 DECLARE_CROS_LAPTOP(samsung_series_5);
225 
226 static const int chromebook_pixel_tp_keys[] __initconst = {
227 	KEY_RESERVED,
228 	KEY_RESERVED,
229 	KEY_RESERVED,
230 	KEY_RESERVED,
231 	KEY_RESERVED,
232 	BTN_LEFT
233 };
234 
235 static const struct property_entry
236 chromebook_pixel_trackpad_props[] __initconst = {
237 	PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys),
238 	{ }
239 };
240 
241 static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = {
242 	/* Touch Screen. */
243 	{
244 		.board_info	= {
245 			I2C_BOARD_INFO("atmel_mxt_ts",
246 					ATMEL_TS_I2C_ADDR),
247 			.flags		= I2C_CLIENT_WAKE,
248 		},
249 		.dmi_name	= "touchscreen",
250 		.irqflags	= IRQF_TRIGGER_FALLING,
251 		.type		= I2C_ADAPTER_PANEL,
252 		.alt_addr	= ATMEL_TS_I2C_BL_ADDR,
253 	},
254 	/* Touchpad. */
255 	{
256 		.board_info	= {
257 			I2C_BOARD_INFO("atmel_mxt_tp",
258 					ATMEL_TP_I2C_ADDR),
259 			.properties	=
260 				chromebook_pixel_trackpad_props,
261 			.flags		= I2C_CLIENT_WAKE,
262 		},
263 		.dmi_name	= "trackpad",
264 		.irqflags	= IRQF_TRIGGER_FALLING,
265 		.type		= I2C_ADAPTER_VGADDC,
266 		.alt_addr	= ATMEL_TP_I2C_BL_ADDR,
267 	},
268 	/* Light Sensor. */
269 	{
270 		.board_info	= {
271 			I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
272 		},
273 		.dmi_name	= "lightsensor",
274 		.type		= I2C_ADAPTER_PANEL,
275 	},
276 };
277 DECLARE_CROS_LAPTOP(chromebook_pixel);
278 
279 static struct i2c_peripheral hp_chromebook_14_peripherals[] __initdata = {
280 	/* Touchpad. */
281 	{
282 		.board_info	= {
283 			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
284 			.flags		= I2C_CLIENT_WAKE,
285 		},
286 		.dmi_name	= "trackpad",
287 		.type		= I2C_ADAPTER_DESIGNWARE,
288 	},
289 };
290 DECLARE_CROS_LAPTOP(hp_chromebook_14);
291 
292 static struct i2c_peripheral dell_chromebook_11_peripherals[] __initdata = {
293 	/* Touchpad. */
294 	{
295 		.board_info	= {
296 			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
297 			.flags		= I2C_CLIENT_WAKE,
298 		},
299 		.dmi_name	= "trackpad",
300 		.type		= I2C_ADAPTER_DESIGNWARE,
301 	},
302 	/* Elan Touchpad option. */
303 	{
304 		.board_info	= {
305 			I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
306 			.flags		= I2C_CLIENT_WAKE,
307 		},
308 		.dmi_name	= "trackpad",
309 		.type		= I2C_ADAPTER_DESIGNWARE,
310 	},
311 };
312 DECLARE_CROS_LAPTOP(dell_chromebook_11);
313 
314 static struct i2c_peripheral toshiba_cb35_peripherals[] __initdata = {
315 	/* Touchpad. */
316 	{
317 		.board_info	= {
318 			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
319 			.flags		= I2C_CLIENT_WAKE,
320 		},
321 		.dmi_name	= "trackpad",
322 		.type		= I2C_ADAPTER_DESIGNWARE,
323 	},
324 };
325 DECLARE_CROS_LAPTOP(toshiba_cb35);
326 
327 static struct i2c_peripheral acer_c7_chromebook_peripherals[] __initdata = {
328 	/* Touchpad. */
329 	{
330 		.board_info	= {
331 			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
332 			.flags		= I2C_CLIENT_WAKE,
333 		},
334 		.dmi_name	= "trackpad",
335 		.type		= I2C_ADAPTER_SMBUS,
336 	},
337 };
338 DECLARE_CROS_LAPTOP(acer_c7_chromebook);
339 
340 static struct i2c_peripheral acer_ac700_peripherals[] __initdata = {
341 	/* Light Sensor. */
342 	{
343 		.board_info	= {
344 			I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
345 		},
346 		.type		= I2C_ADAPTER_SMBUS,
347 	},
348 };
349 DECLARE_CROS_LAPTOP(acer_ac700);
350 
351 static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
352 	/* Touchscreen. */
353 	{
354 		.board_info	= {
355 			I2C_BOARD_INFO("atmel_mxt_ts",
356 					ATMEL_TS_I2C_ADDR),
357 			.flags		= I2C_CLIENT_WAKE,
358 		},
359 		.dmi_name	= "touchscreen",
360 		.irqflags	= IRQF_TRIGGER_FALLING,
361 		.type		= I2C_ADAPTER_DESIGNWARE,
362 		.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
363 		.alt_addr	= ATMEL_TS_I2C_BL_ADDR,
364 	},
365 	/* Touchpad. */
366 	{
367 		.board_info	= {
368 			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
369 			.flags		= I2C_CLIENT_WAKE,
370 		},
371 		.dmi_name	= "trackpad",
372 		.type		= I2C_ADAPTER_DESIGNWARE,
373 		.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
374 	},
375 	/* Elan Touchpad option. */
376 	{
377 		.board_info	= {
378 			I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
379 			.flags		= I2C_CLIENT_WAKE,
380 		},
381 		.dmi_name	= "trackpad",
382 		.type		= I2C_ADAPTER_DESIGNWARE,
383 		.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
384 	},
385 	/* Light Sensor. */
386 	{
387 		.board_info	= {
388 			I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
389 		},
390 		.dmi_name	= "lightsensor",
391 		.type		= I2C_ADAPTER_DESIGNWARE,
392 		.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
393 	},
394 };
395 DECLARE_CROS_LAPTOP(acer_c720);
396 
397 static struct i2c_peripheral
398 hp_pavilion_14_chromebook_peripherals[] __initdata = {
399 	/* Touchpad. */
400 	{
401 		.board_info	= {
402 			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
403 			.flags		= I2C_CLIENT_WAKE,
404 		},
405 		.dmi_name	= "trackpad",
406 		.type		= I2C_ADAPTER_SMBUS,
407 	},
408 };
409 DECLARE_CROS_LAPTOP(hp_pavilion_14_chromebook);
410 
411 static struct i2c_peripheral cr48_peripherals[] __initdata = {
412 	/* Light Sensor. */
413 	{
414 		.board_info	= {
415 			I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
416 		},
417 		.type		= I2C_ADAPTER_SMBUS,
418 	},
419 };
420 DECLARE_CROS_LAPTOP(cr48);
421 
422 static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
423 	{
424 		.ident = "Samsung Series 5 550",
425 		.matches = {
426 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
427 			DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
428 		},
429 		.driver_data = (void *)&samsung_series_5_550,
430 	},
431 	{
432 		.ident = "Samsung Series 5",
433 		.matches = {
434 			DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
435 		},
436 		.driver_data = (void *)&samsung_series_5,
437 	},
438 	{
439 		.ident = "Chromebook Pixel",
440 		.matches = {
441 			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
442 			DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
443 		},
444 		.driver_data = (void *)&chromebook_pixel,
445 	},
446 	{
447 		.ident = "Wolf",
448 		.matches = {
449 			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
450 			DMI_MATCH(DMI_PRODUCT_NAME, "Wolf"),
451 		},
452 		.driver_data = (void *)&dell_chromebook_11,
453 	},
454 	{
455 		.ident = "HP Chromebook 14",
456 		.matches = {
457 			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
458 			DMI_MATCH(DMI_PRODUCT_NAME, "Falco"),
459 		},
460 		.driver_data = (void *)&hp_chromebook_14,
461 	},
462 	{
463 		.ident = "Toshiba CB35",
464 		.matches = {
465 			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
466 			DMI_MATCH(DMI_PRODUCT_NAME, "Leon"),
467 		},
468 		.driver_data = (void *)&toshiba_cb35,
469 	},
470 	{
471 		.ident = "Acer C7 Chromebook",
472 		.matches = {
473 			DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
474 		},
475 		.driver_data = (void *)&acer_c7_chromebook,
476 	},
477 	{
478 		.ident = "Acer AC700",
479 		.matches = {
480 			DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
481 		},
482 		.driver_data = (void *)&acer_ac700,
483 	},
484 	{
485 		.ident = "Acer C720",
486 		.matches = {
487 			DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"),
488 		},
489 		.driver_data = (void *)&acer_c720,
490 	},
491 	{
492 		.ident = "HP Pavilion 14 Chromebook",
493 		.matches = {
494 			DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
495 		},
496 		.driver_data = (void *)&hp_pavilion_14_chromebook,
497 	},
498 	{
499 		.ident = "Cr-48",
500 		.matches = {
501 			DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
502 		},
503 		.driver_data = (void *)&cr48,
504 	},
505 	{ }
506 };
507 MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
508 
509 static int __init chromeos_laptop_scan_adapter(struct device *dev, void *data)
510 {
511 	struct i2c_adapter *adapter;
512 
513 	adapter = i2c_verify_adapter(dev);
514 	if (adapter)
515 		chromeos_laptop_check_adapter(adapter);
516 
517 	return 0;
518 }
519 
520 static int __init chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
521 {
522 	const struct dmi_device *dmi_dev;
523 	const struct dmi_dev_onboard *dev_data;
524 
525 	dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, dmi_name, NULL);
526 	if (!dmi_dev) {
527 		pr_err("failed to find DMI device '%s'\n", dmi_name);
528 		return -ENOENT;
529 	}
530 
531 	dev_data = dmi_dev->device_data;
532 	if (!dev_data) {
533 		pr_err("failed to get data from DMI for '%s'\n", dmi_name);
534 		return -EINVAL;
535 	}
536 
537 	return dev_data->instance;
538 }
539 
540 static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev)
541 {
542 	int irq;
543 
544 	if (i2c_dev->dmi_name) {
545 		irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name);
546 		if (irq < 0)
547 			return irq;
548 
549 		i2c_dev->irq_resource  = (struct resource)
550 			DEFINE_RES_NAMED(irq, 1, NULL,
551 					 IORESOURCE_IRQ | i2c_dev->irqflags);
552 		i2c_dev->board_info.resources = &i2c_dev->irq_resource;
553 		i2c_dev->board_info.num_resources = 1;
554 	}
555 
556 	return 0;
557 }
558 
559 static struct chromeos_laptop * __init
560 chromeos_laptop_prepare(const struct chromeos_laptop *src)
561 {
562 	struct chromeos_laptop *cros_laptop;
563 	struct i2c_peripheral *i2c_dev;
564 	struct i2c_board_info *info;
565 	int error;
566 	int i;
567 
568 	cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
569 	if (!cros_laptop)
570 		return ERR_PTR(-ENOMEM);
571 
572 	cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals,
573 					       src->num_i2c_peripherals *
574 						sizeof(*src->i2c_peripherals),
575 					       GFP_KERNEL);
576 	if (!cros_laptop->i2c_peripherals) {
577 		error = -ENOMEM;
578 		goto err_free_cros_laptop;
579 	}
580 
581 	cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals;
582 
583 	for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
584 		i2c_dev = &cros_laptop->i2c_peripherals[i];
585 		info = &i2c_dev->board_info;
586 
587 		error = chromeos_laptop_setup_irq(i2c_dev);
588 		if (error)
589 			goto err_destroy_cros_peripherals;
590 
591 		/* We need to deep-copy properties */
592 		if (info->properties) {
593 			info->properties =
594 				property_entries_dup(info->properties);
595 			if (IS_ERR(info->properties)) {
596 				error = PTR_ERR(info->properties);
597 				goto err_destroy_cros_peripherals;
598 			}
599 		}
600 	}
601 
602 	return cros_laptop;
603 
604 err_destroy_cros_peripherals:
605 	while (--i >= 0) {
606 		i2c_dev = &cros_laptop->i2c_peripherals[i];
607 		info = &i2c_dev->board_info;
608 		if (info->properties)
609 			property_entries_free(info->properties);
610 	}
611 	kfree(cros_laptop->i2c_peripherals);
612 err_free_cros_laptop:
613 	kfree(cros_laptop);
614 	return ERR_PTR(error);
615 }
616 
617 static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
618 {
619 	struct i2c_peripheral *i2c_dev;
620 	struct i2c_board_info *info;
621 	int i;
622 
623 	for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
624 		i2c_dev = &cros_laptop->i2c_peripherals[i];
625 		info = &i2c_dev->board_info;
626 
627 		if (i2c_dev->client)
628 			i2c_unregister_device(i2c_dev->client);
629 
630 		if (info->properties)
631 			property_entries_free(info->properties);
632 	}
633 
634 	kfree(cros_laptop->i2c_peripherals);
635 	kfree(cros_laptop);
636 }
637 
638 static int __init chromeos_laptop_init(void)
639 {
640 	const struct dmi_system_id *dmi_id;
641 	int error;
642 
643 	dmi_id = dmi_first_match(chromeos_laptop_dmi_table);
644 	if (!dmi_id) {
645 		pr_debug("unsupported system\n");
646 		return -ENODEV;
647 	}
648 
649 	pr_debug("DMI Matched %s\n", dmi_id->ident);
650 
651 	cros_laptop = chromeos_laptop_prepare((void *)dmi_id->driver_data);
652 	if (IS_ERR(cros_laptop))
653 		return PTR_ERR(cros_laptop);
654 
655 	error = bus_register_notifier(&i2c_bus_type,
656 				      &chromeos_laptop_i2c_notifier);
657 	if (error) {
658 		pr_err("failed to register i2c bus notifier: %d\n", error);
659 		chromeos_laptop_destroy(cros_laptop);
660 		return error;
661 	}
662 
663 	/*
664 	 * Scan adapters that have been registered before we installed
665 	 * the notifier to make sure we do not miss any devices.
666 	 */
667 	i2c_for_each_dev(NULL, chromeos_laptop_scan_adapter);
668 
669 	return 0;
670 }
671 
672 static void __exit chromeos_laptop_exit(void)
673 {
674 	bus_unregister_notifier(&i2c_bus_type, &chromeos_laptop_i2c_notifier);
675 	chromeos_laptop_destroy(cros_laptop);
676 }
677 
678 module_init(chromeos_laptop_init);
679 module_exit(chromeos_laptop_exit);
680 
681 MODULE_DESCRIPTION("Chrome OS Laptop driver");
682 MODULE_AUTHOR("Benson Leung <bleung@chromium.org>");
683 MODULE_LICENSE("GPL");
684