paw3222.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /* Copyright 2024 Colin Lam (Ploopy Corporation)
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "paw3222.h"
  17. #include "wait.h"
  18. #include "gpio.h"
  19. #include "spi_master.h"
  20. #include "pointing_device_internal.h"
  21. #define MSB1 0x80
  22. #define MSB0 0x7F
  23. const pointing_device_driver_t paw3222_pointing_device_driver = {
  24. .init = paw3222_init,
  25. .get_report = paw3222_get_report,
  26. .set_cpi = paw3222_set_cpi,
  27. .get_cpi = paw3222_get_cpi,
  28. };
  29. // Convert a 12-bit twos complement binary-represented number into a
  30. // signed 12-bit integer.
  31. static int16_t convert_twoscomp_12(uint16_t data) {
  32. if ((data & 0x800) == 0x800)
  33. return -2048 + (data & 0x7FF);
  34. else
  35. return data;
  36. }
  37. void paw3222_write(uint8_t reg_addr, uint8_t data) {
  38. spi_start(PAW3222_CS_PIN, false, 3, PAW3222_SPI_DIVISOR);
  39. wait_us(1); // Tncs_lead
  40. spi_write(reg_addr | MSB1);
  41. spi_write(data);
  42. wait_us(1); // Tncs_lag
  43. spi_stop();
  44. }
  45. uint8_t paw3222_read(uint8_t reg_addr) {
  46. spi_start(PAW3222_CS_PIN, false, 3, PAW3222_SPI_DIVISOR);
  47. wait_us(1); // Tncs_lead
  48. spi_write(reg_addr & MSB0);
  49. wait_us(10); // Tprep_rd
  50. uint8_t data = spi_read();
  51. wait_us(1); // Tncs_lag
  52. spi_stop();
  53. return data;
  54. }
  55. bool paw3222_init(void) {
  56. gpio_set_pin_output(PAW3222_CS_PIN);
  57. // CS must be kept low at power-up stage for at least 1ms
  58. gpio_write_pin_low(PAW3222_CS_PIN);
  59. wait_ms(10);
  60. gpio_write_pin_high(PAW3222_CS_PIN);
  61. spi_init();
  62. // reboot
  63. paw3222_write(0x06, 0x80);
  64. wait_ms(50);
  65. if (!paw3222_check_signature()) {
  66. return false;
  67. }
  68. // initialize
  69. paw3222_write(0x09, 0x5A);
  70. paw3222_write(0x0D, 0x23);
  71. paw3222_write(0x0E, 0x24);
  72. paw3222_write(0x19, 0x1C);
  73. paw3222_write(0x05, 0xA1);
  74. paw3222_write(0x2B, 0x6D);
  75. paw3222_write(0x30, 0x2E);
  76. paw3222_write(0x5C, 0xDF);
  77. paw3222_write(0x7F, 0x01);
  78. paw3222_write(0x06, 0x14);
  79. paw3222_write(0x31, 0x25);
  80. paw3222_write(0x34, 0xC4);
  81. paw3222_write(0x36, 0xCC);
  82. paw3222_write(0x37, 0x42);
  83. paw3222_write(0x38, 0x01);
  84. paw3222_write(0x3A, 0x76);
  85. paw3222_write(0x3B, 0x34);
  86. paw3222_write(0x42, 0x39);
  87. paw3222_write(0x43, 0xF2);
  88. paw3222_write(0x44, 0x39);
  89. paw3222_write(0x45, 0xF0);
  90. paw3222_write(0x46, 0x12);
  91. paw3222_write(0x47, 0x39);
  92. paw3222_write(0x48, 0xE3);
  93. paw3222_write(0x49, 0x48);
  94. paw3222_write(0x4A, 0xD3);
  95. paw3222_write(0x4B, 0x98);
  96. paw3222_write(0x64, 0x46);
  97. paw3222_write(0x71, 0x28);
  98. paw3222_write(0x72, 0x28);
  99. paw3222_write(0x7F, 0x00);
  100. paw3222_write(0x09, 0x00);
  101. // read a burst, then discard
  102. paw3222_read_burst();
  103. return true;
  104. }
  105. report_paw3222_t paw3222_read_burst(void) {
  106. report_paw3222_t report = {0};
  107. uint8_t motion = paw3222_read(0x02);
  108. if ((motion & MSB1) == MSB1) {
  109. // Motion detected
  110. uint16_t dx = (uint16_t)paw3222_read(0x03);
  111. uint16_t dy = (uint16_t)paw3222_read(0x04);
  112. uint16_t dxy_hi = (uint16_t)paw3222_read(0x12);
  113. dx = dx | ((dxy_hi & 0xF0) << 4);
  114. dy = dy | ((dxy_hi & 0x0F) << 8);
  115. report.dx = convert_twoscomp_12(dx);
  116. report.dy = convert_twoscomp_12(dy);
  117. }
  118. return report;
  119. }
  120. void paw3222_set_cpi(uint16_t cpi) {
  121. uint16_t cpival = (cpi) < (480) ? (480) : ((cpi) > (4020) ? (4020) : (cpi));
  122. uint8_t cpival_x = (cpival + (30 / 2)) / 30;
  123. uint8_t cpival_y = (cpival + (29 / 2)) / 29;
  124. paw3222_write(0x09, 0x5A);
  125. paw3222_write(0x0D, cpival_x);
  126. paw3222_write(0x0E, cpival_y);
  127. paw3222_write(0x09, 0x00);
  128. }
  129. uint16_t paw3222_get_cpi(void) {
  130. uint8_t cpival = paw3222_read(0x0D);
  131. return (uint16_t)(cpival * 30);
  132. }
  133. report_mouse_t paw3222_get_report(report_mouse_t mouse_report) {
  134. report_paw3222_t data = paw3222_read_burst();
  135. if (data.dx != 0 || data.dy != 0) {
  136. pd_dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
  137. mouse_report.x = CONSTRAIN_HID_XY(data.dx);
  138. mouse_report.y = CONSTRAIN_HID_XY(data.dy);
  139. }
  140. return mouse_report;
  141. }
  142. bool paw3222_check_signature(void) {
  143. uint8_t checkval_1 = paw3222_read(0x00);
  144. uint8_t checkval_2 = paw3222_read(0x01);
  145. return (checkval_1 == 0x30 && checkval_2 == 0x02);
  146. }