chromeos_laptop.c 22 KB

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