qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

paw3222.c (4890B)


      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 
     17 #include "paw3222.h"
     18 #include "wait.h"
     19 #include "gpio.h"
     20 #include "spi_master.h"
     21 #include "pointing_device_internal.h"
     22 
     23 #define MSB1 0x80
     24 #define MSB0 0x7F
     25 
     26 const pointing_device_driver_t paw3222_pointing_device_driver = {
     27     .init       = paw3222_init,
     28     .get_report = paw3222_get_report,
     29     .set_cpi    = paw3222_set_cpi,
     30     .get_cpi    = paw3222_get_cpi,
     31 };
     32 
     33 // Convert a 12-bit twos complement binary-represented number into a
     34 // signed 12-bit integer.
     35 static int16_t convert_twoscomp_12(uint16_t data) {
     36     if ((data & 0x800) == 0x800)
     37         return -2048 + (data & 0x7FF);
     38     else
     39         return data;
     40 }
     41 
     42 void paw3222_write(uint8_t reg_addr, uint8_t data) {
     43     spi_start(PAW3222_CS_PIN, false, 3, PAW3222_SPI_DIVISOR);
     44     wait_us(1); // Tncs_lead
     45     spi_write(reg_addr | MSB1);
     46     spi_write(data);
     47     wait_us(1); // Tncs_lag
     48     spi_stop();
     49 }
     50 
     51 uint8_t paw3222_read(uint8_t reg_addr) {
     52     spi_start(PAW3222_CS_PIN, false, 3, PAW3222_SPI_DIVISOR);
     53     wait_us(1); // Tncs_lead
     54     spi_write(reg_addr & MSB0);
     55     wait_us(10); // Tprep_rd
     56     uint8_t data = spi_read();
     57     wait_us(1); // Tncs_lag
     58     spi_stop();
     59 
     60     return data;
     61 }
     62 
     63 bool paw3222_init(void) {
     64     gpio_set_pin_output(PAW3222_CS_PIN);
     65 
     66     // CS must be kept low at power-up stage for at least 1ms
     67     gpio_write_pin_low(PAW3222_CS_PIN);
     68     wait_ms(10);
     69     gpio_write_pin_high(PAW3222_CS_PIN);
     70 
     71     spi_init();
     72 
     73     // reboot
     74     paw3222_write(0x06, 0x80);
     75     wait_ms(50);
     76 
     77     if (!paw3222_check_signature()) {
     78         return false;
     79     }
     80 
     81     // initialize
     82     paw3222_write(0x09, 0x5A);
     83     paw3222_write(0x0D, 0x23);
     84     paw3222_write(0x0E, 0x24);
     85     paw3222_write(0x19, 0x1C);
     86     paw3222_write(0x05, 0xA1);
     87     paw3222_write(0x2B, 0x6D);
     88     paw3222_write(0x30, 0x2E);
     89     paw3222_write(0x5C, 0xDF);
     90     paw3222_write(0x7F, 0x01);
     91     paw3222_write(0x06, 0x14);
     92     paw3222_write(0x31, 0x25);
     93     paw3222_write(0x34, 0xC4);
     94     paw3222_write(0x36, 0xCC);
     95     paw3222_write(0x37, 0x42);
     96     paw3222_write(0x38, 0x01);
     97     paw3222_write(0x3A, 0x76);
     98     paw3222_write(0x3B, 0x34);
     99     paw3222_write(0x42, 0x39);
    100     paw3222_write(0x43, 0xF2);
    101     paw3222_write(0x44, 0x39);
    102     paw3222_write(0x45, 0xF0);
    103     paw3222_write(0x46, 0x12);
    104     paw3222_write(0x47, 0x39);
    105     paw3222_write(0x48, 0xE3);
    106     paw3222_write(0x49, 0x48);
    107     paw3222_write(0x4A, 0xD3);
    108     paw3222_write(0x4B, 0x98);
    109     paw3222_write(0x64, 0x46);
    110     paw3222_write(0x71, 0x28);
    111     paw3222_write(0x72, 0x28);
    112     paw3222_write(0x7F, 0x00);
    113     paw3222_write(0x09, 0x00);
    114 
    115     // read a burst, then discard
    116     paw3222_read_burst();
    117 
    118     return true;
    119 }
    120 
    121 report_paw3222_t paw3222_read_burst(void) {
    122     report_paw3222_t report = {0};
    123 
    124     uint8_t motion = paw3222_read(0x02);
    125     if ((motion & MSB1) == MSB1) {
    126         // Motion detected
    127         uint16_t dx     = (uint16_t)paw3222_read(0x03);
    128         uint16_t dy     = (uint16_t)paw3222_read(0x04);
    129         uint16_t dxy_hi = (uint16_t)paw3222_read(0x12);
    130 
    131         dx = dx | ((dxy_hi & 0xF0) << 4);
    132         dy = dy | ((dxy_hi & 0x0F) << 8);
    133 
    134         report.dx = convert_twoscomp_12(dx);
    135         report.dy = convert_twoscomp_12(dy);
    136     }
    137 
    138     return report;
    139 }
    140 
    141 void paw3222_set_cpi(uint16_t cpi) {
    142     uint16_t cpival   = (cpi) < (480) ? (480) : ((cpi) > (4020) ? (4020) : (cpi));
    143     uint8_t  cpival_x = (cpival + (30 / 2)) / 30;
    144     uint8_t  cpival_y = (cpival + (29 / 2)) / 29;
    145 
    146     paw3222_write(0x09, 0x5A);
    147     paw3222_write(0x0D, cpival_x);
    148     paw3222_write(0x0E, cpival_y);
    149     paw3222_write(0x09, 0x00);
    150 }
    151 
    152 uint16_t paw3222_get_cpi(void) {
    153     uint8_t cpival = paw3222_read(0x0D);
    154     return (uint16_t)(cpival * 30);
    155 }
    156 
    157 report_mouse_t paw3222_get_report(report_mouse_t mouse_report) {
    158     report_paw3222_t data = paw3222_read_burst();
    159 
    160     if (data.dx != 0 || data.dy != 0) {
    161         pd_dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
    162         mouse_report.x = CONSTRAIN_HID_XY(data.dx);
    163         mouse_report.y = CONSTRAIN_HID_XY(data.dy);
    164     }
    165 
    166     return mouse_report;
    167 }
    168 
    169 bool paw3222_check_signature(void) {
    170     uint8_t checkval_1 = paw3222_read(0x00);
    171     uint8_t checkval_2 = paw3222_read(0x01);
    172 
    173     return (checkval_1 == 0x30 && checkval_2 == 0x02);
    174 }