cyapa_gen6.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. /*
  2. * Cypress APA trackpad with I2C interface
  3. *
  4. * Author: Dudley Du <dudl@cypress.com>
  5. *
  6. * Copyright (C) 2015 Cypress Semiconductor, Inc.
  7. *
  8. * This file is subject to the terms and conditions of the GNU General Public
  9. * License. See the file COPYING in the main directory of this archive for
  10. * more details.
  11. */
  12. #include <linux/delay.h>
  13. #include <linux/i2c.h>
  14. #include <linux/input.h>
  15. #include <linux/input/mt.h>
  16. #include <linux/mutex.h>
  17. #include <linux/completion.h>
  18. #include <linux/slab.h>
  19. #include <asm/unaligned.h>
  20. #include <linux/crc-itu-t.h>
  21. #include "cyapa.h"
  22. #define GEN6_ENABLE_CMD_IRQ 0x41
  23. #define GEN6_DISABLE_CMD_IRQ 0x42
  24. #define GEN6_ENABLE_DEV_IRQ 0x43
  25. #define GEN6_DISABLE_DEV_IRQ 0x44
  26. #define GEN6_POWER_MODE_ACTIVE 0x01
  27. #define GEN6_POWER_MODE_LP_MODE1 0x02
  28. #define GEN6_POWER_MODE_LP_MODE2 0x03
  29. #define GEN6_POWER_MODE_BTN_ONLY 0x04
  30. #define GEN6_SET_POWER_MODE_INTERVAL 0x47
  31. #define GEN6_GET_POWER_MODE_INTERVAL 0x48
  32. #define GEN6_MAX_RX_NUM 14
  33. #define GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC 0x00
  34. #define GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM 0x12
  35. struct pip_app_cmd_head {
  36. __le16 addr;
  37. __le16 length;
  38. u8 report_id;
  39. u8 resv; /* Reserved, must be 0 */
  40. u8 cmd_code; /* bit7: resv, set to 0; bit6~0: command code.*/
  41. } __packed;
  42. struct pip_app_resp_head {
  43. __le16 length;
  44. u8 report_id;
  45. u8 resv; /* Reserved, must be 0 */
  46. u8 cmd_code; /* bit7: TGL; bit6~0: command code.*/
  47. /*
  48. * The value of data_status can be the first byte of data or
  49. * the command status or the unsupported command code depending on the
  50. * requested command code.
  51. */
  52. u8 data_status;
  53. } __packed;
  54. struct pip_fixed_info {
  55. u8 silicon_id_high;
  56. u8 silicon_id_low;
  57. u8 family_id;
  58. };
  59. static u8 pip_get_bl_info[] = {
  60. 0x04, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x01, 0x38,
  61. 0x00, 0x00, 0x70, 0x9E, 0x17
  62. };
  63. static bool cyapa_sort_pip_hid_descriptor_data(struct cyapa *cyapa,
  64. u8 *buf, int len)
  65. {
  66. if (len != PIP_HID_DESCRIPTOR_SIZE)
  67. return false;
  68. if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID ||
  69. buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID)
  70. return true;
  71. return false;
  72. }
  73. static int cyapa_get_pip_fixed_info(struct cyapa *cyapa,
  74. struct pip_fixed_info *pip_info, bool is_bootloader)
  75. {
  76. u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH];
  77. int resp_len;
  78. u16 product_family;
  79. int error;
  80. if (is_bootloader) {
  81. /* Read Bootloader Information to determine Gen5 or Gen6. */
  82. resp_len = sizeof(resp_data);
  83. error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
  84. pip_get_bl_info, sizeof(pip_get_bl_info),
  85. resp_data, &resp_len,
  86. 2000, cyapa_sort_tsg_pip_bl_resp_data,
  87. false);
  88. if (error || resp_len < PIP_BL_GET_INFO_RESP_LENGTH)
  89. return error ? error : -EIO;
  90. pip_info->family_id = resp_data[8];
  91. pip_info->silicon_id_low = resp_data[10];
  92. pip_info->silicon_id_high = resp_data[11];
  93. return 0;
  94. }
  95. /* Get App System Information to determine Gen5 or Gen6. */
  96. resp_len = sizeof(resp_data);
  97. error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
  98. pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH,
  99. resp_data, &resp_len,
  100. 2000, cyapa_pip_sort_system_info_data, false);
  101. if (error || resp_len < PIP_READ_SYS_INFO_RESP_LENGTH)
  102. return error ? error : -EIO;
  103. product_family = get_unaligned_le16(&resp_data[7]);
  104. if ((product_family & PIP_PRODUCT_FAMILY_MASK) !=
  105. PIP_PRODUCT_FAMILY_TRACKPAD)
  106. return -EINVAL;
  107. pip_info->family_id = resp_data[19];
  108. pip_info->silicon_id_low = resp_data[21];
  109. pip_info->silicon_id_high = resp_data[22];
  110. return 0;
  111. }
  112. int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
  113. {
  114. u8 cmd[] = { 0x01, 0x00};
  115. struct pip_fixed_info pip_info;
  116. u8 resp_data[PIP_HID_DESCRIPTOR_SIZE];
  117. int resp_len;
  118. bool is_bootloader;
  119. int error;
  120. cyapa->state = CYAPA_STATE_NO_DEVICE;
  121. /* Try to wake from it deep sleep state if it is. */
  122. cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);
  123. /* Empty the buffer queue to get fresh data with later commands. */
  124. cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
  125. /*
  126. * Read description info from trackpad device to determine running in
  127. * APP mode or Bootloader mode.
  128. */
  129. resp_len = PIP_HID_DESCRIPTOR_SIZE;
  130. error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
  131. cmd, sizeof(cmd),
  132. resp_data, &resp_len,
  133. 300,
  134. cyapa_sort_pip_hid_descriptor_data,
  135. false);
  136. if (error)
  137. return error;
  138. if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID)
  139. is_bootloader = true;
  140. else if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID)
  141. is_bootloader = false;
  142. else
  143. return -EAGAIN;
  144. /* Get PIP fixed information to determine Gen5 or Gen6. */
  145. memset(&pip_info, 0, sizeof(struct pip_fixed_info));
  146. error = cyapa_get_pip_fixed_info(cyapa, &pip_info, is_bootloader);
  147. if (error)
  148. return error;
  149. if (pip_info.family_id == 0x9B && pip_info.silicon_id_high == 0x0B) {
  150. cyapa->gen = CYAPA_GEN6;
  151. cyapa->state = is_bootloader ? CYAPA_STATE_GEN6_BL
  152. : CYAPA_STATE_GEN6_APP;
  153. } else if (pip_info.family_id == 0x91 &&
  154. pip_info.silicon_id_high == 0x02) {
  155. cyapa->gen = CYAPA_GEN5;
  156. cyapa->state = is_bootloader ? CYAPA_STATE_GEN5_BL
  157. : CYAPA_STATE_GEN5_APP;
  158. }
  159. return 0;
  160. }
  161. static int cyapa_gen6_read_sys_info(struct cyapa *cyapa)
  162. {
  163. u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH];
  164. int resp_len;
  165. u16 product_family;
  166. u8 rotat_align;
  167. int error;
  168. /* Get App System Information to determine Gen5 or Gen6. */
  169. resp_len = sizeof(resp_data);
  170. error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
  171. pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH,
  172. resp_data, &resp_len,
  173. 2000, cyapa_pip_sort_system_info_data, false);
  174. if (error || resp_len < sizeof(resp_data))
  175. return error ? error : -EIO;
  176. product_family = get_unaligned_le16(&resp_data[7]);
  177. if ((product_family & PIP_PRODUCT_FAMILY_MASK) !=
  178. PIP_PRODUCT_FAMILY_TRACKPAD)
  179. return -EINVAL;
  180. cyapa->platform_ver = (resp_data[67] >> PIP_BL_PLATFORM_VER_SHIFT) &
  181. PIP_BL_PLATFORM_VER_MASK;
  182. cyapa->fw_maj_ver = resp_data[9];
  183. cyapa->fw_min_ver = resp_data[10];
  184. cyapa->electrodes_x = resp_data[33];
  185. cyapa->electrodes_y = resp_data[34];
  186. cyapa->physical_size_x = get_unaligned_le16(&resp_data[35]) / 100;
  187. cyapa->physical_size_y = get_unaligned_le16(&resp_data[37]) / 100;
  188. cyapa->max_abs_x = get_unaligned_le16(&resp_data[39]);
  189. cyapa->max_abs_y = get_unaligned_le16(&resp_data[41]);
  190. cyapa->max_z = get_unaligned_le16(&resp_data[43]);
  191. cyapa->x_origin = resp_data[45] & 0x01;
  192. cyapa->y_origin = resp_data[46] & 0x01;
  193. cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK;
  194. memcpy(&cyapa->product_id[0], &resp_data[51], 5);
  195. cyapa->product_id[5] = '-';
  196. memcpy(&cyapa->product_id[6], &resp_data[56], 6);
  197. cyapa->product_id[12] = '-';
  198. memcpy(&cyapa->product_id[13], &resp_data[62], 2);
  199. cyapa->product_id[15] = '\0';
  200. /* Get the number of Rx electrodes. */
  201. rotat_align = resp_data[68];
  202. cyapa->electrodes_rx =
  203. rotat_align ? cyapa->electrodes_y : cyapa->electrodes_x;
  204. cyapa->aligned_electrodes_rx = (cyapa->electrodes_rx + 3) & ~3u;
  205. if (!cyapa->electrodes_x || !cyapa->electrodes_y ||
  206. !cyapa->physical_size_x || !cyapa->physical_size_y ||
  207. !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z)
  208. return -EINVAL;
  209. return 0;
  210. }
  211. static int cyapa_gen6_bl_read_app_info(struct cyapa *cyapa)
  212. {
  213. u8 resp_data[PIP_BL_APP_INFO_RESP_LENGTH];
  214. int resp_len;
  215. int error;
  216. resp_len = sizeof(resp_data);
  217. error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
  218. pip_bl_read_app_info, PIP_BL_READ_APP_INFO_CMD_LENGTH,
  219. resp_data, &resp_len,
  220. 500, cyapa_sort_tsg_pip_bl_resp_data, false);
  221. if (error || resp_len < PIP_BL_APP_INFO_RESP_LENGTH ||
  222. !PIP_CMD_COMPLETE_SUCCESS(resp_data))
  223. return error ? error : -EIO;
  224. cyapa->fw_maj_ver = resp_data[8];
  225. cyapa->fw_min_ver = resp_data[9];
  226. cyapa->platform_ver = (resp_data[12] >> PIP_BL_PLATFORM_VER_SHIFT) &
  227. PIP_BL_PLATFORM_VER_MASK;
  228. memcpy(&cyapa->product_id[0], &resp_data[13], 5);
  229. cyapa->product_id[5] = '-';
  230. memcpy(&cyapa->product_id[6], &resp_data[18], 6);
  231. cyapa->product_id[12] = '-';
  232. memcpy(&cyapa->product_id[13], &resp_data[24], 2);
  233. cyapa->product_id[15] = '\0';
  234. return 0;
  235. }
  236. static int cyapa_gen6_config_dev_irq(struct cyapa *cyapa, u8 cmd_code)
  237. {
  238. u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, cmd_code };
  239. u8 resp_data[6];
  240. int resp_len;
  241. int error;
  242. resp_len = sizeof(resp_data);
  243. error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
  244. resp_data, &resp_len,
  245. 500, cyapa_sort_tsg_pip_app_resp_data, false);
  246. if (error || !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
  247. !PIP_CMD_COMPLETE_SUCCESS(resp_data)
  248. )
  249. return error < 0 ? error : -EINVAL;
  250. return 0;
  251. }
  252. static int cyapa_gen6_set_proximity(struct cyapa *cyapa, bool enable)
  253. {
  254. int error;
  255. cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
  256. error = cyapa_pip_set_proximity(cyapa, enable);
  257. cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ);
  258. return error;
  259. }
  260. static int cyapa_gen6_change_power_state(struct cyapa *cyapa, u8 power_mode)
  261. {
  262. u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode };
  263. u8 resp_data[6];
  264. int resp_len;
  265. int error;
  266. resp_len = sizeof(resp_data);
  267. error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
  268. resp_data, &resp_len,
  269. 500, cyapa_sort_tsg_pip_app_resp_data, false);
  270. if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x46))
  271. return error < 0 ? error : -EINVAL;
  272. /* New power state applied in device not match the set power state. */
  273. if (resp_data[5] != power_mode)
  274. return -EAGAIN;
  275. return 0;
  276. }
  277. static int cyapa_gen6_set_interval_setting(struct cyapa *cyapa,
  278. struct gen6_interval_setting *interval_setting)
  279. {
  280. struct gen6_set_interval_cmd {
  281. __le16 addr;
  282. __le16 length;
  283. u8 report_id;
  284. u8 rsvd; /* Reserved, must be 0 */
  285. u8 cmd_code;
  286. __le16 active_interval;
  287. __le16 lp1_interval;
  288. __le16 lp2_interval;
  289. } __packed set_interval_cmd;
  290. u8 resp_data[11];
  291. int resp_len;
  292. int error;
  293. memset(&set_interval_cmd, 0, sizeof(set_interval_cmd));
  294. put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &set_interval_cmd.addr);
  295. put_unaligned_le16(sizeof(set_interval_cmd) - 2,
  296. &set_interval_cmd.length);
  297. set_interval_cmd.report_id = PIP_APP_CMD_REPORT_ID;
  298. set_interval_cmd.cmd_code = GEN6_SET_POWER_MODE_INTERVAL;
  299. put_unaligned_le16(interval_setting->active_interval,
  300. &set_interval_cmd.active_interval);
  301. put_unaligned_le16(interval_setting->lp1_interval,
  302. &set_interval_cmd.lp1_interval);
  303. put_unaligned_le16(interval_setting->lp2_interval,
  304. &set_interval_cmd.lp2_interval);
  305. resp_len = sizeof(resp_data);
  306. error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
  307. (u8 *)&set_interval_cmd, sizeof(set_interval_cmd),
  308. resp_data, &resp_len,
  309. 500, cyapa_sort_tsg_pip_app_resp_data, false);
  310. if (error ||
  311. !VALID_CMD_RESP_HEADER(resp_data, GEN6_SET_POWER_MODE_INTERVAL))
  312. return error < 0 ? error : -EINVAL;
  313. /* Get the real set intervals from response. */
  314. interval_setting->active_interval = get_unaligned_le16(&resp_data[5]);
  315. interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]);
  316. interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]);
  317. return 0;
  318. }
  319. static int cyapa_gen6_get_interval_setting(struct cyapa *cyapa,
  320. struct gen6_interval_setting *interval_setting)
  321. {
  322. u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00,
  323. GEN6_GET_POWER_MODE_INTERVAL };
  324. u8 resp_data[11];
  325. int resp_len;
  326. int error;
  327. resp_len = sizeof(resp_data);
  328. error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
  329. resp_data, &resp_len,
  330. 500, cyapa_sort_tsg_pip_app_resp_data, false);
  331. if (error ||
  332. !VALID_CMD_RESP_HEADER(resp_data, GEN6_GET_POWER_MODE_INTERVAL))
  333. return error < 0 ? error : -EINVAL;
  334. interval_setting->active_interval = get_unaligned_le16(&resp_data[5]);
  335. interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]);
  336. interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]);
  337. return 0;
  338. }
  339. static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state)
  340. {
  341. u8 ping[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x00 };
  342. if (state == PIP_DEEP_SLEEP_STATE_ON)
  343. /*
  344. * Send ping command to notify device prepare for wake up
  345. * when it's in deep sleep mode. At this time, device will
  346. * response nothing except an I2C NAK.
  347. */
  348. cyapa_i2c_pip_write(cyapa, ping, sizeof(ping));
  349. return cyapa_pip_deep_sleep(cyapa, state);
  350. }
  351. static int cyapa_gen6_set_power_mode(struct cyapa *cyapa,
  352. u8 power_mode, u16 sleep_time, bool is_suspend)
  353. {
  354. struct device *dev = &cyapa->client->dev;
  355. struct gen6_interval_setting *interval_setting =
  356. &cyapa->gen6_interval_setting;
  357. u8 lp_mode;
  358. int error;
  359. if (cyapa->state != CYAPA_STATE_GEN6_APP)
  360. return 0;
  361. if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
  362. /*
  363. * Assume TP in deep sleep mode when driver is loaded,
  364. * avoid driver unload and reload command IO issue caused by TP
  365. * has been set into deep sleep mode when unloading.
  366. */
  367. PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
  368. }
  369. if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) &&
  370. PIP_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF)
  371. PIP_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME);
  372. if (PIP_DEV_GET_PWR_STATE(cyapa) == power_mode) {
  373. if (power_mode == PWR_MODE_OFF ||
  374. power_mode == PWR_MODE_FULL_ACTIVE ||
  375. power_mode == PWR_MODE_BTN_ONLY ||
  376. PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
  377. /* Has in correct power mode state, early return. */
  378. return 0;
  379. }
  380. }
  381. if (power_mode == PWR_MODE_OFF) {
  382. cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
  383. error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF);
  384. if (error) {
  385. dev_err(dev, "enter deep sleep fail: %d\n", error);
  386. return error;
  387. }
  388. PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
  389. return 0;
  390. }
  391. /*
  392. * When trackpad in power off mode, it cannot change to other power
  393. * state directly, must be wake up from sleep firstly, then
  394. * continue to do next power sate change.
  395. */
  396. if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
  397. error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);
  398. if (error) {
  399. dev_err(dev, "deep sleep wake fail: %d\n", error);
  400. return error;
  401. }
  402. }
  403. /*
  404. * Disable device assert interrupts for command response to avoid
  405. * disturbing system suspending or hibernating process.
  406. */
  407. cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
  408. if (power_mode == PWR_MODE_FULL_ACTIVE) {
  409. error = cyapa_gen6_change_power_state(cyapa,
  410. GEN6_POWER_MODE_ACTIVE);
  411. if (error) {
  412. dev_err(dev, "change to active fail: %d\n", error);
  413. goto out;
  414. }
  415. PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
  416. /* Sync the interval setting from device. */
  417. cyapa_gen6_get_interval_setting(cyapa, interval_setting);
  418. } else if (power_mode == PWR_MODE_BTN_ONLY) {
  419. error = cyapa_gen6_change_power_state(cyapa,
  420. GEN6_POWER_MODE_BTN_ONLY);
  421. if (error) {
  422. dev_err(dev, "fail to button only mode: %d\n", error);
  423. goto out;
  424. }
  425. PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
  426. } else {
  427. /*
  428. * Gen6 internally supports to 2 low power scan interval time,
  429. * so can help to switch power mode quickly.
  430. * such as runtime suspend and system suspend.
  431. */
  432. if (interval_setting->lp1_interval == sleep_time) {
  433. lp_mode = GEN6_POWER_MODE_LP_MODE1;
  434. } else if (interval_setting->lp2_interval == sleep_time) {
  435. lp_mode = GEN6_POWER_MODE_LP_MODE2;
  436. } else {
  437. if (interval_setting->lp1_interval == 0) {
  438. interval_setting->lp1_interval = sleep_time;
  439. lp_mode = GEN6_POWER_MODE_LP_MODE1;
  440. } else {
  441. interval_setting->lp2_interval = sleep_time;
  442. lp_mode = GEN6_POWER_MODE_LP_MODE2;
  443. }
  444. cyapa_gen6_set_interval_setting(cyapa,
  445. interval_setting);
  446. }
  447. error = cyapa_gen6_change_power_state(cyapa, lp_mode);
  448. if (error) {
  449. dev_err(dev, "set power state to 0x%02x failed: %d\n",
  450. lp_mode, error);
  451. goto out;
  452. }
  453. PIP_DEV_SET_SLEEP_TIME(cyapa, sleep_time);
  454. PIP_DEV_SET_PWR_STATE(cyapa,
  455. cyapa_sleep_time_to_pwr_cmd(sleep_time));
  456. }
  457. out:
  458. cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ);
  459. return error;
  460. }
  461. static int cyapa_gen6_initialize(struct cyapa *cyapa)
  462. {
  463. return 0;
  464. }
  465. static int cyapa_pip_retrieve_data_structure(struct cyapa *cyapa,
  466. u16 read_offset, u16 read_len, u8 data_id,
  467. u8 *data, int *data_buf_lens)
  468. {
  469. struct retrieve_data_struct_cmd {
  470. struct pip_app_cmd_head head;
  471. __le16 read_offset;
  472. __le16 read_length;
  473. u8 data_id;
  474. } __packed cmd;
  475. u8 resp_data[GEN6_MAX_RX_NUM + 10];
  476. int resp_len;
  477. int error;
  478. memset(&cmd, 0, sizeof(cmd));
  479. put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd.head.addr);
  480. put_unaligned_le16(sizeof(cmd), &cmd.head.length - 2);
  481. cmd.head.report_id = PIP_APP_CMD_REPORT_ID;
  482. cmd.head.cmd_code = PIP_RETRIEVE_DATA_STRUCTURE;
  483. put_unaligned_le16(read_offset, &cmd.read_offset);
  484. put_unaligned_le16(read_len, &cmd.read_length);
  485. cmd.data_id = data_id;
  486. resp_len = sizeof(resp_data);
  487. error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
  488. (u8 *)&cmd, sizeof(cmd),
  489. resp_data, &resp_len,
  490. 500, cyapa_sort_tsg_pip_app_resp_data,
  491. true);
  492. if (error || !PIP_CMD_COMPLETE_SUCCESS(resp_data) ||
  493. resp_data[6] != data_id ||
  494. !VALID_CMD_RESP_HEADER(resp_data, PIP_RETRIEVE_DATA_STRUCTURE))
  495. return (error < 0) ? error : -EAGAIN;
  496. read_len = get_unaligned_le16(&resp_data[7]);
  497. if (*data_buf_lens < read_len) {
  498. *data_buf_lens = read_len;
  499. return -ENOBUFS;
  500. }
  501. memcpy(data, &resp_data[10], read_len);
  502. *data_buf_lens = read_len;
  503. return 0;
  504. }
  505. static ssize_t cyapa_gen6_show_baseline(struct device *dev,
  506. struct device_attribute *attr, char *buf)
  507. {
  508. struct cyapa *cyapa = dev_get_drvdata(dev);
  509. u8 data[GEN6_MAX_RX_NUM];
  510. int data_len;
  511. int size = 0;
  512. int i;
  513. int error;
  514. int resume_error;
  515. if (!cyapa_is_pip_app_mode(cyapa))
  516. return -EBUSY;
  517. /* 1. Suspend Scanning*/
  518. error = cyapa_pip_suspend_scanning(cyapa);
  519. if (error)
  520. return error;
  521. /* 2. IDAC and RX Attenuator Calibration Data (Center Frequency). */
  522. data_len = sizeof(data);
  523. error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len,
  524. GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC,
  525. data, &data_len);
  526. if (error)
  527. goto resume_scanning;
  528. size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d ",
  529. data[0], /* RX Attenuator Mutual */
  530. data[1], /* IDAC Mutual */
  531. data[2], /* RX Attenuator Self RX */
  532. data[3], /* IDAC Self RX */
  533. data[4], /* RX Attenuator Self TX */
  534. data[5] /* IDAC Self TX */
  535. );
  536. /* 3. Read Attenuator Trim. */
  537. data_len = sizeof(data);
  538. error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len,
  539. GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM,
  540. data, &data_len);
  541. if (error)
  542. goto resume_scanning;
  543. /* set attenuator trim values. */
  544. for (i = 0; i < data_len; i++)
  545. size += scnprintf(buf + size, PAGE_SIZE - size, "%d ", data[i]);
  546. size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
  547. resume_scanning:
  548. /* 4. Resume Scanning*/
  549. resume_error = cyapa_pip_resume_scanning(cyapa);
  550. if (resume_error || error) {
  551. memset(buf, 0, PAGE_SIZE);
  552. return resume_error ? resume_error : error;
  553. }
  554. return size;
  555. }
  556. static int cyapa_gen6_operational_check(struct cyapa *cyapa)
  557. {
  558. struct device *dev = &cyapa->client->dev;
  559. int error;
  560. if (cyapa->gen != CYAPA_GEN6)
  561. return -ENODEV;
  562. switch (cyapa->state) {
  563. case CYAPA_STATE_GEN6_BL:
  564. error = cyapa_pip_bl_exit(cyapa);
  565. if (error) {
  566. /* Try to update trackpad product information. */
  567. cyapa_gen6_bl_read_app_info(cyapa);
  568. goto out;
  569. }
  570. cyapa->state = CYAPA_STATE_GEN6_APP;
  571. case CYAPA_STATE_GEN6_APP:
  572. /*
  573. * If trackpad device in deep sleep mode,
  574. * the app command will fail.
  575. * So always try to reset trackpad device to full active when
  576. * the device state is required.
  577. */
  578. error = cyapa_gen6_set_power_mode(cyapa,
  579. PWR_MODE_FULL_ACTIVE, 0, false);
  580. if (error)
  581. dev_warn(dev, "%s: failed to set power active mode.\n",
  582. __func__);
  583. /* By default, the trackpad proximity function is enabled. */
  584. error = cyapa_pip_set_proximity(cyapa, true);
  585. if (error)
  586. dev_warn(dev, "%s: failed to enable proximity.\n",
  587. __func__);
  588. /* Get trackpad product information. */
  589. error = cyapa_gen6_read_sys_info(cyapa);
  590. if (error)
  591. goto out;
  592. /* Only support product ID starting with CYTRA */
  593. if (memcmp(cyapa->product_id, product_id,
  594. strlen(product_id)) != 0) {
  595. dev_err(dev, "%s: unknown product ID (%s)\n",
  596. __func__, cyapa->product_id);
  597. error = -EINVAL;
  598. }
  599. break;
  600. default:
  601. error = -EINVAL;
  602. }
  603. out:
  604. return error;
  605. }
  606. const struct cyapa_dev_ops cyapa_gen6_ops = {
  607. .check_fw = cyapa_pip_check_fw,
  608. .bl_enter = cyapa_pip_bl_enter,
  609. .bl_initiate = cyapa_pip_bl_initiate,
  610. .update_fw = cyapa_pip_do_fw_update,
  611. .bl_activate = cyapa_pip_bl_activate,
  612. .bl_deactivate = cyapa_pip_bl_deactivate,
  613. .show_baseline = cyapa_gen6_show_baseline,
  614. .calibrate_store = cyapa_pip_do_calibrate,
  615. .initialize = cyapa_gen6_initialize,
  616. .state_parse = cyapa_pip_state_parse,
  617. .operational_check = cyapa_gen6_operational_check,
  618. .irq_handler = cyapa_pip_irq_handler,
  619. .irq_cmd_handler = cyapa_pip_irq_cmd_handler,
  620. .sort_empty_output_data = cyapa_empty_pip_output_data,
  621. .set_power_mode = cyapa_gen6_set_power_mode,
  622. .set_proximity = cyapa_gen6_set_proximity,
  623. };