1 /*
2  *  chromeos_laptop.c - Driver to instantiate Chromebook i2c/smbus devices.
3  *
4  *  Author : Benson Leung <bleung@chromium.org>
5  *
6  *  Copyright (C) 2012 Google, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 
24 #include <linux/dmi.h>
25 #include <linux/i2c.h>
26 #include <linux/i2c/atmel_mxt_ts.h>
27 #include <linux/input.h>
28 #include <linux/interrupt.h>
29 #include <linux/module.h>
30 #include <linux/platform_device.h>
31 
32 #define ATMEL_TP_I2C_ADDR	0x4b
33 #define ATMEL_TP_I2C_BL_ADDR	0x25
34 #define ATMEL_TS_I2C_ADDR	0x4a
35 #define ATMEL_TS_I2C_BL_ADDR	0x26
36 #define CYAPA_TP_I2C_ADDR	0x67
37 #define ISL_ALS_I2C_ADDR	0x44
38 #define TAOS_ALS_I2C_ADDR	0x29
39 
40 #define MAX_I2C_DEVICE_DEFERRALS	5
41 
42 static struct i2c_client *als;
43 static struct i2c_client *tp;
44 static struct i2c_client *ts;
45 
46 static const char *i2c_adapter_names[] = {
47 	"SMBus I801 adapter",
48 	"i915 gmbus vga",
49 	"i915 gmbus panel",
50 	"i2c-designware-pci",
51 	"i2c-designware-pci",
52 };
53 
54 /* Keep this enum consistent with i2c_adapter_names */
55 enum i2c_adapter_type {
56 	I2C_ADAPTER_SMBUS = 0,
57 	I2C_ADAPTER_VGADDC,
58 	I2C_ADAPTER_PANEL,
59 	I2C_ADAPTER_DESIGNWARE_0,
60 	I2C_ADAPTER_DESIGNWARE_1,
61 };
62 
63 enum i2c_peripheral_state {
64 	UNPROBED = 0,
65 	PROBED,
66 	TIMEDOUT,
67 };
68 
69 struct i2c_peripheral {
70 	int (*add)(enum i2c_adapter_type type);
71 	enum i2c_adapter_type type;
72 	enum i2c_peripheral_state state;
73 	int tries;
74 };
75 
76 #define MAX_I2C_PERIPHERALS 3
77 
78 struct chromeos_laptop {
79 	struct i2c_peripheral i2c_peripherals[MAX_I2C_PERIPHERALS];
80 };
81 
82 static struct chromeos_laptop *cros_laptop;
83 
84 static struct i2c_board_info cyapa_device = {
85 	I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
86 	.flags		= I2C_CLIENT_WAKE,
87 };
88 
89 static struct i2c_board_info isl_als_device = {
90 	I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
91 };
92 
93 static struct i2c_board_info tsl2583_als_device = {
94 	I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
95 };
96 
97 static struct i2c_board_info tsl2563_als_device = {
98 	I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
99 };
100 
101 static int mxt_t19_keys[] = {
102 	KEY_RESERVED,
103 	KEY_RESERVED,
104 	KEY_RESERVED,
105 	KEY_RESERVED,
106 	KEY_RESERVED,
107 	BTN_LEFT
108 };
109 
110 static struct mxt_platform_data atmel_224s_tp_platform_data = {
111 	.irqflags		= IRQF_TRIGGER_FALLING,
112 	.t19_num_keys		= ARRAY_SIZE(mxt_t19_keys),
113 	.t19_keymap		= mxt_t19_keys,
114 };
115 
116 static struct i2c_board_info atmel_224s_tp_device = {
117 	I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR),
118 	.platform_data = &atmel_224s_tp_platform_data,
119 	.flags		= I2C_CLIENT_WAKE,
120 };
121 
122 static struct mxt_platform_data atmel_1664s_platform_data = {
123 	.irqflags		= IRQF_TRIGGER_FALLING,
124 };
125 
126 static struct i2c_board_info atmel_1664s_device = {
127 	I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR),
128 	.platform_data = &atmel_1664s_platform_data,
129 	.flags		= I2C_CLIENT_WAKE,
130 };
131 
132 static struct i2c_client *__add_probed_i2c_device(
133 		const char *name,
134 		int bus,
135 		struct i2c_board_info *info,
136 		const unsigned short *alt_addr_list)
137 {
138 	const struct dmi_device *dmi_dev;
139 	const struct dmi_dev_onboard *dev_data;
140 	struct i2c_adapter *adapter;
141 	struct i2c_client *client = NULL;
142 	const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
143 
144 	if (bus < 0)
145 		return NULL;
146 	/*
147 	 * If a name is specified, look for irq platform information stashed
148 	 * in DMI_DEV_TYPE_DEV_ONBOARD by the Chrome OS custom system firmware.
149 	 */
150 	if (name) {
151 		dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, name, NULL);
152 		if (!dmi_dev) {
153 			pr_err("%s failed to dmi find device %s.\n",
154 			       __func__,
155 			       name);
156 			return NULL;
157 		}
158 		dev_data = (struct dmi_dev_onboard *)dmi_dev->device_data;
159 		if (!dev_data) {
160 			pr_err("%s failed to get data from dmi for %s.\n",
161 			       __func__, name);
162 			return NULL;
163 		}
164 		info->irq = dev_data->instance;
165 	}
166 
167 	adapter = i2c_get_adapter(bus);
168 	if (!adapter) {
169 		pr_err("%s failed to get i2c adapter %d.\n", __func__, bus);
170 		return NULL;
171 	}
172 
173 	/*
174 	 * Add the i2c device. If we can't detect it at the primary
175 	 * address we scan secondary addresses. In any case the client
176 	 * structure gets assigned primary address.
177 	 */
178 	client = i2c_new_probed_device(adapter, info, addr_list, NULL);
179 	if (!client && alt_addr_list) {
180 		struct i2c_board_info dummy_info = {
181 			I2C_BOARD_INFO("dummy", info->addr),
182 		};
183 		struct i2c_client *dummy;
184 
185 		dummy = i2c_new_probed_device(adapter, &dummy_info,
186 					      alt_addr_list, NULL);
187 		if (dummy) {
188 			pr_debug("%s %d-%02x is probed at %02x\n",
189 				  __func__, bus, info->addr, dummy->addr);
190 			i2c_unregister_device(dummy);
191 			client = i2c_new_device(adapter, info);
192 		}
193 	}
194 
195 	if (!client)
196 		pr_notice("%s failed to register device %d-%02x\n",
197 			  __func__, bus, info->addr);
198 	else
199 		pr_debug("%s added i2c device %d-%02x\n",
200 			 __func__, bus, info->addr);
201 
202 	i2c_put_adapter(adapter);
203 	return client;
204 }
205 
206 struct i2c_lookup {
207 	const char *name;
208 	int instance;
209 	int n;
210 };
211 
212 static int __find_i2c_adap(struct device *dev, void *data)
213 {
214 	struct i2c_lookup *lookup = data;
215 	static const char *prefix = "i2c-";
216 	struct i2c_adapter *adapter;
217 
218 	if (strncmp(dev_name(dev), prefix, strlen(prefix)) != 0)
219 		return 0;
220 	adapter = to_i2c_adapter(dev);
221 	if (strncmp(adapter->name, lookup->name, strlen(lookup->name)) == 0 &&
222 	    lookup->n++ == lookup->instance)
223 		return 1;
224 	return 0;
225 }
226 
227 static int find_i2c_adapter_num(enum i2c_adapter_type type)
228 {
229 	struct device *dev = NULL;
230 	struct i2c_adapter *adapter;
231 	struct i2c_lookup lookup;
232 
233 	memset(&lookup, 0, sizeof(lookup));
234 	lookup.name = i2c_adapter_names[type];
235 	lookup.instance = (type == I2C_ADAPTER_DESIGNWARE_1) ? 1 : 0;
236 
237 	/* find the adapter by name */
238 	dev = bus_find_device(&i2c_bus_type, NULL, &lookup, __find_i2c_adap);
239 	if (!dev) {
240 		/* Adapters may appear later. Deferred probing will retry */
241 		pr_notice("%s: i2c adapter %s not found on system.\n", __func__,
242 			  lookup.name);
243 		return -ENODEV;
244 	}
245 	adapter = to_i2c_adapter(dev);
246 	return adapter->nr;
247 }
248 
249 /*
250  * Takes a list of addresses in addrs as such :
251  * { addr1, ... , addrn, I2C_CLIENT_END };
252  * add_probed_i2c_device will use i2c_new_probed_device
253  * and probe for devices at all of the addresses listed.
254  * Returns NULL if no devices found.
255  * See Documentation/i2c/instantiating-devices for more information.
256  */
257 static struct i2c_client *add_probed_i2c_device(
258 		const char *name,
259 		enum i2c_adapter_type type,
260 		struct i2c_board_info *info,
261 		const unsigned short *addrs)
262 {
263 	return __add_probed_i2c_device(name,
264 				       find_i2c_adapter_num(type),
265 				       info,
266 				       addrs);
267 }
268 
269 /*
270  * Probes for a device at a single address, the one provided by
271  * info->addr.
272  * Returns NULL if no device found.
273  */
274 static struct i2c_client *add_i2c_device(const char *name,
275 						enum i2c_adapter_type type,
276 						struct i2c_board_info *info)
277 {
278 	return __add_probed_i2c_device(name,
279 				       find_i2c_adapter_num(type),
280 				       info,
281 				       NULL);
282 }
283 
284 static int setup_cyapa_tp(enum i2c_adapter_type type)
285 {
286 	if (tp)
287 		return 0;
288 
289 	/* add cyapa touchpad */
290 	tp = add_i2c_device("trackpad", type, &cyapa_device);
291 	return (!tp) ? -EAGAIN : 0;
292 }
293 
294 static int setup_atmel_224s_tp(enum i2c_adapter_type type)
295 {
296 	const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR,
297 					     I2C_CLIENT_END };
298 	if (tp)
299 		return 0;
300 
301 	/* add atmel mxt touchpad */
302 	tp = add_probed_i2c_device("trackpad", type,
303 				   &atmel_224s_tp_device, addr_list);
304 	return (!tp) ? -EAGAIN : 0;
305 }
306 
307 static int setup_atmel_1664s_ts(enum i2c_adapter_type type)
308 {
309 	const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR,
310 					     I2C_CLIENT_END };
311 	if (ts)
312 		return 0;
313 
314 	/* add atmel mxt touch device */
315 	ts = add_probed_i2c_device("touchscreen", type,
316 				   &atmel_1664s_device, addr_list);
317 	return (!ts) ? -EAGAIN : 0;
318 }
319 
320 static int setup_isl29018_als(enum i2c_adapter_type type)
321 {
322 	if (als)
323 		return 0;
324 
325 	/* add isl29018 light sensor */
326 	als = add_i2c_device("lightsensor", type, &isl_als_device);
327 	return (!als) ? -EAGAIN : 0;
328 }
329 
330 static int setup_tsl2583_als(enum i2c_adapter_type type)
331 {
332 	if (als)
333 		return 0;
334 
335 	/* add tsl2583 light sensor */
336 	als = add_i2c_device(NULL, type, &tsl2583_als_device);
337 	return (!als) ? -EAGAIN : 0;
338 }
339 
340 static int setup_tsl2563_als(enum i2c_adapter_type type)
341 {
342 	if (als)
343 		return 0;
344 
345 	/* add tsl2563 light sensor */
346 	als = add_i2c_device(NULL, type, &tsl2563_als_device);
347 	return (!als) ? -EAGAIN : 0;
348 }
349 
350 static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)
351 {
352 	cros_laptop = (void *)id->driver_data;
353 	pr_debug("DMI Matched %s.\n", id->ident);
354 
355 	/* Indicate to dmi_scan that processing is done. */
356 	return 1;
357 }
358 
359 static int chromeos_laptop_probe(struct platform_device *pdev)
360 {
361 	int i;
362 	int ret = 0;
363 
364 	for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
365 		struct i2c_peripheral *i2c_dev;
366 
367 		i2c_dev = &cros_laptop->i2c_peripherals[i];
368 
369 		/* No more peripherals. */
370 		if (i2c_dev->add == NULL)
371 			break;
372 
373 		if (i2c_dev->state == TIMEDOUT || i2c_dev->state == PROBED)
374 			continue;
375 
376 		/*
377 		 * Check that the i2c adapter is present.
378 		 * -EPROBE_DEFER if missing as the adapter may appear much
379 		 * later.
380 		 */
381 		if (find_i2c_adapter_num(i2c_dev->type) == -ENODEV) {
382 			ret = -EPROBE_DEFER;
383 			continue;
384 		}
385 
386 		/* Add the device. */
387 		if (i2c_dev->add(i2c_dev->type) == -EAGAIN) {
388 			/*
389 			 * Set -EPROBE_DEFER a limited num of times
390 			 * if device is not successfully added.
391 			 */
392 			if (++i2c_dev->tries < MAX_I2C_DEVICE_DEFERRALS) {
393 				ret = -EPROBE_DEFER;
394 			} else {
395 				/* Ran out of tries. */
396 				pr_notice("%s: Ran out of tries for device.\n",
397 					  __func__);
398 				i2c_dev->state = TIMEDOUT;
399 			}
400 		} else {
401 			i2c_dev->state = PROBED;
402 		}
403 	}
404 
405 	return ret;
406 }
407 
408 static struct chromeos_laptop samsung_series_5_550 = {
409 	.i2c_peripherals = {
410 		/* Touchpad. */
411 		{ .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
412 		/* Light Sensor. */
413 		{ .add = setup_isl29018_als, I2C_ADAPTER_SMBUS },
414 	},
415 };
416 
417 static struct chromeos_laptop samsung_series_5 = {
418 	.i2c_peripherals = {
419 		/* Light Sensor. */
420 		{ .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS },
421 	},
422 };
423 
424 static struct chromeos_laptop chromebook_pixel = {
425 	.i2c_peripherals = {
426 		/* Touch Screen. */
427 		{ .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL },
428 		/* Touchpad. */
429 		{ .add = setup_atmel_224s_tp, I2C_ADAPTER_VGADDC },
430 		/* Light Sensor. */
431 		{ .add = setup_isl29018_als, I2C_ADAPTER_PANEL },
432 	},
433 };
434 
435 static struct chromeos_laptop hp_chromebook_14 = {
436 	.i2c_peripherals = {
437 		/* Touchpad. */
438 		{ .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
439 	},
440 };
441 
442 static struct chromeos_laptop dell_chromebook_11 = {
443 	.i2c_peripherals = {
444 		/* Touchpad. */
445 		{ .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
446 	},
447 };
448 
449 static struct chromeos_laptop toshiba_cb35 = {
450 	.i2c_peripherals = {
451 		/* Touchpad. */
452 		{ .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
453 	},
454 };
455 
456 static struct chromeos_laptop acer_c7_chromebook = {
457 	.i2c_peripherals = {
458 		/* Touchpad. */
459 		{ .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
460 	},
461 };
462 
463 static struct chromeos_laptop acer_ac700 = {
464 	.i2c_peripherals = {
465 		/* Light Sensor. */
466 		{ .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
467 	},
468 };
469 
470 static struct chromeos_laptop acer_c720 = {
471 	.i2c_peripherals = {
472 		/* Touchscreen. */
473 		{ .add = setup_atmel_1664s_ts, I2C_ADAPTER_DESIGNWARE_1 },
474 		/* Touchpad. */
475 		{ .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
476 		/* Light Sensor. */
477 		{ .add = setup_isl29018_als, I2C_ADAPTER_DESIGNWARE_1 },
478 	},
479 };
480 
481 static struct chromeos_laptop hp_pavilion_14_chromebook = {
482 	.i2c_peripherals = {
483 		/* Touchpad. */
484 		{ .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
485 	},
486 };
487 
488 static struct chromeos_laptop cr48 = {
489 	.i2c_peripherals = {
490 		/* Light Sensor. */
491 		{ .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
492 	},
493 };
494 
495 #define _CBDD(board_) \
496 	.callback = chromeos_laptop_dmi_matched, \
497 	.driver_data = (void *)&board_
498 
499 static struct dmi_system_id chromeos_laptop_dmi_table[] __initdata = {
500 	{
501 		.ident = "Samsung Series 5 550",
502 		.matches = {
503 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
504 			DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
505 		},
506 		_CBDD(samsung_series_5_550),
507 	},
508 	{
509 		.ident = "Samsung Series 5",
510 		.matches = {
511 			DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
512 		},
513 		_CBDD(samsung_series_5),
514 	},
515 	{
516 		.ident = "Chromebook Pixel",
517 		.matches = {
518 			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
519 			DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
520 		},
521 		_CBDD(chromebook_pixel),
522 	},
523 	{
524 		.ident = "Wolf",
525 		.matches = {
526 			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
527 			DMI_MATCH(DMI_PRODUCT_NAME, "Wolf"),
528 		},
529 		_CBDD(dell_chromebook_11),
530 	},
531 	{
532 		.ident = "HP Chromebook 14",
533 		.matches = {
534 			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
535 			DMI_MATCH(DMI_PRODUCT_NAME, "Falco"),
536 		},
537 		_CBDD(hp_chromebook_14),
538 	},
539 	{
540 		.ident = "Toshiba CB35",
541 		.matches = {
542 			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
543 			DMI_MATCH(DMI_PRODUCT_NAME, "Leon"),
544 		},
545 		_CBDD(toshiba_cb35),
546 	},
547 	{
548 		.ident = "Acer C7 Chromebook",
549 		.matches = {
550 			DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
551 		},
552 		_CBDD(acer_c7_chromebook),
553 	},
554 	{
555 		.ident = "Acer AC700",
556 		.matches = {
557 			DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
558 		},
559 		_CBDD(acer_ac700),
560 	},
561 	{
562 		.ident = "Acer C720",
563 		.matches = {
564 			DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"),
565 		},
566 		_CBDD(acer_c720),
567 	},
568 	{
569 		.ident = "HP Pavilion 14 Chromebook",
570 		.matches = {
571 			DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
572 		},
573 		_CBDD(hp_pavilion_14_chromebook),
574 	},
575 	{
576 		.ident = "Cr-48",
577 		.matches = {
578 			DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
579 		},
580 		_CBDD(cr48),
581 	},
582 	{ }
583 };
584 MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
585 
586 static struct platform_device *cros_platform_device;
587 
588 static struct platform_driver cros_platform_driver = {
589 	.driver = {
590 		.name = "chromeos_laptop",
591 	},
592 	.probe = chromeos_laptop_probe,
593 };
594 
595 static int __init chromeos_laptop_init(void)
596 {
597 	int ret;
598 
599 	if (!dmi_check_system(chromeos_laptop_dmi_table)) {
600 		pr_debug("%s unsupported system.\n", __func__);
601 		return -ENODEV;
602 	}
603 
604 	ret = platform_driver_register(&cros_platform_driver);
605 	if (ret)
606 		return ret;
607 
608 	cros_platform_device = platform_device_alloc("chromeos_laptop", -1);
609 	if (!cros_platform_device) {
610 		ret = -ENOMEM;
611 		goto fail_platform_device1;
612 	}
613 
614 	ret = platform_device_add(cros_platform_device);
615 	if (ret)
616 		goto fail_platform_device2;
617 
618 	return 0;
619 
620 fail_platform_device2:
621 	platform_device_put(cros_platform_device);
622 fail_platform_device1:
623 	platform_driver_unregister(&cros_platform_driver);
624 	return ret;
625 }
626 
627 static void __exit chromeos_laptop_exit(void)
628 {
629 	if (als)
630 		i2c_unregister_device(als);
631 	if (tp)
632 		i2c_unregister_device(tp);
633 	if (ts)
634 		i2c_unregister_device(ts);
635 
636 	platform_device_unregister(cros_platform_device);
637 	platform_driver_unregister(&cros_platform_driver);
638 }
639 
640 module_init(chromeos_laptop_init);
641 module_exit(chromeos_laptop_exit);
642 
643 MODULE_DESCRIPTION("Chrome OS Laptop driver");
644 MODULE_AUTHOR("Benson Leung <bleung@chromium.org>");
645 MODULE_LICENSE("GPL");
646