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