other.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * DMI based code to deal with broken DSDTs on X86 tablets which ship with
  4. * Android as (part of) the factory image. The factory kernels shipped on these
  5. * devices typically have a bunch of things hardcoded, rather than specified
  6. * in their DSDT.
  7. *
  8. * Copyright (C) 2021-2023 Hans de Goede <hdegoede@redhat.com>
  9. */
  10. #include <linux/acpi.h>
  11. #include <linux/gpio/machine.h>
  12. #include <linux/input.h>
  13. #include <linux/leds.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/pwm.h>
  16. #include <dt-bindings/leds/common.h>
  17. #include "shared-psy-info.h"
  18. #include "x86-android-tablets.h"
  19. /* Acer Iconia One 7 B1-750 has an Android factory image with everything hardcoded */
  20. static const char * const acer_b1_750_mount_matrix[] = {
  21. "-1", "0", "0",
  22. "0", "1", "0",
  23. "0", "0", "1"
  24. };
  25. static const struct property_entry acer_b1_750_bma250e_props[] = {
  26. PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix),
  27. { }
  28. };
  29. static const struct software_node acer_b1_750_bma250e_node = {
  30. .properties = acer_b1_750_bma250e_props,
  31. };
  32. static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = {
  33. {
  34. /* Novatek NVT-ts touchscreen */
  35. .board_info = {
  36. .type = "NVT-ts",
  37. .addr = 0x34,
  38. .dev_name = "NVT-ts",
  39. },
  40. .adapter_path = "\\_SB_.I2C4",
  41. .irq_data = {
  42. .type = X86_ACPI_IRQ_TYPE_GPIOINT,
  43. .chip = "INT33FC:02",
  44. .index = 3,
  45. .trigger = ACPI_EDGE_SENSITIVE,
  46. .polarity = ACPI_ACTIVE_LOW,
  47. .con_id = "NVT-ts_irq",
  48. },
  49. }, {
  50. /* BMA250E accelerometer */
  51. .board_info = {
  52. .type = "bma250e",
  53. .addr = 0x18,
  54. .swnode = &acer_b1_750_bma250e_node,
  55. },
  56. .adapter_path = "\\_SB_.I2C3",
  57. .irq_data = {
  58. .type = X86_ACPI_IRQ_TYPE_GPIOINT,
  59. .chip = "INT33FC:02",
  60. .index = 25,
  61. .trigger = ACPI_LEVEL_SENSITIVE,
  62. .polarity = ACPI_ACTIVE_HIGH,
  63. .con_id = "bma250e_irq",
  64. },
  65. },
  66. };
  67. static struct gpiod_lookup_table acer_b1_750_nvt_ts_gpios = {
  68. .dev_id = "i2c-NVT-ts",
  69. .table = {
  70. GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),
  71. { }
  72. },
  73. };
  74. static struct gpiod_lookup_table * const acer_b1_750_gpios[] = {
  75. &acer_b1_750_nvt_ts_gpios,
  76. &int3496_reference_gpios,
  77. NULL
  78. };
  79. const struct x86_dev_info acer_b1_750_info __initconst = {
  80. .i2c_client_info = acer_b1_750_i2c_clients,
  81. .i2c_client_count = ARRAY_SIZE(acer_b1_750_i2c_clients),
  82. .pdev_info = int3496_pdevs,
  83. .pdev_count = 1,
  84. .gpiod_lookup_tables = acer_b1_750_gpios,
  85. };
  86. /*
  87. * Advantech MICA-071
  88. * This is a standard Windows tablet, but it has an extra "quick launch" button
  89. * which is not described in the ACPI tables in anyway.
  90. * Use the x86-android-tablets infra to create a gpio-keys device for this.
  91. */
  92. static const struct x86_gpio_button advantech_mica_071_button __initconst = {
  93. .button = {
  94. .code = KEY_PROG1,
  95. .active_low = true,
  96. .desc = "prog1_key",
  97. .type = EV_KEY,
  98. .wakeup = false,
  99. .debounce_interval = 50,
  100. },
  101. .chip = "INT33FC:00",
  102. .pin = 2,
  103. };
  104. const struct x86_dev_info advantech_mica_071_info __initconst = {
  105. .gpio_button = &advantech_mica_071_button,
  106. .gpio_button_count = 1,
  107. };
  108. /*
  109. * When booted with the BIOS set to Android mode the Chuwi Hi8 (CWI509) DSDT
  110. * contains a whole bunch of bogus ACPI I2C devices and is missing entries
  111. * for the touchscreen and the accelerometer.
  112. */
  113. static const struct property_entry chuwi_hi8_gsl1680_props[] = {
  114. PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
  115. PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
  116. PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
  117. PROPERTY_ENTRY_BOOL("silead,home-button"),
  118. PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"),
  119. { }
  120. };
  121. static const struct software_node chuwi_hi8_gsl1680_node = {
  122. .properties = chuwi_hi8_gsl1680_props,
  123. };
  124. static const char * const chuwi_hi8_mount_matrix[] = {
  125. "1", "0", "0",
  126. "0", "-1", "0",
  127. "0", "0", "1"
  128. };
  129. static const struct property_entry chuwi_hi8_bma250e_props[] = {
  130. PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", chuwi_hi8_mount_matrix),
  131. { }
  132. };
  133. static const struct software_node chuwi_hi8_bma250e_node = {
  134. .properties = chuwi_hi8_bma250e_props,
  135. };
  136. static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {
  137. {
  138. /* Silead touchscreen */
  139. .board_info = {
  140. .type = "gsl1680",
  141. .addr = 0x40,
  142. .swnode = &chuwi_hi8_gsl1680_node,
  143. },
  144. .adapter_path = "\\_SB_.I2C4",
  145. .irq_data = {
  146. .type = X86_ACPI_IRQ_TYPE_APIC,
  147. .index = 0x44,
  148. .trigger = ACPI_EDGE_SENSITIVE,
  149. .polarity = ACPI_ACTIVE_HIGH,
  150. },
  151. }, {
  152. /* BMA250E accelerometer */
  153. .board_info = {
  154. .type = "bma250e",
  155. .addr = 0x18,
  156. .swnode = &chuwi_hi8_bma250e_node,
  157. },
  158. .adapter_path = "\\_SB_.I2C3",
  159. .irq_data = {
  160. .type = X86_ACPI_IRQ_TYPE_GPIOINT,
  161. .chip = "INT33FC:02",
  162. .index = 23,
  163. .trigger = ACPI_LEVEL_SENSITIVE,
  164. .polarity = ACPI_ACTIVE_HIGH,
  165. .con_id = "bma250e_irq",
  166. },
  167. },
  168. };
  169. static int __init chuwi_hi8_init(struct device *dev)
  170. {
  171. /*
  172. * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get()
  173. * breaking the touchscreen + logging various errors when the Windows
  174. * BIOS is used.
  175. */
  176. if (acpi_dev_present("MSSL0001", NULL, 1))
  177. return -ENODEV;
  178. return 0;
  179. }
  180. const struct x86_dev_info chuwi_hi8_info __initconst = {
  181. .i2c_client_info = chuwi_hi8_i2c_clients,
  182. .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
  183. .init = chuwi_hi8_init,
  184. };
  185. /*
  186. * Cyberbook T116 Android version
  187. * This comes in both Windows and Android versions and even on Android
  188. * the DSDT is mostly sane. This tablet has 2 extra general purpose buttons
  189. * in the button row with the power + volume-buttons labeled P and F.
  190. * Use the x86-android-tablets infra to create a gpio-keys device for these.
  191. */
  192. static const struct x86_gpio_button cyberbook_t116_buttons[] __initconst = {
  193. {
  194. .button = {
  195. .code = KEY_PROG1,
  196. .active_low = true,
  197. .desc = "prog1_key",
  198. .type = EV_KEY,
  199. .wakeup = false,
  200. .debounce_interval = 50,
  201. },
  202. .chip = "INT33FF:00",
  203. .pin = 30,
  204. },
  205. {
  206. .button = {
  207. .code = KEY_PROG2,
  208. .active_low = true,
  209. .desc = "prog2_key",
  210. .type = EV_KEY,
  211. .wakeup = false,
  212. .debounce_interval = 50,
  213. },
  214. .chip = "INT33FF:03",
  215. .pin = 48,
  216. },
  217. };
  218. const struct x86_dev_info cyberbook_t116_info __initconst = {
  219. .gpio_button = cyberbook_t116_buttons,
  220. .gpio_button_count = ARRAY_SIZE(cyberbook_t116_buttons),
  221. };
  222. #define CZC_EC_EXTRA_PORT 0x68
  223. #define CZC_EC_ANDROID_KEYS 0x63
  224. static int __init czc_p10t_init(struct device *dev)
  225. {
  226. /*
  227. * The device boots up in "Windows 7" mode, when the home button sends a
  228. * Windows specific key sequence (Left Meta + D) and the second button
  229. * sends an unknown one while also toggling the Radio Kill Switch.
  230. * This is a surprising behavior when the second button is labeled "Back".
  231. *
  232. * The vendor-supplied Android-x86 build switches the device to a "Android"
  233. * mode by writing value 0x63 to the I/O port 0x68. This just seems to just
  234. * set bit 6 on address 0x96 in the EC region; switching the bit directly
  235. * seems to achieve the same result. It uses a "p10t_switcher" to do the
  236. * job. It doesn't seem to be able to do anything else, and no other use
  237. * of the port 0x68 is known.
  238. *
  239. * In the Android mode, the home button sends just a single scancode,
  240. * which can be handled in Linux userspace more reasonably and the back
  241. * button only sends a scancode without toggling the kill switch.
  242. * The scancode can then be mapped either to Back or RF Kill functionality
  243. * in userspace, depending on how the button is labeled on that particular
  244. * model.
  245. */
  246. outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
  247. return 0;
  248. }
  249. const struct x86_dev_info czc_p10t __initconst = {
  250. .init = czc_p10t_init,
  251. };
  252. /* Medion Lifetab S10346 tablets have an Android factory image with everything hardcoded */
  253. static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {
  254. "0", "1", "0",
  255. "1", "0", "0",
  256. "0", "0", "1"
  257. };
  258. static const struct property_entry medion_lifetab_s10346_accel_props[] = {
  259. PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", medion_lifetab_s10346_accel_mount_matrix),
  260. { }
  261. };
  262. static const struct software_node medion_lifetab_s10346_accel_node = {
  263. .properties = medion_lifetab_s10346_accel_props,
  264. };
  265. /* Note the LCD panel is mounted upside down, this is correctly indicated in the VBT */
  266. static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = {
  267. PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
  268. PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
  269. { }
  270. };
  271. static const struct software_node medion_lifetab_s10346_touchscreen_node = {
  272. .properties = medion_lifetab_s10346_touchscreen_props,
  273. };
  274. static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {
  275. {
  276. /* kxtj21009 accelerometer */
  277. .board_info = {
  278. .type = "kxtj21009",
  279. .addr = 0x0f,
  280. .dev_name = "kxtj21009",
  281. .swnode = &medion_lifetab_s10346_accel_node,
  282. },
  283. .adapter_path = "\\_SB_.I2C3",
  284. .irq_data = {
  285. .type = X86_ACPI_IRQ_TYPE_GPIOINT,
  286. .chip = "INT33FC:02",
  287. .index = 23,
  288. .trigger = ACPI_EDGE_SENSITIVE,
  289. .polarity = ACPI_ACTIVE_HIGH,
  290. .con_id = "kxtj21009_irq",
  291. },
  292. }, {
  293. /* goodix touchscreen */
  294. .board_info = {
  295. .type = "GDIX1001:00",
  296. .addr = 0x14,
  297. .dev_name = "goodix_ts",
  298. .swnode = &medion_lifetab_s10346_touchscreen_node,
  299. },
  300. .adapter_path = "\\_SB_.I2C4",
  301. .irq_data = {
  302. .type = X86_ACPI_IRQ_TYPE_APIC,
  303. .index = 0x44,
  304. .trigger = ACPI_EDGE_SENSITIVE,
  305. .polarity = ACPI_ACTIVE_LOW,
  306. },
  307. },
  308. };
  309. static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = {
  310. .dev_id = "i2c-goodix_ts",
  311. .table = {
  312. GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
  313. GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
  314. { }
  315. },
  316. };
  317. static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = {
  318. &medion_lifetab_s10346_goodix_gpios,
  319. NULL
  320. };
  321. const struct x86_dev_info medion_lifetab_s10346_info __initconst = {
  322. .i2c_client_info = medion_lifetab_s10346_i2c_clients,
  323. .i2c_client_count = ARRAY_SIZE(medion_lifetab_s10346_i2c_clients),
  324. .gpiod_lookup_tables = medion_lifetab_s10346_gpios,
  325. };
  326. /* Nextbook Ares 8 (BYT) tablets have an Android factory image with everything hardcoded */
  327. static const char * const nextbook_ares8_accel_mount_matrix[] = {
  328. "0", "-1", "0",
  329. "-1", "0", "0",
  330. "0", "0", "1"
  331. };
  332. static const struct property_entry nextbook_ares8_accel_props[] = {
  333. PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8_accel_mount_matrix),
  334. { }
  335. };
  336. static const struct software_node nextbook_ares8_accel_node = {
  337. .properties = nextbook_ares8_accel_props,
  338. };
  339. static const struct property_entry nextbook_ares8_touchscreen_props[] = {
  340. PROPERTY_ENTRY_U32("touchscreen-size-x", 800),
  341. PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
  342. { }
  343. };
  344. static const struct software_node nextbook_ares8_touchscreen_node = {
  345. .properties = nextbook_ares8_touchscreen_props,
  346. };
  347. static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst = {
  348. {
  349. /* Freescale MMA8653FC accelerometer */
  350. .board_info = {
  351. .type = "mma8653",
  352. .addr = 0x1d,
  353. .dev_name = "mma8653",
  354. .swnode = &nextbook_ares8_accel_node,
  355. },
  356. .adapter_path = "\\_SB_.I2C3",
  357. }, {
  358. /* FT5416DQ9 touchscreen controller */
  359. .board_info = {
  360. .type = "edt-ft5x06",
  361. .addr = 0x38,
  362. .dev_name = "ft5416",
  363. .swnode = &nextbook_ares8_touchscreen_node,
  364. },
  365. .adapter_path = "\\_SB_.I2C4",
  366. .irq_data = {
  367. .type = X86_ACPI_IRQ_TYPE_GPIOINT,
  368. .chip = "INT33FC:02",
  369. .index = 3,
  370. .trigger = ACPI_EDGE_SENSITIVE,
  371. .polarity = ACPI_ACTIVE_LOW,
  372. .con_id = "ft5416_irq",
  373. },
  374. },
  375. };
  376. static struct gpiod_lookup_table * const nextbook_ares8_gpios[] = {
  377. &int3496_reference_gpios,
  378. NULL
  379. };
  380. const struct x86_dev_info nextbook_ares8_info __initconst = {
  381. .i2c_client_info = nextbook_ares8_i2c_clients,
  382. .i2c_client_count = ARRAY_SIZE(nextbook_ares8_i2c_clients),
  383. .pdev_info = int3496_pdevs,
  384. .pdev_count = 1,
  385. .gpiod_lookup_tables = nextbook_ares8_gpios,
  386. };
  387. /* Nextbook Ares 8A (CHT) tablets have an Android factory image with everything hardcoded */
  388. static const char * const nextbook_ares8a_accel_mount_matrix[] = {
  389. "1", "0", "0",
  390. "0", "-1", "0",
  391. "0", "0", "1"
  392. };
  393. static const struct property_entry nextbook_ares8a_accel_props[] = {
  394. PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8a_accel_mount_matrix),
  395. { }
  396. };
  397. static const struct software_node nextbook_ares8a_accel_node = {
  398. .properties = nextbook_ares8a_accel_props,
  399. };
  400. static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initconst = {
  401. {
  402. /* Freescale MMA8653FC accelerometer */
  403. .board_info = {
  404. .type = "mma8653",
  405. .addr = 0x1d,
  406. .dev_name = "mma8653",
  407. .swnode = &nextbook_ares8a_accel_node,
  408. },
  409. .adapter_path = "\\_SB_.PCI0.I2C3",
  410. }, {
  411. /* FT5416DQ9 touchscreen controller */
  412. .board_info = {
  413. .type = "edt-ft5x06",
  414. .addr = 0x38,
  415. .dev_name = "ft5416",
  416. .swnode = &nextbook_ares8_touchscreen_node,
  417. },
  418. .adapter_path = "\\_SB_.PCI0.I2C6",
  419. .irq_data = {
  420. .type = X86_ACPI_IRQ_TYPE_GPIOINT,
  421. .chip = "INT33FF:01",
  422. .index = 17,
  423. .trigger = ACPI_EDGE_SENSITIVE,
  424. .polarity = ACPI_ACTIVE_LOW,
  425. .con_id = "ft5416_irq",
  426. },
  427. },
  428. };
  429. static struct gpiod_lookup_table nextbook_ares8a_ft5416_gpios = {
  430. .dev_id = "i2c-ft5416",
  431. .table = {
  432. GPIO_LOOKUP("INT33FF:01", 25, "reset", GPIO_ACTIVE_LOW),
  433. { }
  434. },
  435. };
  436. static struct gpiod_lookup_table * const nextbook_ares8a_gpios[] = {
  437. &nextbook_ares8a_ft5416_gpios,
  438. NULL
  439. };
  440. const struct x86_dev_info nextbook_ares8a_info __initconst = {
  441. .i2c_client_info = nextbook_ares8a_i2c_clients,
  442. .i2c_client_count = ARRAY_SIZE(nextbook_ares8a_i2c_clients),
  443. .gpiod_lookup_tables = nextbook_ares8a_gpios,
  444. };
  445. /*
  446. * Peaq C1010
  447. * This is a standard Windows tablet, but it has a special Dolby button.
  448. * This button has a WMI interface, but that is broken. Instead of trying to
  449. * use the broken WMI interface, instantiate a gpio-keys device for this.
  450. */
  451. static const struct x86_gpio_button peaq_c1010_button __initconst = {
  452. .button = {
  453. .code = KEY_SOUND,
  454. .active_low = true,
  455. .desc = "dolby_key",
  456. .type = EV_KEY,
  457. .wakeup = false,
  458. .debounce_interval = 50,
  459. },
  460. .chip = "INT33FC:00",
  461. .pin = 3,
  462. };
  463. const struct x86_dev_info peaq_c1010_info __initconst = {
  464. .gpio_button = &peaq_c1010_button,
  465. .gpio_button_count = 1,
  466. };
  467. /*
  468. * Whitelabel (sold as various brands) TM800A550L tablets.
  469. * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
  470. * (removed through acpi_quirk_skip_i2c_client_enumeration()) and
  471. * the touchscreen firmware node has the wrong GPIOs.
  472. */
  473. static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = {
  474. "-1", "0", "0",
  475. "0", "1", "0",
  476. "0", "0", "1"
  477. };
  478. static const struct property_entry whitelabel_tm800a550l_accel_props[] = {
  479. PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", whitelabel_tm800a550l_accel_mount_matrix),
  480. { }
  481. };
  482. static const struct software_node whitelabel_tm800a550l_accel_node = {
  483. .properties = whitelabel_tm800a550l_accel_props,
  484. };
  485. static const struct property_entry whitelabel_tm800a550l_goodix_props[] = {
  486. PROPERTY_ENTRY_STRING("firmware-name", "gt912-tm800a550l.fw"),
  487. PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-tm800a550l.cfg"),
  488. PROPERTY_ENTRY_U32("goodix,main-clk", 54),
  489. { }
  490. };
  491. static const struct software_node whitelabel_tm800a550l_goodix_node = {
  492. .properties = whitelabel_tm800a550l_goodix_props,
  493. };
  494. static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __initconst = {
  495. {
  496. /* goodix touchscreen */
  497. .board_info = {
  498. .type = "GDIX1001:00",
  499. .addr = 0x14,
  500. .dev_name = "goodix_ts",
  501. .swnode = &whitelabel_tm800a550l_goodix_node,
  502. },
  503. .adapter_path = "\\_SB_.I2C2",
  504. .irq_data = {
  505. .type = X86_ACPI_IRQ_TYPE_APIC,
  506. .index = 0x44,
  507. .trigger = ACPI_EDGE_SENSITIVE,
  508. .polarity = ACPI_ACTIVE_HIGH,
  509. },
  510. }, {
  511. /* kxcj91008 accelerometer */
  512. .board_info = {
  513. .type = "kxcj91008",
  514. .addr = 0x0f,
  515. .dev_name = "kxcj91008",
  516. .swnode = &whitelabel_tm800a550l_accel_node,
  517. },
  518. .adapter_path = "\\_SB_.I2C3",
  519. },
  520. };
  521. static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
  522. .dev_id = "i2c-goodix_ts",
  523. .table = {
  524. GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
  525. GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
  526. { }
  527. },
  528. };
  529. static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
  530. &whitelabel_tm800a550l_goodix_gpios,
  531. NULL
  532. };
  533. const struct x86_dev_info whitelabel_tm800a550l_info __initconst = {
  534. .i2c_client_info = whitelabel_tm800a550l_i2c_clients,
  535. .i2c_client_count = ARRAY_SIZE(whitelabel_tm800a550l_i2c_clients),
  536. .gpiod_lookup_tables = whitelabel_tm800a550l_gpios,
  537. };
  538. /*
  539. * The firmware node for ktd2026 on Xaomi pad2. It composed of a RGB LED node
  540. * with three subnodes for each color (B/G/R). The RGB LED node is named
  541. * "multi-led" to align with the name in the device tree.
  542. */
  543. /* Main firmware node for ktd2026 */
  544. static const struct software_node ktd2026_node = {
  545. .name = "ktd2026",
  546. };
  547. static const struct property_entry ktd2026_rgb_led_props[] = {
  548. PROPERTY_ENTRY_U32("reg", 0),
  549. PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RGB),
  550. PROPERTY_ENTRY_STRING("label", "mipad2:rgb:indicator"),
  551. PROPERTY_ENTRY_STRING("linux,default-trigger", "bq27520-0-charging-orange-full-green"),
  552. { }
  553. };
  554. static const struct software_node ktd2026_rgb_led_node = {
  555. .name = "multi-led",
  556. .properties = ktd2026_rgb_led_props,
  557. .parent = &ktd2026_node,
  558. };
  559. static const struct property_entry ktd2026_blue_led_props[] = {
  560. PROPERTY_ENTRY_U32("reg", 0),
  561. PROPERTY_ENTRY_U32("color", LED_COLOR_ID_BLUE),
  562. { }
  563. };
  564. static const struct software_node ktd2026_blue_led_node = {
  565. .properties = ktd2026_blue_led_props,
  566. .parent = &ktd2026_rgb_led_node,
  567. };
  568. static const struct property_entry ktd2026_green_led_props[] = {
  569. PROPERTY_ENTRY_U32("reg", 1),
  570. PROPERTY_ENTRY_U32("color", LED_COLOR_ID_GREEN),
  571. { }
  572. };
  573. static const struct software_node ktd2026_green_led_node = {
  574. .properties = ktd2026_green_led_props,
  575. .parent = &ktd2026_rgb_led_node,
  576. };
  577. static const struct property_entry ktd2026_red_led_props[] = {
  578. PROPERTY_ENTRY_U32("reg", 2),
  579. PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RED),
  580. { }
  581. };
  582. static const struct software_node ktd2026_red_led_node = {
  583. .properties = ktd2026_red_led_props,
  584. .parent = &ktd2026_rgb_led_node,
  585. };
  586. static const struct software_node *ktd2026_node_group[] = {
  587. &ktd2026_node,
  588. &ktd2026_rgb_led_node,
  589. &ktd2026_red_led_node,
  590. &ktd2026_green_led_node,
  591. &ktd2026_blue_led_node,
  592. NULL
  593. };
  594. /*
  595. * For the LEDs which backlight the Menu / Home / Back capacitive buttons on
  596. * the bottom bezel. These are attached to a TPS61158 LED controller which
  597. * is controlled by the "pwm_soc_lpss_2" PWM output.
  598. */
  599. #define XIAOMI_MIPAD2_LED_PERIOD_NS 19200
  600. #define XIAOMI_MIPAD2_LED_MAX_DUTY_NS 6000 /* From Android kernel */
  601. static struct pwm_device *xiaomi_mipad2_led_pwm;
  602. static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,
  603. enum led_brightness val)
  604. {
  605. struct pwm_state state = {
  606. .period = XIAOMI_MIPAD2_LED_PERIOD_NS,
  607. .duty_cycle = XIAOMI_MIPAD2_LED_MAX_DUTY_NS * val / LED_FULL,
  608. /* Always set PWM enabled to avoid the pin floating */
  609. .enabled = true,
  610. };
  611. return pwm_apply_might_sleep(xiaomi_mipad2_led_pwm, &state);
  612. }
  613. static int __init xiaomi_mipad2_init(struct device *dev)
  614. {
  615. struct led_classdev *led_cdev;
  616. int ret;
  617. xiaomi_mipad2_led_pwm = devm_pwm_get(dev, "pwm_soc_lpss_2");
  618. if (IS_ERR(xiaomi_mipad2_led_pwm))
  619. return dev_err_probe(dev, PTR_ERR(xiaomi_mipad2_led_pwm), "getting pwm\n");
  620. led_cdev = devm_kzalloc(dev, sizeof(*led_cdev), GFP_KERNEL);
  621. if (!led_cdev)
  622. return -ENOMEM;
  623. led_cdev->name = "mipad2:white:touch-buttons-backlight";
  624. led_cdev->max_brightness = LED_FULL;
  625. led_cdev->default_trigger = "input-events";
  626. led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set;
  627. /* Turn LED off during suspend */
  628. led_cdev->flags = LED_CORE_SUSPENDRESUME;
  629. ret = devm_led_classdev_register(dev, led_cdev);
  630. if (ret)
  631. return dev_err_probe(dev, ret, "registering LED\n");
  632. return software_node_register_node_group(ktd2026_node_group);
  633. }
  634. static void xiaomi_mipad2_exit(void)
  635. {
  636. software_node_unregister_node_group(ktd2026_node_group);
  637. }
  638. /*
  639. * If the EFI bootloader is not Xiaomi's own signed Android loader, then the
  640. * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing
  641. * a bunch of devices to be hidden.
  642. *
  643. * This takes care of instantiating the hidden devices manually.
  644. */
  645. static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = {
  646. {
  647. /* BQ27520 fuel-gauge */
  648. .board_info = {
  649. .type = "bq27520",
  650. .addr = 0x55,
  651. .dev_name = "bq27520",
  652. .swnode = &fg_bq25890_supply_node,
  653. },
  654. .adapter_path = "\\_SB_.PCI0.I2C1",
  655. }, {
  656. /* KTD2026 RGB notification LED controller */
  657. .board_info = {
  658. .type = "ktd2026",
  659. .addr = 0x30,
  660. .dev_name = "ktd2026",
  661. .swnode = &ktd2026_node,
  662. },
  663. .adapter_path = "\\_SB_.PCI0.I2C3",
  664. },
  665. };
  666. const struct x86_dev_info xiaomi_mipad2_info __initconst = {
  667. .i2c_client_info = xiaomi_mipad2_i2c_clients,
  668. .i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients),
  669. .init = xiaomi_mipad2_init,
  670. .exit = xiaomi_mipad2_exit,
  671. };