qmk_firmware

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

azoteq_iqs5xx.c (20803B)


      1 // Copyright 2023 Dasky (@daskygit)
      2 // Copyright 2023 George Norton (@george-norton)
      3 // SPDX-License-Identifier: GPL-2.0-or-later
      4 
      5 #include "azoteq_iqs5xx.h"
      6 #include "pointing_device_internal.h"
      7 #include "wait.h"
      8 
      9 #ifndef AZOTEQ_IQS5XX_ADDRESS
     10 #    define AZOTEQ_IQS5XX_ADDRESS (0x74 << 1)
     11 #endif
     12 #ifndef AZOTEQ_IQS5XX_TIMEOUT_MS
     13 #    define AZOTEQ_IQS5XX_TIMEOUT_MS 10
     14 #endif
     15 
     16 #define AZOTEQ_IQS5XX_REG_PRODUCT_NUMBER 0x0000
     17 #define AZOTEQ_IQS5XX_REG_PREVIOUS_CYCLE_TIME 0x000C
     18 #define AZOTEQ_IQS5XX_REG_SYSTEM_CONTROL_1 0x0432
     19 #define AZOTEQ_IQS5XX_REG_REPORT_RATE_ACTIVE 0x057A
     20 #define AZOTEQ_IQS5XX_REG_IDLE_MODE_TIMEOUT 0x0586
     21 #define AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_0 0x058E
     22 #define AZOTEQ_IQS5XX_REG_SYSTEM_CONFIG_1 0x058F
     23 #define AZOTEQ_IQS5XX_REG_X_RESOLUTION 0x066E
     24 #define AZOTEQ_IQS5XX_REG_XY_CONFIG_0 0x0669
     25 #define AZOTEQ_IQS5XX_REG_Y_RESOLUTION 0x0670
     26 #define AZOTEQ_IQS5XX_REG_SINGLE_FINGER_GESTURES 0x06B7
     27 #define AZOTEQ_IQS5XX_REG_END_COMMS 0xEEEE
     28 
     29 // Gesture configuration
     30 #ifndef AZOTEQ_IQS5XX_TAP_ENABLE
     31 #    define AZOTEQ_IQS5XX_TAP_ENABLE true
     32 #endif
     33 #ifndef AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE
     34 #    define AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE false
     35 #endif
     36 #ifndef AZOTEQ_IQS5XX_TWO_FINGER_TAP_ENABLE
     37 #    define AZOTEQ_IQS5XX_TWO_FINGER_TAP_ENABLE true
     38 #endif
     39 #ifndef AZOTEQ_IQS5XX_SCROLL_ENABLE
     40 #    define AZOTEQ_IQS5XX_SCROLL_ENABLE true
     41 #endif
     42 #ifndef AZOTEQ_IQS5XX_SWIPE_X_ENABLE
     43 #    define AZOTEQ_IQS5XX_SWIPE_X_ENABLE false
     44 #endif
     45 #ifndef AZOTEQ_IQS5XX_SWIPE_Y_ENABLE
     46 #    define AZOTEQ_IQS5XX_SWIPE_Y_ENABLE false
     47 #endif
     48 #ifndef AZOTEQ_IQS5XX_ZOOM_ENABLE
     49 #    define AZOTEQ_IQS5XX_ZOOM_ENABLE false
     50 #endif
     51 #ifndef AZOTEQ_IQS5XX_TAP_TIME
     52 #    define AZOTEQ_IQS5XX_TAP_TIME 0x96
     53 #endif
     54 #ifndef AZOTEQ_IQS5XX_TAP_DISTANCE
     55 #    define AZOTEQ_IQS5XX_TAP_DISTANCE 0x19
     56 #endif
     57 #ifndef AZOTEQ_IQS5XX_HOLD_TIME
     58 #    define AZOTEQ_IQS5XX_HOLD_TIME 0x12C
     59 #endif
     60 #ifndef AZOTEQ_IQS5XX_SWIPE_INITIAL_TIME
     61 #    define AZOTEQ_IQS5XX_SWIPE_INITIAL_TIME 0x64 // 0x96
     62 #endif
     63 #ifndef AZOTEQ_IQS5XX_SWIPE_INITIAL_DISTANCE
     64 #    define AZOTEQ_IQS5XX_SWIPE_INITIAL_DISTANCE 0x12C
     65 #endif
     66 #ifndef AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_TIME
     67 #    define AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_TIME 0x0
     68 #endif
     69 #ifndef AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_DISTANCE
     70 #    define AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_DISTANCE 0x7D0
     71 #endif
     72 #ifndef AZOTEQ_IQS5XX_SCROLL_INITIAL_DISTANCE
     73 #    define AZOTEQ_IQS5XX_SCROLL_INITIAL_DISTANCE 0x32
     74 #endif
     75 #ifndef AZOTEQ_IQS5XX_ZOOM_INITIAL_DISTANCE
     76 #    define AZOTEQ_IQS5XX_ZOOM_INITIAL_DISTANCE 0x32
     77 #endif
     78 #ifndef AZOTEQ_IQS5XX_ZOOM_CONSECUTIVE_DISTANCE
     79 #    define AZOTEQ_IQS5XX_ZOOM_CONSECUTIVE_DISTANCE 0x19
     80 #endif
     81 #ifndef AZOTEQ_IQS5XX_EVENT_MODE
     82 // Event mode can't be used until the pointing code has changed (stuck buttons)
     83 #    define AZOTEQ_IQS5XX_EVENT_MODE false
     84 #endif
     85 
     86 #if defined(AZOTEQ_IQS5XX_TPS43)
     87 #    define AZOTEQ_IQS5XX_WIDTH_MM 43
     88 #    define AZOTEQ_IQS5XX_HEIGHT_MM 40
     89 #    define AZOTEQ_IQS5XX_RESOLUTION_X 2048
     90 #    define AZOTEQ_IQS5XX_RESOLUTION_Y 1792
     91 #elif defined(AZOTEQ_IQS5XX_TPS65)
     92 #    define AZOTEQ_IQS5XX_WIDTH_MM 65
     93 #    define AZOTEQ_IQS5XX_HEIGHT_MM 49
     94 #    define AZOTEQ_IQS5XX_RESOLUTION_X 3072
     95 #    define AZOTEQ_IQS5XX_RESOLUTION_Y 2048
     96 #elif !defined(AZOTEQ_IQS5XX_WIDTH_MM) && !defined(AZOTEQ_IQS5XX_HEIGHT_MM)
     97 #    error "You must define one of the available azoteq trackpads or specify at least the width and height"
     98 #endif
     99 
    100 #define DIVIDE_UNSIGNED_ROUND(numerator, denominator) (((numerator) + ((denominator) / 2)) / (denominator))
    101 #define AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_X(inch) (DIVIDE_UNSIGNED_ROUND((inch) * (uint32_t)AZOTEQ_IQS5XX_WIDTH_MM * 10, 254))
    102 #define AZOTEQ_IQS5XX_RESOLUTION_X_TO_INCH(px) (DIVIDE_UNSIGNED_ROUND((px) * (uint32_t)254, AZOTEQ_IQS5XX_WIDTH_MM * 10))
    103 #define AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_Y(inch) (DIVIDE_UNSIGNED_ROUND((inch) * (uint32_t)AZOTEQ_IQS5XX_HEIGHT_MM * 10, 254))
    104 #define AZOTEQ_IQS5XX_RESOLUTION_Y_TO_INCH(px) (DIVIDE_UNSIGNED_ROUND((px) * (uint32_t)254, AZOTEQ_IQS5XX_HEIGHT_MM * 10))
    105 
    106 const pointing_device_driver_t azoteq_iqs5xx_pointing_device_driver = {
    107     .init       = azoteq_iqs5xx_init,
    108     .get_report = azoteq_iqs5xx_get_report,
    109     .set_cpi    = azoteq_iqs5xx_set_cpi,
    110     .get_cpi    = azoteq_iqs5xx_get_cpi,
    111 };
    112 
    113 static uint16_t azoteq_iqs5xx_product_number = AZOTEQ_IQS5XX_UNKNOWN;
    114 
    115 static struct {
    116     uint16_t resolution_x;
    117     uint16_t resolution_y;
    118 } azoteq_iqs5xx_device_resolution_t;
    119 
    120 i2c_status_t azoteq_iqs5xx_end_session(void) {
    121     const uint8_t END_BYTE = 1; // any data
    122     return i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_END_COMMS, &END_BYTE, 1, AZOTEQ_IQS5XX_TIMEOUT_MS);
    123 }
    124 
    125 i2c_status_t azoteq_iqs5xx_get_base_data(azoteq_iqs5xx_base_data_t *base_data) {
    126     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);
    127     if (status == I2C_STATUS_SUCCESS) {
    128         azoteq_iqs5xx_end_session();
    129     }
    130     return status;
    131 }
    132 
    133 i2c_status_t azoteq_iqs5xx_get_report_rate(azoteq_iqs5xx_report_rate_t *report_rate, azoteq_iqs5xx_charging_modes_t mode, bool end_session) {
    134     if (mode > AZOTEQ_IQS5XX_LP2) {
    135         pd_dprintf("IQS5XX - Invalid mode for get report rate.\n");
    136         return I2C_STATUS_ERROR;
    137     }
    138     uint16_t     selected_reg = AZOTEQ_IQS5XX_REG_REPORT_RATE_ACTIVE + (2 * mode);
    139     i2c_status_t status       = i2c_read_register16(AZOTEQ_IQS5XX_ADDRESS, selected_reg, (uint8_t *)report_rate, 2, AZOTEQ_IQS5XX_TIMEOUT_MS);
    140     if (end_session) {
    141         azoteq_iqs5xx_end_session();
    142     }
    143     return status;
    144 }
    145 
    146 i2c_status_t azoteq_iqs5xx_set_report_rate(uint16_t report_rate_ms, azoteq_iqs5xx_charging_modes_t mode, bool end_session) {
    147     if (mode > AZOTEQ_IQS5XX_LP2) {
    148         pd_dprintf("IQS5XX - Invalid mode for set report rate.\n");
    149         return I2C_STATUS_ERROR;
    150     }
    151     uint16_t                    selected_reg = AZOTEQ_IQS5XX_REG_REPORT_RATE_ACTIVE + (2 * mode);
    152     azoteq_iqs5xx_report_rate_t report_rate  = {0};
    153     report_rate.h                            = (uint8_t)((report_rate_ms >> 8) & 0xFF);
    154     report_rate.l                            = (uint8_t)(report_rate_ms & 0xFF);
    155     i2c_status_t status                      = i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, selected_reg, (uint8_t *)&report_rate, 2, AZOTEQ_IQS5XX_TIMEOUT_MS);
    156     if (end_session) {
    157         azoteq_iqs5xx_end_session();
    158     }
    159     return status;
    160 }
    161 
    162 i2c_status_t azoteq_iqs5xx_set_reati(bool enabled, bool end_session) {
    163     azoteq_iqs5xx_system_config_0_t config = {0};
    164     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);
    165     if (status == I2C_STATUS_SUCCESS) {
    166         config.reati = enabled;
    167         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);
    168     }
    169     if (end_session) {
    170         azoteq_iqs5xx_end_session();
    171     }
    172     return status;
    173 }
    174 
    175 i2c_status_t azoteq_iqs5xx_set_event_mode(bool enabled, bool end_session) {
    176     azoteq_iqs5xx_system_config_1_t config = {0};
    177     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);
    178     if (status == I2C_STATUS_SUCCESS) {
    179         config.event_mode     = enabled;
    180         config.touch_event    = true;
    181         config.tp_event       = true;
    182         config.prox_event     = false;
    183         config.snap_event     = false;
    184         config.reati_event    = false;
    185         config.alp_prox_event = false;
    186         config.gesture_event  = true;
    187         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);
    188     }
    189     if (end_session) {
    190         azoteq_iqs5xx_end_session();
    191     }
    192     return status;
    193 }
    194 
    195 i2c_status_t azoteq_iqs5xx_set_gesture_config(bool end_session) {
    196     azoteq_iqs5xx_gesture_config_t config = {0};
    197     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);
    198     pd_dprintf("azo scroll: %d\n", config.multi_finger_gestures.scroll);
    199     if (status == I2C_STATUS_SUCCESS) {
    200         config.single_finger_gestures.single_tap     = AZOTEQ_IQS5XX_TAP_ENABLE;
    201         config.single_finger_gestures.press_and_hold = AZOTEQ_IQS5XX_PRESS_AND_HOLD_ENABLE;
    202         config.single_finger_gestures.swipe_x_plus   = AZOTEQ_IQS5XX_SWIPE_X_ENABLE;
    203         config.single_finger_gestures.swipe_x_minus  = AZOTEQ_IQS5XX_SWIPE_X_ENABLE;
    204         config.single_finger_gestures.swipe_y_plus   = AZOTEQ_IQS5XX_SWIPE_Y_ENABLE;
    205         config.single_finger_gestures.swipe_y_minus  = AZOTEQ_IQS5XX_SWIPE_Y_ENABLE;
    206         config.multi_finger_gestures.two_finger_tap  = AZOTEQ_IQS5XX_TWO_FINGER_TAP_ENABLE;
    207         config.multi_finger_gestures.scroll          = AZOTEQ_IQS5XX_SCROLL_ENABLE;
    208         config.multi_finger_gestures.zoom            = AZOTEQ_IQS5XX_ZOOM_ENABLE;
    209         config.tap_time                              = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_TAP_TIME);
    210         config.tap_distance                          = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_TAP_DISTANCE);
    211         config.hold_time                             = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_HOLD_TIME);
    212         config.swipe_initial_time                    = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SWIPE_INITIAL_TIME);
    213         config.swipe_initial_distance                = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SWIPE_INITIAL_DISTANCE);
    214         config.swipe_consecutive_time                = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_TIME);
    215         config.swipe_consecutive_distance            = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SWIPE_CONSECUTIVE_DISTANCE);
    216         config.scroll_initial_distance               = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_SCROLL_INITIAL_DISTANCE);
    217         config.zoom_initial_distance                 = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_ZOOM_INITIAL_DISTANCE);
    218         config.zoom_consecutive_distance             = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(AZOTEQ_IQS5XX_ZOOM_CONSECUTIVE_DISTANCE);
    219         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);
    220     }
    221     if (end_session) {
    222         azoteq_iqs5xx_end_session();
    223     }
    224     return status;
    225 }
    226 
    227 i2c_status_t azoteq_iqs5xx_set_xy_config(bool flip_x, bool flip_y, bool switch_xy, bool palm_reject, bool end_session) {
    228     azoteq_iqs5xx_xy_config_0_t config = {0};
    229     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);
    230     if (status == I2C_STATUS_SUCCESS) {
    231         if (flip_x) {
    232             config.flip_x = !config.flip_x;
    233         }
    234         if (flip_y) {
    235             config.flip_y = !config.flip_y;
    236         }
    237         if (switch_xy) {
    238             config.switch_xy_axis = !config.switch_xy_axis;
    239         }
    240         config.palm_reject = palm_reject;
    241         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);
    242     }
    243     if (end_session) {
    244         azoteq_iqs5xx_end_session();
    245     }
    246     return status;
    247 }
    248 
    249 i2c_status_t azoteq_iqs5xx_reset_suspend(bool reset, bool suspend, bool end_session) {
    250     azoteq_iqs5xx_system_control_1_t config = {0};
    251     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);
    252     if (status == I2C_STATUS_SUCCESS) {
    253         config.reset   = reset;
    254         config.suspend = suspend;
    255         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);
    256     }
    257     if (end_session) {
    258         azoteq_iqs5xx_end_session();
    259     }
    260     return status;
    261 }
    262 
    263 void azoteq_iqs5xx_set_cpi(uint16_t cpi) {
    264     if (azoteq_iqs5xx_product_number != AZOTEQ_IQS5XX_UNKNOWN) {
    265         azoteq_iqs5xx_resolution_t resolution = {0};
    266         resolution.x_resolution               = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(MIN(azoteq_iqs5xx_device_resolution_t.resolution_x, AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_X(cpi)));
    267         resolution.y_resolution               = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(MIN(azoteq_iqs5xx_device_resolution_t.resolution_y, AZOTEQ_IQS5XX_INCH_TO_RESOLUTION_Y(cpi)));
    268         i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_X_RESOLUTION, (uint8_t *)&resolution, sizeof(azoteq_iqs5xx_resolution_t), AZOTEQ_IQS5XX_TIMEOUT_MS);
    269     }
    270 }
    271 
    272 uint16_t azoteq_iqs5xx_get_cpi(void) {
    273     if (azoteq_iqs5xx_product_number != AZOTEQ_IQS5XX_UNKNOWN) {
    274         azoteq_iqs5xx_resolution_t resolution = {0};
    275         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);
    276         if (status == I2C_STATUS_SUCCESS) {
    277             return AZOTEQ_IQS5XX_RESOLUTION_X_TO_INCH(AZOTEQ_IQS5XX_SWAP_H_L_BYTES(resolution.x_resolution));
    278         }
    279     }
    280     return 0;
    281 }
    282 
    283 uint16_t azoteq_iqs5xx_get_product(void) {
    284     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);
    285     if (status == I2C_STATUS_SUCCESS) {
    286         azoteq_iqs5xx_product_number = AZOTEQ_IQS5XX_SWAP_H_L_BYTES(azoteq_iqs5xx_product_number);
    287     }
    288     pd_dprintf("AZOTEQ: Product number %u\n", azoteq_iqs5xx_product_number);
    289     return azoteq_iqs5xx_product_number;
    290 }
    291 
    292 void azoteq_iqs5xx_setup_resolution(void) {
    293 #if !defined(AZOTEQ_IQS5XX_RESOLUTION_X) && !defined(AZOTEQ_IQS5XX_RESOLUTION_Y)
    294     switch (azoteq_iqs5xx_product_number) {
    295         case AZOTEQ_IQS550:
    296             azoteq_iqs5xx_device_resolution_t.resolution_x = 3584;
    297             azoteq_iqs5xx_device_resolution_t.resolution_y = 2304;
    298             break;
    299         case AZOTEQ_IQS572:
    300             azoteq_iqs5xx_device_resolution_t.resolution_x = 2048;
    301             azoteq_iqs5xx_device_resolution_t.resolution_y = 1792;
    302             break;
    303         case AZOTEQ_IQS525:
    304             azoteq_iqs5xx_device_resolution_t.resolution_x = 1280;
    305             azoteq_iqs5xx_device_resolution_t.resolution_y = 768;
    306             break;
    307         default:
    308             // shouldn't be here
    309             azoteq_iqs5xx_device_resolution_t.resolution_x = 0;
    310             azoteq_iqs5xx_device_resolution_t.resolution_y = 0;
    311             break;
    312     }
    313 #endif
    314 #ifdef AZOTEQ_IQS5XX_RESOLUTION_X
    315     azoteq_iqs5xx_device_resolution_t.resolution_x = AZOTEQ_IQS5XX_RESOLUTION_X;
    316 #endif
    317 #ifdef AZOTEQ_IQS5XX_RESOLUTION_Y
    318     azoteq_iqs5xx_device_resolution_t.resolution_y = AZOTEQ_IQS5XX_RESOLUTION_Y;
    319 #endif
    320 }
    321 
    322 static i2c_status_t azoteq_iqs5xx_init_status = 1;
    323 
    324 bool azoteq_iqs5xx_init(void) {
    325     i2c_init();
    326     i2c_ping_address(AZOTEQ_IQS5XX_ADDRESS, 1); // wake
    327     azoteq_iqs5xx_reset_suspend(true, false, true);
    328     wait_ms(100);
    329     i2c_ping_address(AZOTEQ_IQS5XX_ADDRESS, 1); // wake
    330     if (azoteq_iqs5xx_get_product() != AZOTEQ_IQS5XX_UNKNOWN) {
    331         azoteq_iqs5xx_setup_resolution();
    332         azoteq_iqs5xx_init_status = azoteq_iqs5xx_set_report_rate(AZOTEQ_IQS5XX_REPORT_RATE, AZOTEQ_IQS5XX_ACTIVE, false);
    333         azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_report_rate(AZOTEQ_IQS5XX_REPORT_RATE, AZOTEQ_IQS5XX_IDLE, false);
    334         azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_report_rate(AZOTEQ_IQS5XX_REPORT_RATE, AZOTEQ_IQS5XX_IDLE_TOUCH, false);
    335 
    336         uint8_t no_timeout = 255;
    337         azoteq_iqs5xx_init_status |= i2c_write_register16(AZOTEQ_IQS5XX_ADDRESS, AZOTEQ_IQS5XX_REG_IDLE_MODE_TIMEOUT, &no_timeout, 1, AZOTEQ_IQS5XX_TIMEOUT_MS); // Don't enter LP1, LP2 states
    338         azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_event_mode(AZOTEQ_IQS5XX_EVENT_MODE, false);
    339         azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_reati(true, false);
    340 #if defined(AZOTEQ_IQS5XX_ROTATION_90)
    341         azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(false, true, true, true, false);
    342 #elif defined(AZOTEQ_IQS5XX_ROTATION_180)
    343         azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(true, true, false, true, false);
    344 #elif defined(AZOTEQ_IQS5XX_ROTATION_270)
    345         azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(true, false, true, true, false);
    346 #else
    347         azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_xy_config(false, false, false, true, false);
    348 #endif
    349         azoteq_iqs5xx_init_status |= azoteq_iqs5xx_set_gesture_config(true);
    350         wait_ms(AZOTEQ_IQS5XX_REPORT_RATE + 1);
    351     }
    352 
    353     return azoteq_iqs5xx_init_status == I2C_STATUS_SUCCESS;
    354 };
    355 
    356 report_mouse_t azoteq_iqs5xx_get_report(report_mouse_t mouse_report) {
    357     report_mouse_t temp_report = {0};
    358 
    359     azoteq_iqs5xx_base_data_t base_data       = {0};
    360     i2c_status_t              status          = azoteq_iqs5xx_get_base_data(&base_data);
    361     bool                      ignore_movement = false;
    362 
    363     if (status == I2C_STATUS_SUCCESS) {
    364 #ifdef POINTING_DEVICE_DEBUG
    365         if (base_data.previous_cycle_time > AZOTEQ_IQS5XX_REPORT_RATE) {
    366             pd_dprintf("IQS5XX - previous cycle time missed, took: %dms\n", base_data.previous_cycle_time);
    367         }
    368 #endif
    369         if (base_data.gesture_events_0.single_tap || base_data.gesture_events_0.press_and_hold) {
    370             pd_dprintf("IQS5XX - Single tap/hold.\n");
    371             temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON1);
    372         } else if (base_data.gesture_events_1.two_finger_tap) {
    373             pd_dprintf("IQS5XX - Two finger tap.\n");
    374             temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON2);
    375         } else if (base_data.gesture_events_0.swipe_x_neg) {
    376             pd_dprintf("IQS5XX - X-.\n");
    377             temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON4);
    378             ignore_movement     = true;
    379         } else if (base_data.gesture_events_0.swipe_x_pos) {
    380             pd_dprintf("IQS5XX - X+.\n");
    381             temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON5);
    382             ignore_movement     = true;
    383         } else if (base_data.gesture_events_0.swipe_y_neg) {
    384             pd_dprintf("IQS5XX - Y-.\n");
    385             temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON6);
    386             ignore_movement     = true;
    387         } else if (base_data.gesture_events_0.swipe_y_pos) {
    388             pd_dprintf("IQS5XX - Y+.\n");
    389             temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON3);
    390             ignore_movement     = true;
    391         } else if (base_data.gesture_events_1.zoom) {
    392             if (AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l) < 0) {
    393                 pd_dprintf("IQS5XX - Zoom out.\n");
    394                 temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON7);
    395             } else if (AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l) > 0) {
    396                 pd_dprintf("IQS5XX - Zoom in.\n");
    397                 temp_report.buttons = pointing_device_handle_buttons(temp_report.buttons, true, POINTING_DEVICE_BUTTON8);
    398             }
    399         } else if (base_data.gesture_events_1.scroll) {
    400             pd_dprintf("IQS5XX - Scroll.\n");
    401             temp_report.h = CONSTRAIN_HID(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l));
    402             temp_report.v = CONSTRAIN_HID(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.y.h, base_data.y.l));
    403         }
    404         if (base_data.number_of_fingers == 1 && !ignore_movement) {
    405             temp_report.x = CONSTRAIN_HID_XY(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.x.h, base_data.x.l));
    406             temp_report.y = CONSTRAIN_HID_XY(AZOTEQ_IQS5XX_COMBINE_H_L_BYTES(base_data.y.h, base_data.y.l));
    407         }
    408 
    409     } else {
    410         pd_dprintf("IQS5XX - get report failed, i2c status: %d \n", status);
    411     }
    412 
    413     return temp_report;
    414 }