You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

314 lines
15 KiB

  1. // Copyright 2023 Dasky (@daskygit)
  2. // Copyright 2023 George Norton (@george-norton)
  3. // SPDX-License-Identifier: GPL-2.0-or-later
  4. #include "azoteq_iqs5xx.h"
  5. #include "pointing_device_internal.h"
  6. #include "wait.h"
  7. #ifndef AZOTEQ_IQS5XX_ADDRESS
  8. # define AZOTEQ_IQS5XX_ADDRESS (0x74 << 1)
  9. #endif
  10. #ifndef AZOTEQ_IQS5XX_TIMEOUT_MS
  11. # define AZOTEQ_IQS5XX_TIMEOUT_MS 10
  12. #endif
  13. #define AZOTEQ_IQS5XX_REG_PRODUCT_NUMBER 0x0000
  14. #define AZOTEQ_IQS5XX_REG_PREVIOUS_CYCLE_TIME 0x000C
  15. #define AZOTEQ_IQS5XX_REG_SYSTEM_CONTROL_1 0x0432
  16. #define AZOTEQ_IQS5XX_REG_REPORT_RATE_ACTIVE 0x057A
  17. #define AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_0 0x058E
  18. #define AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_1 0x058F
  19. #define AZOTEQ_IQS5XX_REG_X_RESOLUTION 0x066E
  20. #define AZOTEQ_IQS5XX_REG_XY_CONFIG_0 0x0669
  21. #define AZOTEQ_IQS5XX_REG_Y_RESOLUTION 0x0670
  22. #define AZOTEQ_IQS5XX_REG_SINGLE_FINGER_GESTURES 0x06B7
  23. #define AZOTEQ_IQS5XX_REG_END_COMMS 0xEEEE
  24. // Gesture configuration
  25. #ifndef AZOTEQ_IQS5XX_TAP_ENABLE
  26. # define AZOTEQ_IQS5XX_TAP_ENABLE true
  27. #endif
  28. #ifndef AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE
  29. # define AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE false
  30. #endif
  31. #ifndef AZOTEQ_IQS5XX_TWO_FINGER_TAP_ENABLE
  32. # define AZOTEQ_IQS5XX_TWO_FINGER_TAP_ENABLE true
  33. #endif
  34. #ifndef AZOTEQ_IQS5XX_SCROLL_ENABLE
  35. # define AZOTEQ_IQS5XX_SCROLL_ENABLE true
  36. #endif
  37. #ifndef AZOTEQ_IQS5XX_SWIPE_X_ENABLE
  38. # define AZOTEQ_IQS5XX_SWIPE_X_ENABLE false
  39. #endif
  40. #ifndef AZOTEQ_IQS5XX_SWIPE_Y_ENABLE
  41. # define AZOTEQ_IQS5XX_SWIPE_Y_ENABLE false
  42. #endif
  43. #ifndef AZOTEQ_IQS5XX_ZOOM_ENABLE
  44. # define AZOTEQ_IQS5XX_ZOOM_ENABLE false
  45. #endif
  46. #ifndef AZOTEQ_IQS5XX_TAP_TIME
  47. # define AZOTEQ_IQS5XX_TAP_TIME 0x96
  48. #endif
  49. #ifndef AZOTEQ_IQS5XX_TAP_DISTANCE
  50. # define AZOTEQ_IQS5XX_TAP_DISTANCE 0x19
  51. #endif
  52. #ifndef AZOTEQ_IQS5XX_HOLD_TIME
  53. # define AZOTEQ_IQS5XX_HOLD_TIME 0x12C
  54. #endif
  55. #ifndef AZOTEQ_IQS5XX_SWIPE_INITIAL_TIME
  56. # define AZOTEQ_IQS5XX_SWIPE_INITIAL_TIME 0x64 // 0x96
  57. #endif
  58. #ifndef AZOTEQ_IQS5XX_SWIPE_INITIAL_DISTANCE
  59. # define AZOTEQ_IQS5XX_SWIPE_INITIAL_DISTANCE 0x12C
  60. #endif
  61. #ifndef AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_TIME
  62. # define AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_TIME 0x0
  63. #endif
  64. #ifndef AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_DISTANCE
  65. # define AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_DISTANCE 0x7D0
  66. #endif
  67. #ifndef AZOTEQ_IQS5XX_SCROLL_INITIAL_DISTANCE
  68. # define AZOTEQ_IQS5XX_SCROLL_INITIAL_DISTANCE 0x32
  69. #endif
  70. #ifndef AZOTEQ_IQS5XX_ZOOM_INITIAL_DISTANCE
  71. # define AZOTEQ_IQS5XX_ZOOM_INITIAL_DISTANCE 0x32
  72. #endif
  73. #ifndef AZOTEQ_IQS5XX_ZOOM_CONSECUTIVE_DISTANCE
  74. # define AZOTEQ_IQS5XX_ZOOM_CONSECUTIVE_DISTANCE 0x19
  75. #endif
  76. #if defined(AZOTEQ_IQS5XX_TPS43)
  77. # define AZOTEQ_IQS5XX_WIDTH_MM 43
  78. # define AZOTEQ_IQS5XX_HEIGHT_MM 40
  79. # define AZOTEQ_IQS5XX_RESOLUTION_X 2048
  80. # define AZOTEQ_IQS5XX_RESOLUTION_Y 1792
  81. #elif defined(AZOTEQ_IQS5XX_TPS65)
  82. # define AZOTEQ_IQS5XX_WIDTH_MM 65
  83. # define AZOTEQ_IQS5XX_HEIGHT_MM 49
  84. # define AZOTEQ_IQS5XX_RESOLUTION_X 3072
  85. # define AZOTEQ_IQS5XX_RESOLUTION_Y 2048
  86. #elif !defined(AZOTEQ_IQS5XX_WIDTH_MM) && !defined(AZOTEQ_IQS5XX_HEIGHT_MM)
  87. # error "You must define one of the available azoteq trackpads or specify at least the width and height"
  88. #endif
  89. #define DIVIDE_UNSIGNED_ROUND(numerator, denominator) (((numerator) + ((denominator) / 2)) / (denominator))
  90. #define AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_X(inch) (DIVIDE_UNSIGNED_ROUND((inch) * (uint32_t)AZOTEQ_IQS5XX_WIDTH_MM * 10, 254))
  91. #define AZOTEQ_IQS5XX_RESOLUTION_X_TO_INCH(px) (DIVIDE_UNSIGNED_ROUND((px) * (uint32_t)254, AZOTEQ_IQS5XX_WIDTH_MM * 10))
  92. #define AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_Y(inch) (DIVIDE_UNSIGNED_ROUND((inch) * (uint32_t)AZOTEQ_IQS5XX_HEIGHT_MM * 10, 254))
  93. #define AZOTEQ_IQS5XX_RESOLUTION_Y_TO_INCH(px) (DIVIDE_UNSIGNED_ROUND((px) * (uint32_t)254, AZOTEQ_IQS5XX_HEIGHT_MM * 10))
  94. static uint16_t azoteq_iqs5xx_product_number = AZOTEQ_IQS5XX_UNKNOWN;
  95. static struct {
  96. uint16_t resolution_x;
  97. uint16_t resolution_y;
  98. } azoteq_iqs5xx_device_resolution_t;
  99. i2c_status_t azoteq_iqs5xx_wake(void) {
  100. uint8_t data = 0;
  101. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_PREVIOUS_CYCLE_TIME, (uint8_t *)&data, sizeof(data), 1);
  102. wait_us(150);
  103. return status;
  104. }
  105. i2c_status_t azoteq_iqs5xx_end_session(void) {
  106. const uint8_t END_BYTE = 1; // any data
  107. return i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_END_COMMS, &END_BYTE, 1, AZOTEQ_IQS5XX_TIMEOUT_MS);
  108. }
  109. i2c_status_t azoteq_iqs5xx_get_base_data(azoteq_iqs5xx_base_data_t *base_data) {
  110. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_PREVIOUS_CYCLE_TIME, (uint8_t *)base_data, 10, AZOTEQ_IQS5XX_TIMEOUT_MS);
  111. if (status == I2C_STATUS_SUCCESS) {
  112. azoteq_iqs5xx_end_session();
  113. }
  114. return status;
  115. }
  116. i2c_status_t azoteq_iqs5xx_get_report_rate(azoteq_iqs5xx_report_rate_t *report_rate, azoteq_iqs5xx_charging_modes_t mode, bool end_session) {
  117. if (mode > AZOTEQ_IQS5XX_LP2) {
  118. pd_dprintf("IQS5XX - Invalid mode for get report rate.\n");
  119. return I2C_STATUS_ERROR;
  120. }
  121. uint16_t selected_reg = AZOTEQ_IQS5XX_REG_REPORT_RATE_ACTIVE + (2 * mode);
  122. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, selected_reg, (uint8_t *)report_rate, 2, AZOTEQ_IQS5XX_TIMEOUT_MS);
  123. if (end_session) {
  124. azoteq_iqs5xx_end_session();
  125. }
  126. return status;
  127. }
  128. i2c_status_t azoteq_iqs5xx_set_report_rate(uint16_t report_rate_ms, azoteq_iqs5xx_charging_modes_t mode, bool end_session) {
  129. if (mode > AZOTEQ_IQS5XX_LP2) {
  130. pd_dprintf("IQS5XX - Invalid mode for set report rate.\n");
  131. return I2C_STATUS_ERROR;
  132. }
  133. uint16_t selected_reg = AZOTEQ_IQS5XX_REG_REPORT_RATE_ACTIVE + (2 * mode);
  134. azoteq_iqs5xx_report_rate_t report_rate = {0};
  135. report_rate.h = (uint8_t)((report_rate_ms >> 8) & 0xFF);
  136. report_rate.l = (uint8_t)(report_rate_ms & 0xFF);
  137. i2c_status_t status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, selected_reg, (uint8_t *)&report_rate, 2, AZOTEQ_IQS5XX_TIMEOUT_MS);
  138. if (end_session) {
  139. azoteq_iqs5xx_end_session();
  140. }
  141. return status;
  142. }
  143. i2c_status_t azoteq_iqs5xx_set_reati(bool enabled, bool end_session) {
  144. azoteq_iqs5xx_system_config_0_t config = {0};
  145. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  146. if (status == I2C_STATUS_SUCCESS) {
  147. config.reati = enabled;
  148. status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  149. }
  150. if (end_session) {
  151. azoteq_iqs5xx_end_session();
  152. }
  153. return status;
  154. }
  155. i2c_status_t azoteq_iqs5xx_set_event_mode(bool enabled, bool end_session) {
  156. azoteq_iqs5xx_system_config_1_t config = {0};
  157. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  158. if (status == I2C_STATUS_SUCCESS) {
  159. config.event_mode = enabled;
  160. config.touch_event = true;
  161. config.tp_event = true;
  162. config.prox_event = false;
  163. config.snap_event = false;
  164. config.reati_event = false;
  165. config.alp_prox_event = false;
  166. config.gesture_event = true;
  167. status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_config_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  168. }
  169. if (end_session) {
  170. azoteq_iqs5xx_end_session();
  171. }
  172. return status;
  173. }
  174. i2c_status_t azoteq_iqs5xx_set_gesture_config(bool end_session) {
  175. azoteq_iqs5xx_gesture_config_t config = {0};
  176. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SINGLE_FINGER_GESTURES, (uint8_t *)&config, sizeof(azoteq_iqs5xx_gesture_config_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  177. pd_dprintf("azo scroll: %d\n", config.multi_finger_gestures.scroll);
  178. if (status == I2C_STATUS_SUCCESS) {
  179. config.single_finger_gestures.single_tap = AZOTEQ_IQS5XX_TAP_ENABLE;
  180. config.single_finger_gestures.press_and_hold = AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE;
  181. config.single_finger_gestures.swipe_x_plus = AZOTEQ_IQS5XX_SWIPE_X_ENABLE;
  182. config.single_finger_gestures.swipe_x_minus = AZOTEQ_IQS5XX_SWIPE_X_ENABLE;
  183. config.single_finger_gestures.swipe_y_plus = AZOTEQ_IQS5XX_SWIPE_Y_ENABLE;
  184. config.single_finger_gestures.swipe_y_minus = AZOTEQ_IQS5XX_SWIPE_Y_ENABLE;
  185. config.multi_finger_gestures.two_finger_tap = AZOTEQ_IQS5XX_TWO_FINGER_TAP_ENABLE;
  186. config.multi_finger_gestures.scroll = AZOTEQ_IQS5XX_SCROLL_ENABLE;
  187. config.multi_finger_gestures.zoom = AZOTEQ_IQS5XX_ZOOM_ENABLE;
  188. config.tap_time = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_TAP_TIME);
  189. config.tap_distance = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_TAP_DISTANCE);
  190. config.hold_time = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_HOLD_TIME);
  191. config.swipe_initial_time = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SWIPE_INITIAL_TIME);
  192. config.swipe_initial_distance = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SWIPE_INITIAL_DISTANCE);
  193. config.swipe_consecutive_time = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_TIME);
  194. config.swipe_consecutive_distance = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_DISTANCE);
  195. config.scroll_initial_distance = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SCROLL_INITIAL_DISTANCE);
  196. config.zoom_initial_distance = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_ZOOM_INITIAL_DISTANCE);
  197. config.zoom_consecutive_distance = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_ZOOM_CONSECUTIVE_DISTANCE);
  198. status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SINGLE_FINGER_GESTURES, (uint8_t *)&config, sizeof(azoteq_iqs5xx_gesture_config_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  199. }
  200. if (end_session) {
  201. azoteq_iqs5xx_end_session();
  202. }
  203. return status;
  204. }
  205. i2c_status_t azoteq_iqs5xx_set_xy_config(bool flip_x, bool flip_y, bool switch_xy, bool palm_reject, bool end_session) {
  206. azoteq_iqs5xx_xy_config_0_t config = {0};
  207. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_XY_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_xy_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  208. if (status == I2C_STATUS_SUCCESS) {
  209. if (flip_x) {
  210. config.flip_x = !config.flip_x;
  211. }
  212. if (flip_y) {
  213. config.flip_y = !config.flip_y;
  214. }
  215. if (switch_xy) {
  216. config.switch_xy_axis = !config.switch_xy_axis;
  217. }
  218. config.palm_reject = palm_reject;
  219. status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_XY_CONFIG_0, (uint8_t *)&config, sizeof(azoteq_iqs5xx_xy_config_0_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  220. }
  221. if (end_session) {
  222. azoteq_iqs5xx_end_session();
  223. }
  224. return status;
  225. }
  226. i2c_status_t azoteq_iqs5xx_reset_suspend(bool reset, bool suspend, bool end_session) {
  227. azoteq_iqs5xx_system_control_1_t config = {0};
  228. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONTROL_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_control_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  229. if (status == I2C_STATUS_SUCCESS) {
  230. config.reset = reset;
  231. config.suspend = suspend;
  232. status = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_SYSTEM_CONTROL_1, (uint8_t *)&config, sizeof(azoteq_iqs5xx_system_control_1_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  233. }
  234. if (end_session) {
  235. azoteq_iqs5xx_end_session();
  236. }
  237. return status;
  238. }
  239. void azoteq_iqs5xx_set_cpi(uint16_t cpi) {
  240. if (azoteq_iqs5xx_product_number != AZOTEQ_IQS5XX_UNKNOWN) {
  241. azoteq_iqs5xx_resolution_t resolution = {0};
  242. resolution.x_resolution = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(MIN(azoteq_iqs5xx_device_resolution_t.resolution_x, AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_X(cpi)));
  243. resolution.y_resolution = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(MIN(azoteq_iqs5xx_device_resolution_t.resolution_y, AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_Y(cpi)));
  244. i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_X_RESOLUTION, (uint8_t *)&resolution, sizeof(azoteq_iqs5xx_resolution_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  245. }
  246. }
  247. uint16_t azoteq_iqs5xx_get_cpi(void) {
  248. if (azoteq_iqs5xx_product_number != AZOTEQ_IQS5XX_UNKNOWN) {
  249. azoteq_iqs5xx_resolution_t resolution = {0};
  250. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_X_RESOLUTION, (uint8_t *)&resolution, sizeof(azoteq_iqs5xx_resolution_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  251. if (status == I2C_STATUS_SUCCESS) {
  252. return AZOTEQ_IQS5XX_RESOLUTION_X_TO_INCH(AZOTEQ_IQS5XX_SWAP_H_L_BYTES(resolution.x_resolution));
  253. }
  254. }
  255. return 0;
  256. }
  257. uint16_t azoteq_iqs5xx_get_product(void) {
  258. i2c_status_t status = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_PRODUCT_NUMBER, (uint8_t *)&azoteq_iqs5xx_product_number, sizeof(uint16_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
  259. if (status == I2C_STATUS_SUCCESS) {
  260. azoteq_iqs5xx_product_number = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(azoteq_iqs5xx_product_number);
  261. }
  262. pd_dprintf("AZOTEQ: Product number %u\n", azoteq_iqs5xx_product_number);
  263. return azoteq_iqs5xx_product_number;
  264. }
  265. void azoteq_iqs5xx_setup_resolution(void) {
  266. #if !defined(AZOTEQ_IQS5XX_RESOLUTION_X) && !defined(AZOTEQ_IQS5XX_RESOLUTION_Y)
  267. switch (azoteq_iqs5xx_product_number) {
  268. case AZOTEQ_IQS550:
  269. azoteq_iqs5xx_device_resolution_t.resolution_x = 3584;
  270. azoteq_iqs5xx_device_resolution_t.resolution_y = 2304;
  271. break;
  272. case AZOTEQ_IQS572:
  273. azoteq_iqs5xx_device_resolution_t.resolution_x = 2048;
  274. azoteq_iqs5xx_device_resolution_t.resolution_y = 1792;
  275. break;
  276. case AZOTEQ_IQS525:
  277. azoteq_iqs5xx_device_resolution_t.resolution_x = 1280;
  278. azoteq_iqs5xx_device_resolution_t.resolution_y = 768;
  279. break;
  280. default:
  281. // shouldn't be here
  282. azoteq_iqs5xx_device_resolution_t.resolution_x = 0;
  283. azoteq_iqs5xx_device_resolution_t.resolution_y = 0;
  284. break;
  285. }
  286. #endif
  287. #ifdef AZOTEQ_IQS5XX_RESOLUTION_X
  288. azoteq_iqs5xx_device_resolution_t.resolution_x = AZOTEQ_IQS5XX_RESOLUTION_X;
  289. #endif
  290. #ifdef AZOTEQ_IQS5XX_RESOLUTION_Y
  291. azoteq_iqs5xx_device_resolution_t.resolution_y = AZOTEQ_IQS5XX_RESOLUTION_Y;
  292. #endif
  293. }