1e505edaeSJeff LaBundy // SPDX-License-Identifier: GPL-2.0-or-later 2e505edaeSJeff LaBundy /* 3e505edaeSJeff LaBundy * Azoteq IQS7222A/B/C Capacitive Touch Controller 4e505edaeSJeff LaBundy * 5e505edaeSJeff LaBundy * Copyright (C) 2022 Jeff LaBundy <jeff@labundy.com> 6e505edaeSJeff LaBundy */ 7e505edaeSJeff LaBundy 8e505edaeSJeff LaBundy #include <linux/bits.h> 9e505edaeSJeff LaBundy #include <linux/delay.h> 10e505edaeSJeff LaBundy #include <linux/device.h> 11e505edaeSJeff LaBundy #include <linux/err.h> 12e505edaeSJeff LaBundy #include <linux/gpio/consumer.h> 13e505edaeSJeff LaBundy #include <linux/i2c.h> 14e505edaeSJeff LaBundy #include <linux/input.h> 15e505edaeSJeff LaBundy #include <linux/interrupt.h> 16e505edaeSJeff LaBundy #include <linux/kernel.h> 17e505edaeSJeff LaBundy #include <linux/ktime.h> 18e505edaeSJeff LaBundy #include <linux/module.h> 19e505edaeSJeff LaBundy #include <linux/of_device.h> 20e505edaeSJeff LaBundy #include <linux/property.h> 21e505edaeSJeff LaBundy #include <linux/slab.h> 22e505edaeSJeff LaBundy #include <asm/unaligned.h> 23e505edaeSJeff LaBundy 24e505edaeSJeff LaBundy #define IQS7222_PROD_NUM 0x00 25e505edaeSJeff LaBundy #define IQS7222_PROD_NUM_A 840 26e505edaeSJeff LaBundy #define IQS7222_PROD_NUM_B 698 27e505edaeSJeff LaBundy #define IQS7222_PROD_NUM_C 863 28e505edaeSJeff LaBundy 29e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS 0x10 30e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS_RESET BIT(3) 31e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS_ATI_ERROR BIT(1) 32e505edaeSJeff LaBundy #define IQS7222_SYS_STATUS_ATI_ACTIVE BIT(0) 33e505edaeSJeff LaBundy 34e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_REF_MODE_MASK GENMASK(15, 14) 35e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW BIT(15) 36e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_REF_MODE_REF BIT(14) 37e505edaeSJeff LaBundy #define IQS7222_CHAN_SETUP_0_CHAN_EN BIT(8) 38e505edaeSJeff LaBundy 39e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK GENMASK(2, 0) 40e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_2_RES_MASK GENMASK(15, 8) 41e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_2_RES_SHIFT 8 42e505edaeSJeff LaBundy #define IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK GENMASK(7, 0) 43e505edaeSJeff LaBundy 44e505edaeSJeff LaBundy #define IQS7222_GPIO_SETUP_0_GPIO_EN BIT(0) 45e505edaeSJeff LaBundy 46e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP 0xD0 47e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_INTF_MODE_MASK GENMASK(7, 6) 48e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_INTF_MODE_TOUCH BIT(7) 49e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_INTF_MODE_EVENT BIT(6) 50e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_PWR_MODE_MASK GENMASK(5, 4) 51e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_PWR_MODE_AUTO IQS7222_SYS_SETUP_PWR_MODE_MASK 52e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_REDO_ATI BIT(2) 53e505edaeSJeff LaBundy #define IQS7222_SYS_SETUP_ACK_RESET BIT(0) 54e505edaeSJeff LaBundy 55e505edaeSJeff LaBundy #define IQS7222_EVENT_MASK_ATI BIT(12) 5695215d3dSJeff LaBundy #define IQS7222_EVENT_MASK_SLDR BIT(10) 5795215d3dSJeff LaBundy #define IQS7222_EVENT_MASK_TOUCH BIT(1) 5895215d3dSJeff LaBundy #define IQS7222_EVENT_MASK_PROX BIT(0) 59e505edaeSJeff LaBundy 60e505edaeSJeff LaBundy #define IQS7222_COMMS_HOLD BIT(0) 61e505edaeSJeff LaBundy #define IQS7222_COMMS_ERROR 0xEEEE 62e505edaeSJeff LaBundy #define IQS7222_COMMS_RETRY_MS 50 63e505edaeSJeff LaBundy #define IQS7222_COMMS_TIMEOUT_MS 100 64e505edaeSJeff LaBundy #define IQS7222_RESET_TIMEOUT_MS 250 65e505edaeSJeff LaBundy #define IQS7222_ATI_TIMEOUT_MS 2000 66e505edaeSJeff LaBundy 67e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_STAT 8 68e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_CYCLE 3 69e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_GLBL 3 70e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_BTN 3 71e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_CHAN 6 72e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_FILT 2 73e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_SLDR 11 74e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_GPIO 3 75e505edaeSJeff LaBundy #define IQS7222_MAX_COLS_SYS 13 76e505edaeSJeff LaBundy 77e505edaeSJeff LaBundy #define IQS7222_MAX_CHAN 20 78e505edaeSJeff LaBundy #define IQS7222_MAX_SLDR 2 79e505edaeSJeff LaBundy 80e505edaeSJeff LaBundy #define IQS7222_NUM_RETRIES 5 81e505edaeSJeff LaBundy #define IQS7222_REG_OFFSET 0x100 82e505edaeSJeff LaBundy 83e505edaeSJeff LaBundy enum iqs7222_reg_key_id { 84e505edaeSJeff LaBundy IQS7222_REG_KEY_NONE, 85e505edaeSJeff LaBundy IQS7222_REG_KEY_PROX, 86e505edaeSJeff LaBundy IQS7222_REG_KEY_TOUCH, 87e505edaeSJeff LaBundy IQS7222_REG_KEY_DEBOUNCE, 88e505edaeSJeff LaBundy IQS7222_REG_KEY_TAP, 898d4c313cSJeff LaBundy IQS7222_REG_KEY_TAP_LEGACY, 90e505edaeSJeff LaBundy IQS7222_REG_KEY_AXIAL, 918d4c313cSJeff LaBundy IQS7222_REG_KEY_AXIAL_LEGACY, 92e505edaeSJeff LaBundy IQS7222_REG_KEY_WHEEL, 93e505edaeSJeff LaBundy IQS7222_REG_KEY_NO_WHEEL, 94e505edaeSJeff LaBundy IQS7222_REG_KEY_RESERVED 95e505edaeSJeff LaBundy }; 96e505edaeSJeff LaBundy 97e505edaeSJeff LaBundy enum iqs7222_reg_grp_id { 98e505edaeSJeff LaBundy IQS7222_REG_GRP_STAT, 992e70ef52SJeff LaBundy IQS7222_REG_GRP_FILT, 100e505edaeSJeff LaBundy IQS7222_REG_GRP_CYCLE, 101e505edaeSJeff LaBundy IQS7222_REG_GRP_GLBL, 102e505edaeSJeff LaBundy IQS7222_REG_GRP_BTN, 103e505edaeSJeff LaBundy IQS7222_REG_GRP_CHAN, 104e505edaeSJeff LaBundy IQS7222_REG_GRP_SLDR, 105e505edaeSJeff LaBundy IQS7222_REG_GRP_GPIO, 106e505edaeSJeff LaBundy IQS7222_REG_GRP_SYS, 107e505edaeSJeff LaBundy IQS7222_NUM_REG_GRPS 108e505edaeSJeff LaBundy }; 109e505edaeSJeff LaBundy 110bbd16b0dSJeff LaBundy static const char * const iqs7222_reg_grp_names[IQS7222_NUM_REG_GRPS] = { 111e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = "cycle", 112e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = "channel", 113e505edaeSJeff LaBundy [IQS7222_REG_GRP_SLDR] = "slider", 114e505edaeSJeff LaBundy [IQS7222_REG_GRP_GPIO] = "gpio", 115e505edaeSJeff LaBundy }; 116e505edaeSJeff LaBundy 117bbd16b0dSJeff LaBundy static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = { 118e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = IQS7222_MAX_COLS_STAT, 119e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = IQS7222_MAX_COLS_CYCLE, 120e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = IQS7222_MAX_COLS_GLBL, 121e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = IQS7222_MAX_COLS_BTN, 122e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN, 123e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT, 124e505edaeSJeff LaBundy [IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR, 125e505edaeSJeff LaBundy [IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO, 126e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS, 127e505edaeSJeff LaBundy }; 128e505edaeSJeff LaBundy 129e505edaeSJeff LaBundy static const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, }; 130e505edaeSJeff LaBundy 131e505edaeSJeff LaBundy struct iqs7222_event_desc { 132e505edaeSJeff LaBundy const char *name; 133e505edaeSJeff LaBundy u16 mask; 134e505edaeSJeff LaBundy u16 val; 135e505edaeSJeff LaBundy u16 enable; 136e505edaeSJeff LaBundy enum iqs7222_reg_key_id reg_key; 137e505edaeSJeff LaBundy }; 138e505edaeSJeff LaBundy 139e505edaeSJeff LaBundy static const struct iqs7222_event_desc iqs7222_kp_events[] = { 140e505edaeSJeff LaBundy { 141e505edaeSJeff LaBundy .name = "event-prox", 14295215d3dSJeff LaBundy .enable = IQS7222_EVENT_MASK_PROX, 143e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_PROX, 144e505edaeSJeff LaBundy }, 145e505edaeSJeff LaBundy { 146e505edaeSJeff LaBundy .name = "event-touch", 14795215d3dSJeff LaBundy .enable = IQS7222_EVENT_MASK_TOUCH, 148e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TOUCH, 149e505edaeSJeff LaBundy }, 150e505edaeSJeff LaBundy }; 151e505edaeSJeff LaBundy 152e505edaeSJeff LaBundy static const struct iqs7222_event_desc iqs7222_sl_events[] = { 153e505edaeSJeff LaBundy { .name = "event-press", }, 154e505edaeSJeff LaBundy { 155e505edaeSJeff LaBundy .name = "event-tap", 156e505edaeSJeff LaBundy .mask = BIT(0), 157e505edaeSJeff LaBundy .val = BIT(0), 158e505edaeSJeff LaBundy .enable = BIT(0), 159e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP, 160e505edaeSJeff LaBundy }, 161e505edaeSJeff LaBundy { 162e505edaeSJeff LaBundy .name = "event-swipe-pos", 163e505edaeSJeff LaBundy .mask = BIT(5) | BIT(1), 164e505edaeSJeff LaBundy .val = BIT(1), 165e505edaeSJeff LaBundy .enable = BIT(1), 166e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL, 167e505edaeSJeff LaBundy }, 168e505edaeSJeff LaBundy { 169e505edaeSJeff LaBundy .name = "event-swipe-neg", 170e505edaeSJeff LaBundy .mask = BIT(5) | BIT(1), 171e505edaeSJeff LaBundy .val = BIT(5) | BIT(1), 172e505edaeSJeff LaBundy .enable = BIT(1), 173e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL, 174e505edaeSJeff LaBundy }, 175e505edaeSJeff LaBundy { 176e505edaeSJeff LaBundy .name = "event-flick-pos", 177e505edaeSJeff LaBundy .mask = BIT(5) | BIT(2), 178e505edaeSJeff LaBundy .val = BIT(2), 179e505edaeSJeff LaBundy .enable = BIT(2), 180e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL, 181e505edaeSJeff LaBundy }, 182e505edaeSJeff LaBundy { 183e505edaeSJeff LaBundy .name = "event-flick-neg", 184e505edaeSJeff LaBundy .mask = BIT(5) | BIT(2), 185e505edaeSJeff LaBundy .val = BIT(5) | BIT(2), 186e505edaeSJeff LaBundy .enable = BIT(2), 187e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL, 188e505edaeSJeff LaBundy }, 189e505edaeSJeff LaBundy }; 190e505edaeSJeff LaBundy 191e505edaeSJeff LaBundy struct iqs7222_reg_grp_desc { 192e505edaeSJeff LaBundy u16 base; 193e505edaeSJeff LaBundy int num_row; 194e505edaeSJeff LaBundy int num_col; 195e505edaeSJeff LaBundy }; 196e505edaeSJeff LaBundy 197e505edaeSJeff LaBundy struct iqs7222_dev_desc { 198e505edaeSJeff LaBundy u16 prod_num; 199e505edaeSJeff LaBundy u16 fw_major; 200e505edaeSJeff LaBundy u16 fw_minor; 201e505edaeSJeff LaBundy u16 sldr_res; 202e505edaeSJeff LaBundy u16 touch_link; 203e505edaeSJeff LaBundy u16 wheel_enable; 204e505edaeSJeff LaBundy int allow_offset; 205e505edaeSJeff LaBundy int event_offset; 206e505edaeSJeff LaBundy int comms_offset; 2078d4c313cSJeff LaBundy bool legacy_gesture; 208e505edaeSJeff LaBundy struct iqs7222_reg_grp_desc reg_grps[IQS7222_NUM_REG_GRPS]; 209e505edaeSJeff LaBundy }; 210e505edaeSJeff LaBundy 211e505edaeSJeff LaBundy static const struct iqs7222_dev_desc iqs7222_devs[] = { 212e505edaeSJeff LaBundy { 213e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_A, 214e505edaeSJeff LaBundy .fw_major = 1, 2158d4c313cSJeff LaBundy .fw_minor = 13, 2168d4c313cSJeff LaBundy .sldr_res = U8_MAX * 16, 2178d4c313cSJeff LaBundy .touch_link = 1768, 2188d4c313cSJeff LaBundy .allow_offset = 9, 2198d4c313cSJeff LaBundy .event_offset = 10, 2208d4c313cSJeff LaBundy .comms_offset = 12, 2218d4c313cSJeff LaBundy .reg_grps = { 2228d4c313cSJeff LaBundy [IQS7222_REG_GRP_STAT] = { 2238d4c313cSJeff LaBundy .base = IQS7222_SYS_STATUS, 2248d4c313cSJeff LaBundy .num_row = 1, 2258d4c313cSJeff LaBundy .num_col = 8, 2268d4c313cSJeff LaBundy }, 2278d4c313cSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = { 2288d4c313cSJeff LaBundy .base = 0x8000, 2298d4c313cSJeff LaBundy .num_row = 7, 2308d4c313cSJeff LaBundy .num_col = 3, 2318d4c313cSJeff LaBundy }, 2328d4c313cSJeff LaBundy [IQS7222_REG_GRP_GLBL] = { 2338d4c313cSJeff LaBundy .base = 0x8700, 2348d4c313cSJeff LaBundy .num_row = 1, 2358d4c313cSJeff LaBundy .num_col = 3, 2368d4c313cSJeff LaBundy }, 2378d4c313cSJeff LaBundy [IQS7222_REG_GRP_BTN] = { 2388d4c313cSJeff LaBundy .base = 0x9000, 2398d4c313cSJeff LaBundy .num_row = 12, 2408d4c313cSJeff LaBundy .num_col = 3, 2418d4c313cSJeff LaBundy }, 2428d4c313cSJeff LaBundy [IQS7222_REG_GRP_CHAN] = { 2438d4c313cSJeff LaBundy .base = 0xA000, 2448d4c313cSJeff LaBundy .num_row = 12, 2458d4c313cSJeff LaBundy .num_col = 6, 2468d4c313cSJeff LaBundy }, 2478d4c313cSJeff LaBundy [IQS7222_REG_GRP_FILT] = { 2488d4c313cSJeff LaBundy .base = 0xAC00, 2498d4c313cSJeff LaBundy .num_row = 1, 2508d4c313cSJeff LaBundy .num_col = 2, 2518d4c313cSJeff LaBundy }, 2528d4c313cSJeff LaBundy [IQS7222_REG_GRP_SLDR] = { 2538d4c313cSJeff LaBundy .base = 0xB000, 2548d4c313cSJeff LaBundy .num_row = 2, 2558d4c313cSJeff LaBundy .num_col = 11, 2568d4c313cSJeff LaBundy }, 2578d4c313cSJeff LaBundy [IQS7222_REG_GRP_GPIO] = { 2588d4c313cSJeff LaBundy .base = 0xC000, 2598d4c313cSJeff LaBundy .num_row = 1, 2608d4c313cSJeff LaBundy .num_col = 3, 2618d4c313cSJeff LaBundy }, 2628d4c313cSJeff LaBundy [IQS7222_REG_GRP_SYS] = { 2638d4c313cSJeff LaBundy .base = IQS7222_SYS_SETUP, 2648d4c313cSJeff LaBundy .num_row = 1, 2658d4c313cSJeff LaBundy .num_col = 13, 2668d4c313cSJeff LaBundy }, 2678d4c313cSJeff LaBundy }, 2688d4c313cSJeff LaBundy }, 2698d4c313cSJeff LaBundy { 2708d4c313cSJeff LaBundy .prod_num = IQS7222_PROD_NUM_A, 2718d4c313cSJeff LaBundy .fw_major = 1, 272e505edaeSJeff LaBundy .fw_minor = 12, 273e505edaeSJeff LaBundy .sldr_res = U8_MAX * 16, 274e505edaeSJeff LaBundy .touch_link = 1768, 275e505edaeSJeff LaBundy .allow_offset = 9, 276e505edaeSJeff LaBundy .event_offset = 10, 277e505edaeSJeff LaBundy .comms_offset = 12, 2788d4c313cSJeff LaBundy .legacy_gesture = true, 279e505edaeSJeff LaBundy .reg_grps = { 280e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = { 281e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS, 282e505edaeSJeff LaBundy .num_row = 1, 283e505edaeSJeff LaBundy .num_col = 8, 284e505edaeSJeff LaBundy }, 285e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = { 286e505edaeSJeff LaBundy .base = 0x8000, 287e505edaeSJeff LaBundy .num_row = 7, 288e505edaeSJeff LaBundy .num_col = 3, 289e505edaeSJeff LaBundy }, 290e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = { 291e505edaeSJeff LaBundy .base = 0x8700, 292e505edaeSJeff LaBundy .num_row = 1, 293e505edaeSJeff LaBundy .num_col = 3, 294e505edaeSJeff LaBundy }, 295e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = { 296e505edaeSJeff LaBundy .base = 0x9000, 297e505edaeSJeff LaBundy .num_row = 12, 298e505edaeSJeff LaBundy .num_col = 3, 299e505edaeSJeff LaBundy }, 300e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = { 301e505edaeSJeff LaBundy .base = 0xA000, 302e505edaeSJeff LaBundy .num_row = 12, 303e505edaeSJeff LaBundy .num_col = 6, 304e505edaeSJeff LaBundy }, 305e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = { 306e505edaeSJeff LaBundy .base = 0xAC00, 307e505edaeSJeff LaBundy .num_row = 1, 308e505edaeSJeff LaBundy .num_col = 2, 309e505edaeSJeff LaBundy }, 310e505edaeSJeff LaBundy [IQS7222_REG_GRP_SLDR] = { 311e505edaeSJeff LaBundy .base = 0xB000, 312e505edaeSJeff LaBundy .num_row = 2, 313e505edaeSJeff LaBundy .num_col = 11, 314e505edaeSJeff LaBundy }, 315e505edaeSJeff LaBundy [IQS7222_REG_GRP_GPIO] = { 316e505edaeSJeff LaBundy .base = 0xC000, 317e505edaeSJeff LaBundy .num_row = 1, 318e505edaeSJeff LaBundy .num_col = 3, 319e505edaeSJeff LaBundy }, 320e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = { 321e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP, 322e505edaeSJeff LaBundy .num_row = 1, 323e505edaeSJeff LaBundy .num_col = 13, 324e505edaeSJeff LaBundy }, 325e505edaeSJeff LaBundy }, 326e505edaeSJeff LaBundy }, 327e505edaeSJeff LaBundy { 328e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_B, 329e505edaeSJeff LaBundy .fw_major = 1, 330e505edaeSJeff LaBundy .fw_minor = 43, 331e505edaeSJeff LaBundy .event_offset = 10, 332e505edaeSJeff LaBundy .comms_offset = 11, 333e505edaeSJeff LaBundy .reg_grps = { 334e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = { 335e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS, 336e505edaeSJeff LaBundy .num_row = 1, 337e505edaeSJeff LaBundy .num_col = 6, 338e505edaeSJeff LaBundy }, 339e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = { 340e505edaeSJeff LaBundy .base = 0x8000, 341e505edaeSJeff LaBundy .num_row = 10, 342e505edaeSJeff LaBundy .num_col = 2, 343e505edaeSJeff LaBundy }, 344e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = { 345e505edaeSJeff LaBundy .base = 0x8A00, 346e505edaeSJeff LaBundy .num_row = 1, 347e505edaeSJeff LaBundy .num_col = 3, 348e505edaeSJeff LaBundy }, 349e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = { 350e505edaeSJeff LaBundy .base = 0x9000, 351e505edaeSJeff LaBundy .num_row = 20, 352e505edaeSJeff LaBundy .num_col = 2, 353e505edaeSJeff LaBundy }, 354e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = { 355e505edaeSJeff LaBundy .base = 0xB000, 356e505edaeSJeff LaBundy .num_row = 20, 357e505edaeSJeff LaBundy .num_col = 4, 358e505edaeSJeff LaBundy }, 359e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = { 360e505edaeSJeff LaBundy .base = 0xC400, 361e505edaeSJeff LaBundy .num_row = 1, 362e505edaeSJeff LaBundy .num_col = 2, 363e505edaeSJeff LaBundy }, 364e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = { 365e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP, 366e505edaeSJeff LaBundy .num_row = 1, 367e505edaeSJeff LaBundy .num_col = 13, 368e505edaeSJeff LaBundy }, 369e505edaeSJeff LaBundy }, 370e505edaeSJeff LaBundy }, 371e505edaeSJeff LaBundy { 372e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_B, 373e505edaeSJeff LaBundy .fw_major = 1, 374e505edaeSJeff LaBundy .fw_minor = 27, 375e505edaeSJeff LaBundy .reg_grps = { 376e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = { 377e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS, 378e505edaeSJeff LaBundy .num_row = 1, 379e505edaeSJeff LaBundy .num_col = 6, 380e505edaeSJeff LaBundy }, 381e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = { 382e505edaeSJeff LaBundy .base = 0x8000, 383e505edaeSJeff LaBundy .num_row = 10, 384e505edaeSJeff LaBundy .num_col = 2, 385e505edaeSJeff LaBundy }, 386e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = { 387e505edaeSJeff LaBundy .base = 0x8A00, 388e505edaeSJeff LaBundy .num_row = 1, 389e505edaeSJeff LaBundy .num_col = 3, 390e505edaeSJeff LaBundy }, 391e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = { 392e505edaeSJeff LaBundy .base = 0x9000, 393e505edaeSJeff LaBundy .num_row = 20, 394e505edaeSJeff LaBundy .num_col = 2, 395e505edaeSJeff LaBundy }, 396e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = { 397e505edaeSJeff LaBundy .base = 0xB000, 398e505edaeSJeff LaBundy .num_row = 20, 399e505edaeSJeff LaBundy .num_col = 4, 400e505edaeSJeff LaBundy }, 401e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = { 402e505edaeSJeff LaBundy .base = 0xC400, 403e505edaeSJeff LaBundy .num_row = 1, 404e505edaeSJeff LaBundy .num_col = 2, 405e505edaeSJeff LaBundy }, 406e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = { 407e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP, 408e505edaeSJeff LaBundy .num_row = 1, 409e505edaeSJeff LaBundy .num_col = 10, 410e505edaeSJeff LaBundy }, 411e505edaeSJeff LaBundy }, 412e505edaeSJeff LaBundy }, 413e505edaeSJeff LaBundy { 414e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_C, 415e505edaeSJeff LaBundy .fw_major = 2, 416e505edaeSJeff LaBundy .fw_minor = 6, 417e505edaeSJeff LaBundy .sldr_res = U16_MAX, 418e505edaeSJeff LaBundy .touch_link = 1686, 419e505edaeSJeff LaBundy .wheel_enable = BIT(3), 420e505edaeSJeff LaBundy .event_offset = 9, 421e505edaeSJeff LaBundy .comms_offset = 10, 422e505edaeSJeff LaBundy .reg_grps = { 423e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = { 424e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS, 425e505edaeSJeff LaBundy .num_row = 1, 426e505edaeSJeff LaBundy .num_col = 6, 427e505edaeSJeff LaBundy }, 428e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = { 429e505edaeSJeff LaBundy .base = 0x8000, 430e505edaeSJeff LaBundy .num_row = 5, 431e505edaeSJeff LaBundy .num_col = 3, 432e505edaeSJeff LaBundy }, 433e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = { 434e505edaeSJeff LaBundy .base = 0x8500, 435e505edaeSJeff LaBundy .num_row = 1, 436e505edaeSJeff LaBundy .num_col = 3, 437e505edaeSJeff LaBundy }, 438e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = { 439e505edaeSJeff LaBundy .base = 0x9000, 440e505edaeSJeff LaBundy .num_row = 10, 441e505edaeSJeff LaBundy .num_col = 3, 442e505edaeSJeff LaBundy }, 443e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = { 444e505edaeSJeff LaBundy .base = 0xA000, 445e505edaeSJeff LaBundy .num_row = 10, 446e505edaeSJeff LaBundy .num_col = 6, 447e505edaeSJeff LaBundy }, 448e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = { 449e505edaeSJeff LaBundy .base = 0xAA00, 450e505edaeSJeff LaBundy .num_row = 1, 451e505edaeSJeff LaBundy .num_col = 2, 452e505edaeSJeff LaBundy }, 453e505edaeSJeff LaBundy [IQS7222_REG_GRP_SLDR] = { 454e505edaeSJeff LaBundy .base = 0xB000, 455e505edaeSJeff LaBundy .num_row = 2, 456e505edaeSJeff LaBundy .num_col = 10, 457e505edaeSJeff LaBundy }, 458e505edaeSJeff LaBundy [IQS7222_REG_GRP_GPIO] = { 459e505edaeSJeff LaBundy .base = 0xC000, 460e505edaeSJeff LaBundy .num_row = 3, 461e505edaeSJeff LaBundy .num_col = 3, 462e505edaeSJeff LaBundy }, 463e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = { 464e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP, 465e505edaeSJeff LaBundy .num_row = 1, 466e505edaeSJeff LaBundy .num_col = 12, 467e505edaeSJeff LaBundy }, 468e505edaeSJeff LaBundy }, 469e505edaeSJeff LaBundy }, 470e505edaeSJeff LaBundy { 471e505edaeSJeff LaBundy .prod_num = IQS7222_PROD_NUM_C, 472e505edaeSJeff LaBundy .fw_major = 1, 473e505edaeSJeff LaBundy .fw_minor = 13, 474e505edaeSJeff LaBundy .sldr_res = U16_MAX, 475e505edaeSJeff LaBundy .touch_link = 1674, 476e505edaeSJeff LaBundy .wheel_enable = BIT(3), 477e505edaeSJeff LaBundy .event_offset = 9, 478e505edaeSJeff LaBundy .comms_offset = 10, 479e505edaeSJeff LaBundy .reg_grps = { 480e505edaeSJeff LaBundy [IQS7222_REG_GRP_STAT] = { 481e505edaeSJeff LaBundy .base = IQS7222_SYS_STATUS, 482e505edaeSJeff LaBundy .num_row = 1, 483e505edaeSJeff LaBundy .num_col = 6, 484e505edaeSJeff LaBundy }, 485e505edaeSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = { 486e505edaeSJeff LaBundy .base = 0x8000, 487e505edaeSJeff LaBundy .num_row = 5, 488e505edaeSJeff LaBundy .num_col = 3, 489e505edaeSJeff LaBundy }, 490e505edaeSJeff LaBundy [IQS7222_REG_GRP_GLBL] = { 491e505edaeSJeff LaBundy .base = 0x8500, 492e505edaeSJeff LaBundy .num_row = 1, 493e505edaeSJeff LaBundy .num_col = 3, 494e505edaeSJeff LaBundy }, 495e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN] = { 496e505edaeSJeff LaBundy .base = 0x9000, 497e505edaeSJeff LaBundy .num_row = 10, 498e505edaeSJeff LaBundy .num_col = 3, 499e505edaeSJeff LaBundy }, 500e505edaeSJeff LaBundy [IQS7222_REG_GRP_CHAN] = { 501e505edaeSJeff LaBundy .base = 0xA000, 502e505edaeSJeff LaBundy .num_row = 10, 503e505edaeSJeff LaBundy .num_col = 6, 504e505edaeSJeff LaBundy }, 505e505edaeSJeff LaBundy [IQS7222_REG_GRP_FILT] = { 506e505edaeSJeff LaBundy .base = 0xAA00, 507e505edaeSJeff LaBundy .num_row = 1, 508e505edaeSJeff LaBundy .num_col = 2, 509e505edaeSJeff LaBundy }, 510e505edaeSJeff LaBundy [IQS7222_REG_GRP_SLDR] = { 511e505edaeSJeff LaBundy .base = 0xB000, 512e505edaeSJeff LaBundy .num_row = 2, 513e505edaeSJeff LaBundy .num_col = 10, 514e505edaeSJeff LaBundy }, 515e505edaeSJeff LaBundy [IQS7222_REG_GRP_GPIO] = { 516e505edaeSJeff LaBundy .base = 0xC000, 517e505edaeSJeff LaBundy .num_row = 1, 518e505edaeSJeff LaBundy .num_col = 3, 519e505edaeSJeff LaBundy }, 520e505edaeSJeff LaBundy [IQS7222_REG_GRP_SYS] = { 521e505edaeSJeff LaBundy .base = IQS7222_SYS_SETUP, 522e505edaeSJeff LaBundy .num_row = 1, 523e505edaeSJeff LaBundy .num_col = 11, 524e505edaeSJeff LaBundy }, 525e505edaeSJeff LaBundy }, 526e505edaeSJeff LaBundy }, 527e505edaeSJeff LaBundy }; 528e505edaeSJeff LaBundy 529e505edaeSJeff LaBundy struct iqs7222_prop_desc { 530e505edaeSJeff LaBundy const char *name; 531e505edaeSJeff LaBundy enum iqs7222_reg_grp_id reg_grp; 532e505edaeSJeff LaBundy enum iqs7222_reg_key_id reg_key; 533e505edaeSJeff LaBundy int reg_offset; 534e505edaeSJeff LaBundy int reg_shift; 535e505edaeSJeff LaBundy int reg_width; 536e505edaeSJeff LaBundy int val_pitch; 537e505edaeSJeff LaBundy int val_min; 538e505edaeSJeff LaBundy int val_max; 539e505edaeSJeff LaBundy bool invert; 540e505edaeSJeff LaBundy const char *label; 541e505edaeSJeff LaBundy }; 542e505edaeSJeff LaBundy 543e505edaeSJeff LaBundy static const struct iqs7222_prop_desc iqs7222_props[] = { 544e505edaeSJeff LaBundy { 545e505edaeSJeff LaBundy .name = "azoteq,conv-period", 546e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 547e505edaeSJeff LaBundy .reg_offset = 0, 548e505edaeSJeff LaBundy .reg_shift = 8, 549e505edaeSJeff LaBundy .reg_width = 8, 550e505edaeSJeff LaBundy .label = "conversion period", 551e505edaeSJeff LaBundy }, 552e505edaeSJeff LaBundy { 553e505edaeSJeff LaBundy .name = "azoteq,conv-frac", 554e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 555e505edaeSJeff LaBundy .reg_offset = 0, 556e505edaeSJeff LaBundy .reg_shift = 0, 557e505edaeSJeff LaBundy .reg_width = 8, 558e505edaeSJeff LaBundy .label = "conversion frequency fractional divider", 559e505edaeSJeff LaBundy }, 560e505edaeSJeff LaBundy { 561e505edaeSJeff LaBundy .name = "azoteq,rx-float-inactive", 562e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 563e505edaeSJeff LaBundy .reg_offset = 1, 564e505edaeSJeff LaBundy .reg_shift = 6, 565e505edaeSJeff LaBundy .reg_width = 1, 566e505edaeSJeff LaBundy .invert = true, 567e505edaeSJeff LaBundy }, 568e505edaeSJeff LaBundy { 569e505edaeSJeff LaBundy .name = "azoteq,dead-time-enable", 570e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 571e505edaeSJeff LaBundy .reg_offset = 1, 572e505edaeSJeff LaBundy .reg_shift = 5, 573e505edaeSJeff LaBundy .reg_width = 1, 574e505edaeSJeff LaBundy }, 575e505edaeSJeff LaBundy { 576e505edaeSJeff LaBundy .name = "azoteq,tx-freq-fosc", 577e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 578e505edaeSJeff LaBundy .reg_offset = 1, 579e505edaeSJeff LaBundy .reg_shift = 4, 580e505edaeSJeff LaBundy .reg_width = 1, 581e505edaeSJeff LaBundy }, 582e505edaeSJeff LaBundy { 583e505edaeSJeff LaBundy .name = "azoteq,vbias-enable", 584e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 585e505edaeSJeff LaBundy .reg_offset = 1, 586e505edaeSJeff LaBundy .reg_shift = 3, 587e505edaeSJeff LaBundy .reg_width = 1, 588e505edaeSJeff LaBundy }, 589e505edaeSJeff LaBundy { 590e505edaeSJeff LaBundy .name = "azoteq,sense-mode", 591e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 592e505edaeSJeff LaBundy .reg_offset = 1, 593e505edaeSJeff LaBundy .reg_shift = 0, 594e505edaeSJeff LaBundy .reg_width = 3, 595e505edaeSJeff LaBundy .val_max = 3, 596e505edaeSJeff LaBundy .label = "sensing mode", 597e505edaeSJeff LaBundy }, 598e505edaeSJeff LaBundy { 599e505edaeSJeff LaBundy .name = "azoteq,iref-enable", 600e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 601e505edaeSJeff LaBundy .reg_offset = 2, 602e505edaeSJeff LaBundy .reg_shift = 10, 603e505edaeSJeff LaBundy .reg_width = 1, 604e505edaeSJeff LaBundy }, 605e505edaeSJeff LaBundy { 606e505edaeSJeff LaBundy .name = "azoteq,iref-level", 607e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 608e505edaeSJeff LaBundy .reg_offset = 2, 609e505edaeSJeff LaBundy .reg_shift = 4, 610e505edaeSJeff LaBundy .reg_width = 4, 611e505edaeSJeff LaBundy .label = "current reference level", 612e505edaeSJeff LaBundy }, 613e505edaeSJeff LaBundy { 614e505edaeSJeff LaBundy .name = "azoteq,iref-trim", 615e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CYCLE, 616e505edaeSJeff LaBundy .reg_offset = 2, 617e505edaeSJeff LaBundy .reg_shift = 0, 618e505edaeSJeff LaBundy .reg_width = 4, 619e505edaeSJeff LaBundy .label = "current reference trim", 620e505edaeSJeff LaBundy }, 621e505edaeSJeff LaBundy { 622e505edaeSJeff LaBundy .name = "azoteq,max-counts", 623e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL, 624e505edaeSJeff LaBundy .reg_offset = 0, 625e505edaeSJeff LaBundy .reg_shift = 13, 626e505edaeSJeff LaBundy .reg_width = 2, 627e505edaeSJeff LaBundy .label = "maximum counts", 628e505edaeSJeff LaBundy }, 629e505edaeSJeff LaBundy { 630e505edaeSJeff LaBundy .name = "azoteq,auto-mode", 631e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL, 632e505edaeSJeff LaBundy .reg_offset = 0, 633e505edaeSJeff LaBundy .reg_shift = 2, 634e505edaeSJeff LaBundy .reg_width = 2, 635e505edaeSJeff LaBundy .label = "number of conversions", 636e505edaeSJeff LaBundy }, 637e505edaeSJeff LaBundy { 638e505edaeSJeff LaBundy .name = "azoteq,ati-frac-div-fine", 639e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL, 640e505edaeSJeff LaBundy .reg_offset = 1, 641e505edaeSJeff LaBundy .reg_shift = 9, 642e505edaeSJeff LaBundy .reg_width = 5, 643e505edaeSJeff LaBundy .label = "ATI fine fractional divider", 644e505edaeSJeff LaBundy }, 645e505edaeSJeff LaBundy { 646e505edaeSJeff LaBundy .name = "azoteq,ati-frac-div-coarse", 647e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL, 648e505edaeSJeff LaBundy .reg_offset = 1, 649e505edaeSJeff LaBundy .reg_shift = 0, 650e505edaeSJeff LaBundy .reg_width = 5, 651e505edaeSJeff LaBundy .label = "ATI coarse fractional divider", 652e505edaeSJeff LaBundy }, 653e505edaeSJeff LaBundy { 654e505edaeSJeff LaBundy .name = "azoteq,ati-comp-select", 655e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GLBL, 656e505edaeSJeff LaBundy .reg_offset = 2, 657e505edaeSJeff LaBundy .reg_shift = 0, 658e505edaeSJeff LaBundy .reg_width = 10, 659e505edaeSJeff LaBundy .label = "ATI compensation selection", 660e505edaeSJeff LaBundy }, 661e505edaeSJeff LaBundy { 662e505edaeSJeff LaBundy .name = "azoteq,ati-band", 663e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 664e505edaeSJeff LaBundy .reg_offset = 0, 665e505edaeSJeff LaBundy .reg_shift = 12, 666e505edaeSJeff LaBundy .reg_width = 2, 667e505edaeSJeff LaBundy .label = "ATI band", 668e505edaeSJeff LaBundy }, 669e505edaeSJeff LaBundy { 670e505edaeSJeff LaBundy .name = "azoteq,global-halt", 671e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 672e505edaeSJeff LaBundy .reg_offset = 0, 673e505edaeSJeff LaBundy .reg_shift = 11, 674e505edaeSJeff LaBundy .reg_width = 1, 675e505edaeSJeff LaBundy }, 676e505edaeSJeff LaBundy { 677e505edaeSJeff LaBundy .name = "azoteq,invert-enable", 678e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 679e505edaeSJeff LaBundy .reg_offset = 0, 680e505edaeSJeff LaBundy .reg_shift = 10, 681e505edaeSJeff LaBundy .reg_width = 1, 682e505edaeSJeff LaBundy }, 683e505edaeSJeff LaBundy { 684e505edaeSJeff LaBundy .name = "azoteq,dual-direction", 685e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 686e505edaeSJeff LaBundy .reg_offset = 0, 687e505edaeSJeff LaBundy .reg_shift = 9, 688e505edaeSJeff LaBundy .reg_width = 1, 689e505edaeSJeff LaBundy }, 690e505edaeSJeff LaBundy { 691e505edaeSJeff LaBundy .name = "azoteq,samp-cap-double", 692e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 693e505edaeSJeff LaBundy .reg_offset = 0, 694e505edaeSJeff LaBundy .reg_shift = 3, 695e505edaeSJeff LaBundy .reg_width = 1, 696e505edaeSJeff LaBundy }, 697e505edaeSJeff LaBundy { 698e505edaeSJeff LaBundy .name = "azoteq,vref-half", 699e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 700e505edaeSJeff LaBundy .reg_offset = 0, 701e505edaeSJeff LaBundy .reg_shift = 2, 702e505edaeSJeff LaBundy .reg_width = 1, 703e505edaeSJeff LaBundy }, 704e505edaeSJeff LaBundy { 705e505edaeSJeff LaBundy .name = "azoteq,proj-bias", 706e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 707e505edaeSJeff LaBundy .reg_offset = 0, 708e505edaeSJeff LaBundy .reg_shift = 0, 709e505edaeSJeff LaBundy .reg_width = 2, 710e505edaeSJeff LaBundy .label = "projected bias current", 711e505edaeSJeff LaBundy }, 712e505edaeSJeff LaBundy { 713e505edaeSJeff LaBundy .name = "azoteq,ati-target", 714e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 715e505edaeSJeff LaBundy .reg_offset = 1, 716e505edaeSJeff LaBundy .reg_shift = 8, 717e505edaeSJeff LaBundy .reg_width = 8, 718e505edaeSJeff LaBundy .val_pitch = 8, 719e505edaeSJeff LaBundy .label = "ATI target", 720e505edaeSJeff LaBundy }, 721e505edaeSJeff LaBundy { 722e505edaeSJeff LaBundy .name = "azoteq,ati-base", 723e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 724e505edaeSJeff LaBundy .reg_offset = 1, 725e505edaeSJeff LaBundy .reg_shift = 3, 726e505edaeSJeff LaBundy .reg_width = 5, 727e505edaeSJeff LaBundy .val_pitch = 16, 728e505edaeSJeff LaBundy .label = "ATI base", 729e505edaeSJeff LaBundy }, 730e505edaeSJeff LaBundy { 731e505edaeSJeff LaBundy .name = "azoteq,ati-mode", 732e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 733e505edaeSJeff LaBundy .reg_offset = 1, 734e505edaeSJeff LaBundy .reg_shift = 0, 735e505edaeSJeff LaBundy .reg_width = 3, 736e505edaeSJeff LaBundy .val_max = 5, 737e505edaeSJeff LaBundy .label = "ATI mode", 738e505edaeSJeff LaBundy }, 739e505edaeSJeff LaBundy { 740e505edaeSJeff LaBundy .name = "azoteq,ati-frac-div-fine", 741e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 742e505edaeSJeff LaBundy .reg_offset = 2, 743e505edaeSJeff LaBundy .reg_shift = 9, 744e505edaeSJeff LaBundy .reg_width = 5, 745e505edaeSJeff LaBundy .label = "ATI fine fractional divider", 746e505edaeSJeff LaBundy }, 747e505edaeSJeff LaBundy { 748e505edaeSJeff LaBundy .name = "azoteq,ati-frac-mult-coarse", 749e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 750e505edaeSJeff LaBundy .reg_offset = 2, 751e505edaeSJeff LaBundy .reg_shift = 5, 752e505edaeSJeff LaBundy .reg_width = 4, 753e505edaeSJeff LaBundy .label = "ATI coarse fractional multiplier", 754e505edaeSJeff LaBundy }, 755e505edaeSJeff LaBundy { 756e505edaeSJeff LaBundy .name = "azoteq,ati-frac-div-coarse", 757e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 758e505edaeSJeff LaBundy .reg_offset = 2, 759e505edaeSJeff LaBundy .reg_shift = 0, 760e505edaeSJeff LaBundy .reg_width = 5, 761e505edaeSJeff LaBundy .label = "ATI coarse fractional divider", 762e505edaeSJeff LaBundy }, 763e505edaeSJeff LaBundy { 764e505edaeSJeff LaBundy .name = "azoteq,ati-comp-div", 765e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 766e505edaeSJeff LaBundy .reg_offset = 3, 767e505edaeSJeff LaBundy .reg_shift = 11, 768e505edaeSJeff LaBundy .reg_width = 5, 769e505edaeSJeff LaBundy .label = "ATI compensation divider", 770e505edaeSJeff LaBundy }, 771e505edaeSJeff LaBundy { 772e505edaeSJeff LaBundy .name = "azoteq,ati-comp-select", 773e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_CHAN, 774e505edaeSJeff LaBundy .reg_offset = 3, 775e505edaeSJeff LaBundy .reg_shift = 0, 776e505edaeSJeff LaBundy .reg_width = 10, 777e505edaeSJeff LaBundy .label = "ATI compensation selection", 778e505edaeSJeff LaBundy }, 779e505edaeSJeff LaBundy { 780e505edaeSJeff LaBundy .name = "azoteq,debounce-exit", 781e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN, 782e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_DEBOUNCE, 783e505edaeSJeff LaBundy .reg_offset = 0, 784e505edaeSJeff LaBundy .reg_shift = 12, 785e505edaeSJeff LaBundy .reg_width = 4, 786e505edaeSJeff LaBundy .label = "debounce exit factor", 787e505edaeSJeff LaBundy }, 788e505edaeSJeff LaBundy { 789e505edaeSJeff LaBundy .name = "azoteq,debounce-enter", 790e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN, 791e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_DEBOUNCE, 792e505edaeSJeff LaBundy .reg_offset = 0, 793e505edaeSJeff LaBundy .reg_shift = 8, 794e505edaeSJeff LaBundy .reg_width = 4, 795e505edaeSJeff LaBundy .label = "debounce entrance factor", 796e505edaeSJeff LaBundy }, 797e505edaeSJeff LaBundy { 798e505edaeSJeff LaBundy .name = "azoteq,thresh", 799e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN, 800e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_PROX, 801e505edaeSJeff LaBundy .reg_offset = 0, 802e505edaeSJeff LaBundy .reg_shift = 0, 803e505edaeSJeff LaBundy .reg_width = 8, 804e505edaeSJeff LaBundy .val_max = 127, 805e505edaeSJeff LaBundy .label = "threshold", 806e505edaeSJeff LaBundy }, 807e505edaeSJeff LaBundy { 808e505edaeSJeff LaBundy .name = "azoteq,thresh", 809e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN, 810e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TOUCH, 811e505edaeSJeff LaBundy .reg_offset = 1, 812e505edaeSJeff LaBundy .reg_shift = 0, 813e505edaeSJeff LaBundy .reg_width = 8, 814e505edaeSJeff LaBundy .label = "threshold", 815e505edaeSJeff LaBundy }, 816e505edaeSJeff LaBundy { 817e505edaeSJeff LaBundy .name = "azoteq,hyst", 818e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_BTN, 819e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TOUCH, 820e505edaeSJeff LaBundy .reg_offset = 1, 821e505edaeSJeff LaBundy .reg_shift = 8, 822e505edaeSJeff LaBundy .reg_width = 8, 823e505edaeSJeff LaBundy .label = "hysteresis", 824e505edaeSJeff LaBundy }, 825e505edaeSJeff LaBundy { 826e505edaeSJeff LaBundy .name = "azoteq,lta-beta-lp", 827e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT, 828e505edaeSJeff LaBundy .reg_offset = 0, 829e505edaeSJeff LaBundy .reg_shift = 12, 830e505edaeSJeff LaBundy .reg_width = 4, 831e505edaeSJeff LaBundy .label = "low-power mode long-term average beta", 832e505edaeSJeff LaBundy }, 833e505edaeSJeff LaBundy { 834e505edaeSJeff LaBundy .name = "azoteq,lta-beta-np", 835e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT, 836e505edaeSJeff LaBundy .reg_offset = 0, 837e505edaeSJeff LaBundy .reg_shift = 8, 838e505edaeSJeff LaBundy .reg_width = 4, 839e505edaeSJeff LaBundy .label = "normal-power mode long-term average beta", 840e505edaeSJeff LaBundy }, 841e505edaeSJeff LaBundy { 842e505edaeSJeff LaBundy .name = "azoteq,counts-beta-lp", 843e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT, 844e505edaeSJeff LaBundy .reg_offset = 0, 845e505edaeSJeff LaBundy .reg_shift = 4, 846e505edaeSJeff LaBundy .reg_width = 4, 847e505edaeSJeff LaBundy .label = "low-power mode counts beta", 848e505edaeSJeff LaBundy }, 849e505edaeSJeff LaBundy { 850e505edaeSJeff LaBundy .name = "azoteq,counts-beta-np", 851e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT, 852e505edaeSJeff LaBundy .reg_offset = 0, 853e505edaeSJeff LaBundy .reg_shift = 0, 854e505edaeSJeff LaBundy .reg_width = 4, 855e505edaeSJeff LaBundy .label = "normal-power mode counts beta", 856e505edaeSJeff LaBundy }, 857e505edaeSJeff LaBundy { 858e505edaeSJeff LaBundy .name = "azoteq,lta-fast-beta-lp", 859e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT, 860e505edaeSJeff LaBundy .reg_offset = 1, 861e505edaeSJeff LaBundy .reg_shift = 4, 862e505edaeSJeff LaBundy .reg_width = 4, 863e505edaeSJeff LaBundy .label = "low-power mode long-term average fast beta", 864e505edaeSJeff LaBundy }, 865e505edaeSJeff LaBundy { 866e505edaeSJeff LaBundy .name = "azoteq,lta-fast-beta-np", 867e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_FILT, 868e505edaeSJeff LaBundy .reg_offset = 1, 869e505edaeSJeff LaBundy .reg_shift = 0, 870e505edaeSJeff LaBundy .reg_width = 4, 871e505edaeSJeff LaBundy .label = "normal-power mode long-term average fast beta", 872e505edaeSJeff LaBundy }, 873e505edaeSJeff LaBundy { 874e505edaeSJeff LaBundy .name = "azoteq,lower-cal", 875e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 876e505edaeSJeff LaBundy .reg_offset = 0, 877e505edaeSJeff LaBundy .reg_shift = 8, 878e505edaeSJeff LaBundy .reg_width = 8, 879e505edaeSJeff LaBundy .label = "lower calibration", 880e505edaeSJeff LaBundy }, 881e505edaeSJeff LaBundy { 882e505edaeSJeff LaBundy .name = "azoteq,static-beta", 883e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 884e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_NO_WHEEL, 885e505edaeSJeff LaBundy .reg_offset = 0, 886e505edaeSJeff LaBundy .reg_shift = 6, 887e505edaeSJeff LaBundy .reg_width = 1, 888e505edaeSJeff LaBundy }, 889e505edaeSJeff LaBundy { 890e505edaeSJeff LaBundy .name = "azoteq,bottom-beta", 891e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 892e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_NO_WHEEL, 893e505edaeSJeff LaBundy .reg_offset = 0, 894e505edaeSJeff LaBundy .reg_shift = 3, 895e505edaeSJeff LaBundy .reg_width = 3, 896e505edaeSJeff LaBundy .label = "bottom beta", 897e505edaeSJeff LaBundy }, 898e505edaeSJeff LaBundy { 899e505edaeSJeff LaBundy .name = "azoteq,static-beta", 900e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 901e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_WHEEL, 902e505edaeSJeff LaBundy .reg_offset = 0, 903e505edaeSJeff LaBundy .reg_shift = 7, 904e505edaeSJeff LaBundy .reg_width = 1, 905e505edaeSJeff LaBundy }, 906e505edaeSJeff LaBundy { 907e505edaeSJeff LaBundy .name = "azoteq,bottom-beta", 908e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 909e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_WHEEL, 910e505edaeSJeff LaBundy .reg_offset = 0, 911e505edaeSJeff LaBundy .reg_shift = 4, 912e505edaeSJeff LaBundy .reg_width = 3, 913e505edaeSJeff LaBundy .label = "bottom beta", 914e505edaeSJeff LaBundy }, 915e505edaeSJeff LaBundy { 916e505edaeSJeff LaBundy .name = "azoteq,bottom-speed", 917e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 918e505edaeSJeff LaBundy .reg_offset = 1, 919e505edaeSJeff LaBundy .reg_shift = 8, 920e505edaeSJeff LaBundy .reg_width = 8, 921e505edaeSJeff LaBundy .label = "bottom speed", 922e505edaeSJeff LaBundy }, 923e505edaeSJeff LaBundy { 924e505edaeSJeff LaBundy .name = "azoteq,upper-cal", 925e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 926e505edaeSJeff LaBundy .reg_offset = 1, 927e505edaeSJeff LaBundy .reg_shift = 0, 928e505edaeSJeff LaBundy .reg_width = 8, 929e505edaeSJeff LaBundy .label = "upper calibration", 930e505edaeSJeff LaBundy }, 931e505edaeSJeff LaBundy { 932e505edaeSJeff LaBundy .name = "azoteq,gesture-max-ms", 933e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 934e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP, 935e505edaeSJeff LaBundy .reg_offset = 9, 936e505edaeSJeff LaBundy .reg_shift = 8, 937e505edaeSJeff LaBundy .reg_width = 8, 9388d4c313cSJeff LaBundy .val_pitch = 16, 9398d4c313cSJeff LaBundy .label = "maximum gesture time", 9408d4c313cSJeff LaBundy }, 9418d4c313cSJeff LaBundy { 9428d4c313cSJeff LaBundy .name = "azoteq,gesture-max-ms", 9438d4c313cSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 9448d4c313cSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP_LEGACY, 9458d4c313cSJeff LaBundy .reg_offset = 9, 9468d4c313cSJeff LaBundy .reg_shift = 8, 9478d4c313cSJeff LaBundy .reg_width = 8, 948e505edaeSJeff LaBundy .val_pitch = 4, 949e505edaeSJeff LaBundy .label = "maximum gesture time", 950e505edaeSJeff LaBundy }, 951e505edaeSJeff LaBundy { 952e505edaeSJeff LaBundy .name = "azoteq,gesture-min-ms", 953e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 954e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP, 955e505edaeSJeff LaBundy .reg_offset = 9, 956e505edaeSJeff LaBundy .reg_shift = 3, 957e505edaeSJeff LaBundy .reg_width = 5, 9588d4c313cSJeff LaBundy .val_pitch = 16, 9598d4c313cSJeff LaBundy .label = "minimum gesture time", 9608d4c313cSJeff LaBundy }, 9618d4c313cSJeff LaBundy { 9628d4c313cSJeff LaBundy .name = "azoteq,gesture-min-ms", 9638d4c313cSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 9648d4c313cSJeff LaBundy .reg_key = IQS7222_REG_KEY_TAP_LEGACY, 9658d4c313cSJeff LaBundy .reg_offset = 9, 9668d4c313cSJeff LaBundy .reg_shift = 3, 9678d4c313cSJeff LaBundy .reg_width = 5, 968e505edaeSJeff LaBundy .val_pitch = 4, 969e505edaeSJeff LaBundy .label = "minimum gesture time", 970e505edaeSJeff LaBundy }, 971e505edaeSJeff LaBundy { 972e505edaeSJeff LaBundy .name = "azoteq,gesture-dist", 973e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 974e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL, 975e505edaeSJeff LaBundy .reg_offset = 10, 976e505edaeSJeff LaBundy .reg_shift = 8, 977e505edaeSJeff LaBundy .reg_width = 8, 978e505edaeSJeff LaBundy .val_pitch = 16, 979e505edaeSJeff LaBundy .label = "gesture distance", 980e505edaeSJeff LaBundy }, 981e505edaeSJeff LaBundy { 9828d4c313cSJeff LaBundy .name = "azoteq,gesture-dist", 9838d4c313cSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 9848d4c313cSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL_LEGACY, 9858d4c313cSJeff LaBundy .reg_offset = 10, 9868d4c313cSJeff LaBundy .reg_shift = 8, 9878d4c313cSJeff LaBundy .reg_width = 8, 9888d4c313cSJeff LaBundy .val_pitch = 16, 9898d4c313cSJeff LaBundy .label = "gesture distance", 9908d4c313cSJeff LaBundy }, 9918d4c313cSJeff LaBundy { 992e505edaeSJeff LaBundy .name = "azoteq,gesture-max-ms", 993e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 994e505edaeSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL, 995e505edaeSJeff LaBundy .reg_offset = 10, 996e505edaeSJeff LaBundy .reg_shift = 0, 997e505edaeSJeff LaBundy .reg_width = 8, 9988d4c313cSJeff LaBundy .val_pitch = 16, 9998d4c313cSJeff LaBundy .label = "maximum gesture time", 10008d4c313cSJeff LaBundy }, 10018d4c313cSJeff LaBundy { 10028d4c313cSJeff LaBundy .name = "azoteq,gesture-max-ms", 10038d4c313cSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SLDR, 10048d4c313cSJeff LaBundy .reg_key = IQS7222_REG_KEY_AXIAL_LEGACY, 10058d4c313cSJeff LaBundy .reg_offset = 10, 10068d4c313cSJeff LaBundy .reg_shift = 0, 10078d4c313cSJeff LaBundy .reg_width = 8, 1008e505edaeSJeff LaBundy .val_pitch = 4, 1009e505edaeSJeff LaBundy .label = "maximum gesture time", 1010e505edaeSJeff LaBundy }, 1011e505edaeSJeff LaBundy { 1012e505edaeSJeff LaBundy .name = "drive-open-drain", 1013e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_GPIO, 1014e505edaeSJeff LaBundy .reg_offset = 0, 1015e505edaeSJeff LaBundy .reg_shift = 1, 1016e505edaeSJeff LaBundy .reg_width = 1, 1017e505edaeSJeff LaBundy }, 1018e505edaeSJeff LaBundy { 1019e505edaeSJeff LaBundy .name = "azoteq,timeout-ati-ms", 1020e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS, 1021e505edaeSJeff LaBundy .reg_offset = 1, 1022e505edaeSJeff LaBundy .reg_shift = 0, 1023e505edaeSJeff LaBundy .reg_width = 16, 1024e505edaeSJeff LaBundy .val_pitch = 500, 1025e505edaeSJeff LaBundy .label = "ATI error timeout", 1026e505edaeSJeff LaBundy }, 1027e505edaeSJeff LaBundy { 1028e505edaeSJeff LaBundy .name = "azoteq,rate-ati-ms", 1029e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS, 1030e505edaeSJeff LaBundy .reg_offset = 2, 1031e505edaeSJeff LaBundy .reg_shift = 0, 1032e505edaeSJeff LaBundy .reg_width = 16, 1033e505edaeSJeff LaBundy .label = "ATI report rate", 1034e505edaeSJeff LaBundy }, 1035e505edaeSJeff LaBundy { 1036e505edaeSJeff LaBundy .name = "azoteq,timeout-np-ms", 1037e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS, 1038e505edaeSJeff LaBundy .reg_offset = 3, 1039e505edaeSJeff LaBundy .reg_shift = 0, 1040e505edaeSJeff LaBundy .reg_width = 16, 1041e505edaeSJeff LaBundy .label = "normal-power mode timeout", 1042e505edaeSJeff LaBundy }, 1043e505edaeSJeff LaBundy { 1044e505edaeSJeff LaBundy .name = "azoteq,rate-np-ms", 1045e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS, 1046e505edaeSJeff LaBundy .reg_offset = 4, 1047e505edaeSJeff LaBundy .reg_shift = 0, 1048e505edaeSJeff LaBundy .reg_width = 16, 1049e505edaeSJeff LaBundy .val_max = 3000, 1050e505edaeSJeff LaBundy .label = "normal-power mode report rate", 1051e505edaeSJeff LaBundy }, 1052e505edaeSJeff LaBundy { 1053e505edaeSJeff LaBundy .name = "azoteq,timeout-lp-ms", 1054e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS, 1055e505edaeSJeff LaBundy .reg_offset = 5, 1056e505edaeSJeff LaBundy .reg_shift = 0, 1057e505edaeSJeff LaBundy .reg_width = 16, 1058e505edaeSJeff LaBundy .label = "low-power mode timeout", 1059e505edaeSJeff LaBundy }, 1060e505edaeSJeff LaBundy { 1061e505edaeSJeff LaBundy .name = "azoteq,rate-lp-ms", 1062e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS, 1063e505edaeSJeff LaBundy .reg_offset = 6, 1064e505edaeSJeff LaBundy .reg_shift = 0, 1065e505edaeSJeff LaBundy .reg_width = 16, 1066e505edaeSJeff LaBundy .val_max = 3000, 1067e505edaeSJeff LaBundy .label = "low-power mode report rate", 1068e505edaeSJeff LaBundy }, 1069e505edaeSJeff LaBundy { 1070e505edaeSJeff LaBundy .name = "azoteq,timeout-ulp-ms", 1071e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS, 1072e505edaeSJeff LaBundy .reg_offset = 7, 1073e505edaeSJeff LaBundy .reg_shift = 0, 1074e505edaeSJeff LaBundy .reg_width = 16, 1075e505edaeSJeff LaBundy .label = "ultra-low-power mode timeout", 1076e505edaeSJeff LaBundy }, 1077e505edaeSJeff LaBundy { 1078e505edaeSJeff LaBundy .name = "azoteq,rate-ulp-ms", 1079e505edaeSJeff LaBundy .reg_grp = IQS7222_REG_GRP_SYS, 1080e505edaeSJeff LaBundy .reg_offset = 8, 1081e505edaeSJeff LaBundy .reg_shift = 0, 1082e505edaeSJeff LaBundy .reg_width = 16, 1083e505edaeSJeff LaBundy .val_max = 3000, 1084e505edaeSJeff LaBundy .label = "ultra-low-power mode report rate", 1085e505edaeSJeff LaBundy }, 1086e505edaeSJeff LaBundy }; 1087e505edaeSJeff LaBundy 1088e505edaeSJeff LaBundy struct iqs7222_private { 1089e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc; 1090e505edaeSJeff LaBundy struct gpio_desc *reset_gpio; 1091e505edaeSJeff LaBundy struct gpio_desc *irq_gpio; 1092e505edaeSJeff LaBundy struct i2c_client *client; 1093e505edaeSJeff LaBundy struct input_dev *keypad; 1094e505edaeSJeff LaBundy unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)]; 1095e505edaeSJeff LaBundy unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)]; 1096e505edaeSJeff LaBundy unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)]; 1097e505edaeSJeff LaBundy unsigned int sl_axis[IQS7222_MAX_SLDR]; 1098e505edaeSJeff LaBundy u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE]; 1099e505edaeSJeff LaBundy u16 glbl_setup[IQS7222_MAX_COLS_GLBL]; 1100e505edaeSJeff LaBundy u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN]; 1101e505edaeSJeff LaBundy u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN]; 1102e505edaeSJeff LaBundy u16 filt_setup[IQS7222_MAX_COLS_FILT]; 1103e505edaeSJeff LaBundy u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR]; 1104e505edaeSJeff LaBundy u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO]; 1105e505edaeSJeff LaBundy u16 sys_setup[IQS7222_MAX_COLS_SYS]; 1106e505edaeSJeff LaBundy }; 1107e505edaeSJeff LaBundy 1108e505edaeSJeff LaBundy static u16 *iqs7222_setup(struct iqs7222_private *iqs7222, 1109e505edaeSJeff LaBundy enum iqs7222_reg_grp_id reg_grp, int row) 1110e505edaeSJeff LaBundy { 1111e505edaeSJeff LaBundy switch (reg_grp) { 1112e505edaeSJeff LaBundy case IQS7222_REG_GRP_CYCLE: 1113e505edaeSJeff LaBundy return iqs7222->cycle_setup[row]; 1114e505edaeSJeff LaBundy 1115e505edaeSJeff LaBundy case IQS7222_REG_GRP_GLBL: 1116e505edaeSJeff LaBundy return iqs7222->glbl_setup; 1117e505edaeSJeff LaBundy 1118e505edaeSJeff LaBundy case IQS7222_REG_GRP_BTN: 1119e505edaeSJeff LaBundy return iqs7222->btn_setup[row]; 1120e505edaeSJeff LaBundy 1121e505edaeSJeff LaBundy case IQS7222_REG_GRP_CHAN: 1122e505edaeSJeff LaBundy return iqs7222->chan_setup[row]; 1123e505edaeSJeff LaBundy 1124e505edaeSJeff LaBundy case IQS7222_REG_GRP_FILT: 1125e505edaeSJeff LaBundy return iqs7222->filt_setup; 1126e505edaeSJeff LaBundy 1127e505edaeSJeff LaBundy case IQS7222_REG_GRP_SLDR: 1128e505edaeSJeff LaBundy return iqs7222->sldr_setup[row]; 1129e505edaeSJeff LaBundy 1130e505edaeSJeff LaBundy case IQS7222_REG_GRP_GPIO: 1131e505edaeSJeff LaBundy return iqs7222->gpio_setup[row]; 1132e505edaeSJeff LaBundy 1133e505edaeSJeff LaBundy case IQS7222_REG_GRP_SYS: 1134e505edaeSJeff LaBundy return iqs7222->sys_setup; 1135e505edaeSJeff LaBundy 1136e505edaeSJeff LaBundy default: 1137e505edaeSJeff LaBundy return NULL; 1138e505edaeSJeff LaBundy } 1139e505edaeSJeff LaBundy } 1140e505edaeSJeff LaBundy 1141e505edaeSJeff LaBundy static int iqs7222_irq_poll(struct iqs7222_private *iqs7222, u16 timeout_ms) 1142e505edaeSJeff LaBundy { 1143e505edaeSJeff LaBundy ktime_t irq_timeout = ktime_add_ms(ktime_get(), timeout_ms); 1144e505edaeSJeff LaBundy int ret; 1145e505edaeSJeff LaBundy 1146e505edaeSJeff LaBundy do { 1147e505edaeSJeff LaBundy usleep_range(1000, 1100); 1148e505edaeSJeff LaBundy 1149e505edaeSJeff LaBundy ret = gpiod_get_value_cansleep(iqs7222->irq_gpio); 1150e505edaeSJeff LaBundy if (ret < 0) 1151e505edaeSJeff LaBundy return ret; 1152e505edaeSJeff LaBundy else if (ret > 0) 1153e505edaeSJeff LaBundy return 0; 1154e505edaeSJeff LaBundy } while (ktime_compare(ktime_get(), irq_timeout) < 0); 1155e505edaeSJeff LaBundy 1156e505edaeSJeff LaBundy return -EBUSY; 1157e505edaeSJeff LaBundy } 1158e505edaeSJeff LaBundy 1159e505edaeSJeff LaBundy static int iqs7222_hard_reset(struct iqs7222_private *iqs7222) 1160e505edaeSJeff LaBundy { 1161e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 1162e505edaeSJeff LaBundy int error; 1163e505edaeSJeff LaBundy 1164e505edaeSJeff LaBundy if (!iqs7222->reset_gpio) 1165e505edaeSJeff LaBundy return 0; 1166e505edaeSJeff LaBundy 1167e505edaeSJeff LaBundy gpiod_set_value_cansleep(iqs7222->reset_gpio, 1); 1168e505edaeSJeff LaBundy usleep_range(1000, 1100); 1169e505edaeSJeff LaBundy 1170e505edaeSJeff LaBundy gpiod_set_value_cansleep(iqs7222->reset_gpio, 0); 1171e505edaeSJeff LaBundy 1172e505edaeSJeff LaBundy error = iqs7222_irq_poll(iqs7222, IQS7222_RESET_TIMEOUT_MS); 1173e505edaeSJeff LaBundy if (error) 1174e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to reset device: %d\n", error); 1175e505edaeSJeff LaBundy 1176e505edaeSJeff LaBundy return error; 1177e505edaeSJeff LaBundy } 1178e505edaeSJeff LaBundy 1179e505edaeSJeff LaBundy static int iqs7222_force_comms(struct iqs7222_private *iqs7222) 1180e505edaeSJeff LaBundy { 118110e629d3SJeff LaBundy u8 msg_buf[] = { 0xFF, }; 1182e505edaeSJeff LaBundy int ret; 1183e505edaeSJeff LaBundy 1184e505edaeSJeff LaBundy /* 1185e505edaeSJeff LaBundy * The device cannot communicate until it asserts its interrupt (RDY) 1186e505edaeSJeff LaBundy * pin. Attempts to do so while RDY is deasserted return an ACK; how- 1187e505edaeSJeff LaBundy * ever all write data is ignored, and all read data returns 0xEE. 1188e505edaeSJeff LaBundy * 1189e505edaeSJeff LaBundy * Unsolicited communication must be preceded by a special force com- 1190e505edaeSJeff LaBundy * munication command, after which the device eventually asserts its 1191e505edaeSJeff LaBundy * RDY pin and agrees to communicate. 1192e505edaeSJeff LaBundy * 1193e505edaeSJeff LaBundy * Regardless of whether communication is forced or the result of an 1194e505edaeSJeff LaBundy * interrupt, the device automatically deasserts its RDY pin once it 1195e505edaeSJeff LaBundy * detects an I2C stop condition, or a timeout expires. 1196e505edaeSJeff LaBundy */ 1197e505edaeSJeff LaBundy ret = gpiod_get_value_cansleep(iqs7222->irq_gpio); 1198e505edaeSJeff LaBundy if (ret < 0) 1199e505edaeSJeff LaBundy return ret; 1200e505edaeSJeff LaBundy else if (ret > 0) 1201e505edaeSJeff LaBundy return 0; 1202e505edaeSJeff LaBundy 1203e505edaeSJeff LaBundy ret = i2c_master_send(iqs7222->client, msg_buf, sizeof(msg_buf)); 1204e505edaeSJeff LaBundy if (ret < (int)sizeof(msg_buf)) { 1205e505edaeSJeff LaBundy if (ret >= 0) 1206e505edaeSJeff LaBundy ret = -EIO; 1207e505edaeSJeff LaBundy 1208e505edaeSJeff LaBundy /* 1209e505edaeSJeff LaBundy * The datasheet states that the host must wait to retry any 1210e505edaeSJeff LaBundy * failed attempt to communicate over I2C. 1211e505edaeSJeff LaBundy */ 1212e505edaeSJeff LaBundy msleep(IQS7222_COMMS_RETRY_MS); 1213e505edaeSJeff LaBundy return ret; 1214e505edaeSJeff LaBundy } 1215e505edaeSJeff LaBundy 1216e505edaeSJeff LaBundy return iqs7222_irq_poll(iqs7222, IQS7222_COMMS_TIMEOUT_MS); 1217e505edaeSJeff LaBundy } 1218e505edaeSJeff LaBundy 1219e505edaeSJeff LaBundy static int iqs7222_read_burst(struct iqs7222_private *iqs7222, 1220e505edaeSJeff LaBundy u16 reg, void *val, u16 num_val) 1221e505edaeSJeff LaBundy { 1222e505edaeSJeff LaBundy u8 reg_buf[sizeof(__be16)]; 1223e505edaeSJeff LaBundy int ret, i; 1224e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 1225e505edaeSJeff LaBundy struct i2c_msg msg[] = { 1226e505edaeSJeff LaBundy { 1227e505edaeSJeff LaBundy .addr = client->addr, 1228e505edaeSJeff LaBundy .flags = 0, 1229e505edaeSJeff LaBundy .len = reg > U8_MAX ? sizeof(reg) : sizeof(u8), 1230e505edaeSJeff LaBundy .buf = reg_buf, 1231e505edaeSJeff LaBundy }, 1232e505edaeSJeff LaBundy { 1233e505edaeSJeff LaBundy .addr = client->addr, 1234e505edaeSJeff LaBundy .flags = I2C_M_RD, 1235e505edaeSJeff LaBundy .len = num_val * sizeof(__le16), 1236e505edaeSJeff LaBundy .buf = (u8 *)val, 1237e505edaeSJeff LaBundy }, 1238e505edaeSJeff LaBundy }; 1239e505edaeSJeff LaBundy 1240e505edaeSJeff LaBundy if (reg > U8_MAX) 1241e505edaeSJeff LaBundy put_unaligned_be16(reg, reg_buf); 1242e505edaeSJeff LaBundy else 1243e505edaeSJeff LaBundy *reg_buf = (u8)reg; 1244e505edaeSJeff LaBundy 1245e505edaeSJeff LaBundy /* 1246e505edaeSJeff LaBundy * The following loop protects against an edge case in which the RDY 1247e505edaeSJeff LaBundy * pin is automatically deasserted just as the read is initiated. In 1248e505edaeSJeff LaBundy * that case, the read must be retried using forced communication. 1249e505edaeSJeff LaBundy */ 1250e505edaeSJeff LaBundy for (i = 0; i < IQS7222_NUM_RETRIES; i++) { 1251e505edaeSJeff LaBundy ret = iqs7222_force_comms(iqs7222); 1252e505edaeSJeff LaBundy if (ret < 0) 1253e505edaeSJeff LaBundy continue; 1254e505edaeSJeff LaBundy 1255e505edaeSJeff LaBundy ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); 1256e505edaeSJeff LaBundy if (ret < (int)ARRAY_SIZE(msg)) { 1257e505edaeSJeff LaBundy if (ret >= 0) 1258e505edaeSJeff LaBundy ret = -EIO; 1259e505edaeSJeff LaBundy 1260e505edaeSJeff LaBundy msleep(IQS7222_COMMS_RETRY_MS); 1261e505edaeSJeff LaBundy continue; 1262e505edaeSJeff LaBundy } 1263e505edaeSJeff LaBundy 1264e505edaeSJeff LaBundy if (get_unaligned_le16(msg[1].buf) == IQS7222_COMMS_ERROR) { 1265e505edaeSJeff LaBundy ret = -ENODATA; 1266e505edaeSJeff LaBundy continue; 1267e505edaeSJeff LaBundy } 1268e505edaeSJeff LaBundy 1269e505edaeSJeff LaBundy ret = 0; 1270e505edaeSJeff LaBundy break; 1271e505edaeSJeff LaBundy } 1272e505edaeSJeff LaBundy 1273e505edaeSJeff LaBundy /* 1274e505edaeSJeff LaBundy * The following delay ensures the device has deasserted the RDY pin 1275e505edaeSJeff LaBundy * following the I2C stop condition. 1276e505edaeSJeff LaBundy */ 1277e505edaeSJeff LaBundy usleep_range(50, 100); 1278e505edaeSJeff LaBundy 1279e505edaeSJeff LaBundy if (ret < 0) 1280e505edaeSJeff LaBundy dev_err(&client->dev, 1281e505edaeSJeff LaBundy "Failed to read from address 0x%04X: %d\n", reg, ret); 1282e505edaeSJeff LaBundy 1283e505edaeSJeff LaBundy return ret; 1284e505edaeSJeff LaBundy } 1285e505edaeSJeff LaBundy 1286e505edaeSJeff LaBundy static int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val) 1287e505edaeSJeff LaBundy { 1288e505edaeSJeff LaBundy __le16 val_buf; 1289e505edaeSJeff LaBundy int error; 1290e505edaeSJeff LaBundy 1291e505edaeSJeff LaBundy error = iqs7222_read_burst(iqs7222, reg, &val_buf, 1); 1292e505edaeSJeff LaBundy if (error) 1293e505edaeSJeff LaBundy return error; 1294e505edaeSJeff LaBundy 1295e505edaeSJeff LaBundy *val = le16_to_cpu(val_buf); 1296e505edaeSJeff LaBundy 1297e505edaeSJeff LaBundy return 0; 1298e505edaeSJeff LaBundy } 1299e505edaeSJeff LaBundy 1300e505edaeSJeff LaBundy static int iqs7222_write_burst(struct iqs7222_private *iqs7222, 1301e505edaeSJeff LaBundy u16 reg, const void *val, u16 num_val) 1302e505edaeSJeff LaBundy { 1303e505edaeSJeff LaBundy int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8); 1304e505edaeSJeff LaBundy int val_len = num_val * sizeof(__le16); 1305e505edaeSJeff LaBundy int msg_len = reg_len + val_len; 1306e505edaeSJeff LaBundy int ret, i; 1307e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 1308e505edaeSJeff LaBundy u8 *msg_buf; 1309e505edaeSJeff LaBundy 1310e505edaeSJeff LaBundy msg_buf = kzalloc(msg_len, GFP_KERNEL); 1311e505edaeSJeff LaBundy if (!msg_buf) 1312e505edaeSJeff LaBundy return -ENOMEM; 1313e505edaeSJeff LaBundy 1314e505edaeSJeff LaBundy if (reg > U8_MAX) 1315e505edaeSJeff LaBundy put_unaligned_be16(reg, msg_buf); 1316e505edaeSJeff LaBundy else 1317e505edaeSJeff LaBundy *msg_buf = (u8)reg; 1318e505edaeSJeff LaBundy 1319e505edaeSJeff LaBundy memcpy(msg_buf + reg_len, val, val_len); 1320e505edaeSJeff LaBundy 1321e505edaeSJeff LaBundy /* 1322e505edaeSJeff LaBundy * The following loop protects against an edge case in which the RDY 1323e505edaeSJeff LaBundy * pin is automatically asserted just before the force communication 1324e505edaeSJeff LaBundy * command is sent. 1325e505edaeSJeff LaBundy * 1326e505edaeSJeff LaBundy * In that case, the subsequent I2C stop condition tricks the device 1327e505edaeSJeff LaBundy * into preemptively deasserting the RDY pin and the command must be 1328e505edaeSJeff LaBundy * sent again. 1329e505edaeSJeff LaBundy */ 1330e505edaeSJeff LaBundy for (i = 0; i < IQS7222_NUM_RETRIES; i++) { 1331e505edaeSJeff LaBundy ret = iqs7222_force_comms(iqs7222); 1332e505edaeSJeff LaBundy if (ret < 0) 1333e505edaeSJeff LaBundy continue; 1334e505edaeSJeff LaBundy 1335e505edaeSJeff LaBundy ret = i2c_master_send(client, msg_buf, msg_len); 1336e505edaeSJeff LaBundy if (ret < msg_len) { 1337e505edaeSJeff LaBundy if (ret >= 0) 1338e505edaeSJeff LaBundy ret = -EIO; 1339e505edaeSJeff LaBundy 1340e505edaeSJeff LaBundy msleep(IQS7222_COMMS_RETRY_MS); 1341e505edaeSJeff LaBundy continue; 1342e505edaeSJeff LaBundy } 1343e505edaeSJeff LaBundy 1344e505edaeSJeff LaBundy ret = 0; 1345e505edaeSJeff LaBundy break; 1346e505edaeSJeff LaBundy } 1347e505edaeSJeff LaBundy 1348e505edaeSJeff LaBundy kfree(msg_buf); 1349e505edaeSJeff LaBundy 1350e505edaeSJeff LaBundy usleep_range(50, 100); 1351e505edaeSJeff LaBundy 1352e505edaeSJeff LaBundy if (ret < 0) 1353e505edaeSJeff LaBundy dev_err(&client->dev, 1354e505edaeSJeff LaBundy "Failed to write to address 0x%04X: %d\n", reg, ret); 1355e505edaeSJeff LaBundy 1356e505edaeSJeff LaBundy return ret; 1357e505edaeSJeff LaBundy } 1358e505edaeSJeff LaBundy 1359e505edaeSJeff LaBundy static int iqs7222_write_word(struct iqs7222_private *iqs7222, u16 reg, u16 val) 1360e505edaeSJeff LaBundy { 1361e505edaeSJeff LaBundy __le16 val_buf = cpu_to_le16(val); 1362e505edaeSJeff LaBundy 1363e505edaeSJeff LaBundy return iqs7222_write_burst(iqs7222, reg, &val_buf, 1); 1364e505edaeSJeff LaBundy } 1365e505edaeSJeff LaBundy 1366e505edaeSJeff LaBundy static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222) 1367e505edaeSJeff LaBundy { 1368e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 1369e505edaeSJeff LaBundy ktime_t ati_timeout; 1370e505edaeSJeff LaBundy u16 sys_status = 0; 13711e4189d8SJeff LaBundy u16 sys_setup; 1372e505edaeSJeff LaBundy int error, i; 1373e505edaeSJeff LaBundy 13741e4189d8SJeff LaBundy /* 13751e4189d8SJeff LaBundy * The reserved fields of the system setup register may have changed 13761e4189d8SJeff LaBundy * as a result of other registers having been written. As such, read 13771e4189d8SJeff LaBundy * the register's latest value to avoid unexpected behavior when the 13781e4189d8SJeff LaBundy * register is written in the loop that follows. 13791e4189d8SJeff LaBundy */ 13801e4189d8SJeff LaBundy error = iqs7222_read_word(iqs7222, IQS7222_SYS_SETUP, &sys_setup); 13811e4189d8SJeff LaBundy if (error) 13821e4189d8SJeff LaBundy return error; 13831e4189d8SJeff LaBundy 1384e505edaeSJeff LaBundy for (i = 0; i < IQS7222_NUM_RETRIES; i++) { 1385e505edaeSJeff LaBundy /* 1386e505edaeSJeff LaBundy * Trigger ATI from streaming and normal-power modes so that 1387e505edaeSJeff LaBundy * the RDY pin continues to be asserted during ATI. 1388e505edaeSJeff LaBundy */ 1389e505edaeSJeff LaBundy error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP, 1390e505edaeSJeff LaBundy sys_setup | 1391e505edaeSJeff LaBundy IQS7222_SYS_SETUP_REDO_ATI); 1392e505edaeSJeff LaBundy if (error) 1393e505edaeSJeff LaBundy return error; 1394e505edaeSJeff LaBundy 1395e505edaeSJeff LaBundy ati_timeout = ktime_add_ms(ktime_get(), IQS7222_ATI_TIMEOUT_MS); 1396e505edaeSJeff LaBundy 1397e505edaeSJeff LaBundy do { 1398e505edaeSJeff LaBundy error = iqs7222_irq_poll(iqs7222, 1399e505edaeSJeff LaBundy IQS7222_COMMS_TIMEOUT_MS); 1400e505edaeSJeff LaBundy if (error) 1401e505edaeSJeff LaBundy continue; 1402e505edaeSJeff LaBundy 1403e505edaeSJeff LaBundy error = iqs7222_read_word(iqs7222, IQS7222_SYS_STATUS, 1404e505edaeSJeff LaBundy &sys_status); 1405e505edaeSJeff LaBundy if (error) 1406e505edaeSJeff LaBundy return error; 1407e505edaeSJeff LaBundy 14088635c688SJeff LaBundy if (sys_status & IQS7222_SYS_STATUS_RESET) 14098635c688SJeff LaBundy return 0; 1410e505edaeSJeff LaBundy 1411e505edaeSJeff LaBundy if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR) 1412e505edaeSJeff LaBundy break; 1413e505edaeSJeff LaBundy 14148635c688SJeff LaBundy if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE) 14158635c688SJeff LaBundy continue; 14168635c688SJeff LaBundy 1417e505edaeSJeff LaBundy /* 1418e505edaeSJeff LaBundy * Use stream-in-touch mode if either slider reports 1419e505edaeSJeff LaBundy * absolute position. 1420e505edaeSJeff LaBundy */ 1421e505edaeSJeff LaBundy sys_setup |= test_bit(EV_ABS, iqs7222->keypad->evbit) 1422e505edaeSJeff LaBundy ? IQS7222_SYS_SETUP_INTF_MODE_TOUCH 1423e505edaeSJeff LaBundy : IQS7222_SYS_SETUP_INTF_MODE_EVENT; 1424e505edaeSJeff LaBundy sys_setup |= IQS7222_SYS_SETUP_PWR_MODE_AUTO; 1425e505edaeSJeff LaBundy 1426e505edaeSJeff LaBundy return iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP, 1427e505edaeSJeff LaBundy sys_setup); 1428e505edaeSJeff LaBundy } while (ktime_compare(ktime_get(), ati_timeout) < 0); 1429e505edaeSJeff LaBundy 1430e505edaeSJeff LaBundy dev_err(&client->dev, 1431e505edaeSJeff LaBundy "ATI attempt %d of %d failed with status 0x%02X, %s\n", 1432e505edaeSJeff LaBundy i + 1, IQS7222_NUM_RETRIES, (u8)sys_status, 14338635c688SJeff LaBundy i + 1 < IQS7222_NUM_RETRIES ? "retrying" : "stopping"); 1434e505edaeSJeff LaBundy } 1435e505edaeSJeff LaBundy 1436e505edaeSJeff LaBundy return -ETIMEDOUT; 1437e505edaeSJeff LaBundy } 1438e505edaeSJeff LaBundy 1439e505edaeSJeff LaBundy static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir) 1440e505edaeSJeff LaBundy { 1441e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 1442e505edaeSJeff LaBundy int comms_offset = dev_desc->comms_offset; 1443e505edaeSJeff LaBundy int error, i, j, k; 1444e505edaeSJeff LaBundy 1445e505edaeSJeff LaBundy /* 14462e70ef52SJeff LaBundy * Acknowledge reset before writing any registers in case the device 14472e70ef52SJeff LaBundy * suffers a spurious reset during initialization. Because this step 14482e70ef52SJeff LaBundy * may change the reserved fields of the second filter beta register, 14492e70ef52SJeff LaBundy * its cache must be updated. 14502e70ef52SJeff LaBundy * 14512e70ef52SJeff LaBundy * Writing the second filter beta register, in turn, may clobber the 14522e70ef52SJeff LaBundy * system status register. As such, the filter beta register pair is 14532e70ef52SJeff LaBundy * written first to protect against this hazard. 14542e70ef52SJeff LaBundy */ 14552e70ef52SJeff LaBundy if (dir == WRITE) { 14562e70ef52SJeff LaBundy u16 reg = dev_desc->reg_grps[IQS7222_REG_GRP_FILT].base + 1; 14572e70ef52SJeff LaBundy u16 filt_setup; 14582e70ef52SJeff LaBundy 14592e70ef52SJeff LaBundy error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP, 14602e70ef52SJeff LaBundy iqs7222->sys_setup[0] | 14612e70ef52SJeff LaBundy IQS7222_SYS_SETUP_ACK_RESET); 14622e70ef52SJeff LaBundy if (error) 14632e70ef52SJeff LaBundy return error; 14642e70ef52SJeff LaBundy 14652e70ef52SJeff LaBundy error = iqs7222_read_word(iqs7222, reg, &filt_setup); 14662e70ef52SJeff LaBundy if (error) 14672e70ef52SJeff LaBundy return error; 14682e70ef52SJeff LaBundy 14692e70ef52SJeff LaBundy iqs7222->filt_setup[1] &= GENMASK(7, 0); 14702e70ef52SJeff LaBundy iqs7222->filt_setup[1] |= (filt_setup & ~GENMASK(7, 0)); 14712e70ef52SJeff LaBundy } 14722e70ef52SJeff LaBundy 14732e70ef52SJeff LaBundy /* 1474e505edaeSJeff LaBundy * Take advantage of the stop-bit disable function, if available, to 1475e505edaeSJeff LaBundy * save the trouble of having to reopen a communication window after 1476e505edaeSJeff LaBundy * each burst read or write. 1477e505edaeSJeff LaBundy */ 1478e505edaeSJeff LaBundy if (comms_offset) { 1479e505edaeSJeff LaBundy u16 comms_setup; 1480e505edaeSJeff LaBundy 1481e505edaeSJeff LaBundy error = iqs7222_read_word(iqs7222, 1482e505edaeSJeff LaBundy IQS7222_SYS_SETUP + comms_offset, 1483e505edaeSJeff LaBundy &comms_setup); 1484e505edaeSJeff LaBundy if (error) 1485e505edaeSJeff LaBundy return error; 1486e505edaeSJeff LaBundy 1487e505edaeSJeff LaBundy error = iqs7222_write_word(iqs7222, 1488e505edaeSJeff LaBundy IQS7222_SYS_SETUP + comms_offset, 1489e505edaeSJeff LaBundy comms_setup | IQS7222_COMMS_HOLD); 1490e505edaeSJeff LaBundy if (error) 1491e505edaeSJeff LaBundy return error; 1492e505edaeSJeff LaBundy } 1493e505edaeSJeff LaBundy 1494e505edaeSJeff LaBundy for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) { 1495e505edaeSJeff LaBundy int num_row = dev_desc->reg_grps[i].num_row; 1496e505edaeSJeff LaBundy int num_col = dev_desc->reg_grps[i].num_col; 1497e505edaeSJeff LaBundy u16 reg = dev_desc->reg_grps[i].base; 1498e505edaeSJeff LaBundy __le16 *val_buf; 1499e505edaeSJeff LaBundy u16 *val; 1500e505edaeSJeff LaBundy 1501e505edaeSJeff LaBundy if (!num_col) 1502e505edaeSJeff LaBundy continue; 1503e505edaeSJeff LaBundy 1504e505edaeSJeff LaBundy val = iqs7222_setup(iqs7222, i, 0); 1505e505edaeSJeff LaBundy if (!val) 1506e505edaeSJeff LaBundy continue; 1507e505edaeSJeff LaBundy 1508e505edaeSJeff LaBundy val_buf = kcalloc(num_col, sizeof(__le16), GFP_KERNEL); 1509e505edaeSJeff LaBundy if (!val_buf) 1510e505edaeSJeff LaBundy return -ENOMEM; 1511e505edaeSJeff LaBundy 1512e505edaeSJeff LaBundy for (j = 0; j < num_row; j++) { 1513e505edaeSJeff LaBundy switch (dir) { 1514e505edaeSJeff LaBundy case READ: 1515e505edaeSJeff LaBundy error = iqs7222_read_burst(iqs7222, reg, 1516e505edaeSJeff LaBundy val_buf, num_col); 1517e505edaeSJeff LaBundy for (k = 0; k < num_col; k++) 1518e505edaeSJeff LaBundy val[k] = le16_to_cpu(val_buf[k]); 1519e505edaeSJeff LaBundy break; 1520e505edaeSJeff LaBundy 1521e505edaeSJeff LaBundy case WRITE: 1522e505edaeSJeff LaBundy for (k = 0; k < num_col; k++) 1523e505edaeSJeff LaBundy val_buf[k] = cpu_to_le16(val[k]); 1524e505edaeSJeff LaBundy error = iqs7222_write_burst(iqs7222, reg, 1525e505edaeSJeff LaBundy val_buf, num_col); 1526e505edaeSJeff LaBundy break; 1527e505edaeSJeff LaBundy 1528e505edaeSJeff LaBundy default: 1529e505edaeSJeff LaBundy error = -EINVAL; 1530e505edaeSJeff LaBundy } 1531e505edaeSJeff LaBundy 1532e505edaeSJeff LaBundy if (error) 1533e505edaeSJeff LaBundy break; 1534e505edaeSJeff LaBundy 1535e505edaeSJeff LaBundy reg += IQS7222_REG_OFFSET; 1536e505edaeSJeff LaBundy val += iqs7222_max_cols[i]; 1537e505edaeSJeff LaBundy } 1538e505edaeSJeff LaBundy 1539e505edaeSJeff LaBundy kfree(val_buf); 1540e505edaeSJeff LaBundy 1541e505edaeSJeff LaBundy if (error) 1542e505edaeSJeff LaBundy return error; 1543e505edaeSJeff LaBundy } 1544e505edaeSJeff LaBundy 1545e505edaeSJeff LaBundy if (comms_offset) { 1546e505edaeSJeff LaBundy u16 comms_setup; 1547e505edaeSJeff LaBundy 1548e505edaeSJeff LaBundy error = iqs7222_read_word(iqs7222, 1549e505edaeSJeff LaBundy IQS7222_SYS_SETUP + comms_offset, 1550e505edaeSJeff LaBundy &comms_setup); 1551e505edaeSJeff LaBundy if (error) 1552e505edaeSJeff LaBundy return error; 1553e505edaeSJeff LaBundy 1554e505edaeSJeff LaBundy error = iqs7222_write_word(iqs7222, 1555e505edaeSJeff LaBundy IQS7222_SYS_SETUP + comms_offset, 1556e505edaeSJeff LaBundy comms_setup & ~IQS7222_COMMS_HOLD); 1557e505edaeSJeff LaBundy if (error) 1558e505edaeSJeff LaBundy return error; 1559e505edaeSJeff LaBundy } 1560e505edaeSJeff LaBundy 1561*2e00b8bfSJeff LaBundy if (dir == READ) { 1562*2e00b8bfSJeff LaBundy iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK; 1563*2e00b8bfSJeff LaBundy iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK; 1564e505edaeSJeff LaBundy return 0; 1565*2e00b8bfSJeff LaBundy } 1566e505edaeSJeff LaBundy 1567e505edaeSJeff LaBundy return iqs7222_ati_trigger(iqs7222); 1568e505edaeSJeff LaBundy } 1569e505edaeSJeff LaBundy 1570e505edaeSJeff LaBundy static int iqs7222_dev_info(struct iqs7222_private *iqs7222) 1571e505edaeSJeff LaBundy { 1572e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 1573e505edaeSJeff LaBundy bool prod_num_valid = false; 1574e505edaeSJeff LaBundy __le16 dev_id[3]; 1575e505edaeSJeff LaBundy int error, i; 1576e505edaeSJeff LaBundy 1577e505edaeSJeff LaBundy error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id, 1578e505edaeSJeff LaBundy ARRAY_SIZE(dev_id)); 1579e505edaeSJeff LaBundy if (error) 1580e505edaeSJeff LaBundy return error; 1581e505edaeSJeff LaBundy 1582e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_devs); i++) { 1583e505edaeSJeff LaBundy if (le16_to_cpu(dev_id[0]) != iqs7222_devs[i].prod_num) 1584e505edaeSJeff LaBundy continue; 1585e505edaeSJeff LaBundy 1586e505edaeSJeff LaBundy prod_num_valid = true; 1587e505edaeSJeff LaBundy 1588e505edaeSJeff LaBundy if (le16_to_cpu(dev_id[1]) < iqs7222_devs[i].fw_major) 1589e505edaeSJeff LaBundy continue; 1590e505edaeSJeff LaBundy 1591e505edaeSJeff LaBundy if (le16_to_cpu(dev_id[2]) < iqs7222_devs[i].fw_minor) 1592e505edaeSJeff LaBundy continue; 1593e505edaeSJeff LaBundy 1594e505edaeSJeff LaBundy iqs7222->dev_desc = &iqs7222_devs[i]; 1595e505edaeSJeff LaBundy return 0; 1596e505edaeSJeff LaBundy } 1597e505edaeSJeff LaBundy 1598e505edaeSJeff LaBundy if (prod_num_valid) 1599e505edaeSJeff LaBundy dev_err(&client->dev, "Unsupported firmware revision: %u.%u\n", 1600e505edaeSJeff LaBundy le16_to_cpu(dev_id[1]), le16_to_cpu(dev_id[2])); 1601e505edaeSJeff LaBundy else 1602e505edaeSJeff LaBundy dev_err(&client->dev, "Unrecognized product number: %u\n", 1603e505edaeSJeff LaBundy le16_to_cpu(dev_id[0])); 1604e505edaeSJeff LaBundy 1605e505edaeSJeff LaBundy return -EINVAL; 1606e505edaeSJeff LaBundy } 1607e505edaeSJeff LaBundy 1608e505edaeSJeff LaBundy static int iqs7222_gpio_select(struct iqs7222_private *iqs7222, 1609e505edaeSJeff LaBundy struct fwnode_handle *child_node, 1610e505edaeSJeff LaBundy int child_enable, u16 child_link) 1611e505edaeSJeff LaBundy { 1612e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 1613e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 1614e505edaeSJeff LaBundy int num_gpio = dev_desc->reg_grps[IQS7222_REG_GRP_GPIO].num_row; 1615e505edaeSJeff LaBundy int error, count, i; 1616e505edaeSJeff LaBundy unsigned int gpio_sel[ARRAY_SIZE(iqs7222_gpio_links)]; 1617e505edaeSJeff LaBundy 1618e505edaeSJeff LaBundy if (!num_gpio) 1619e505edaeSJeff LaBundy return 0; 1620e505edaeSJeff LaBundy 1621e505edaeSJeff LaBundy if (!fwnode_property_present(child_node, "azoteq,gpio-select")) 1622e505edaeSJeff LaBundy return 0; 1623e505edaeSJeff LaBundy 1624e505edaeSJeff LaBundy count = fwnode_property_count_u32(child_node, "azoteq,gpio-select"); 1625e505edaeSJeff LaBundy if (count > num_gpio) { 1626e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid number of %s GPIOs\n", 1627e505edaeSJeff LaBundy fwnode_get_name(child_node)); 1628e505edaeSJeff LaBundy return -EINVAL; 1629e505edaeSJeff LaBundy } else if (count < 0) { 1630e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to count %s GPIOs: %d\n", 1631e505edaeSJeff LaBundy fwnode_get_name(child_node), count); 1632e505edaeSJeff LaBundy return count; 1633e505edaeSJeff LaBundy } 1634e505edaeSJeff LaBundy 1635e505edaeSJeff LaBundy error = fwnode_property_read_u32_array(child_node, 1636e505edaeSJeff LaBundy "azoteq,gpio-select", 1637e505edaeSJeff LaBundy gpio_sel, count); 1638e505edaeSJeff LaBundy if (error) { 1639e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to read %s GPIOs: %d\n", 1640e505edaeSJeff LaBundy fwnode_get_name(child_node), error); 1641e505edaeSJeff LaBundy return error; 1642e505edaeSJeff LaBundy } 1643e505edaeSJeff LaBundy 1644e505edaeSJeff LaBundy for (i = 0; i < count; i++) { 1645e505edaeSJeff LaBundy u16 *gpio_setup; 1646e505edaeSJeff LaBundy 1647e505edaeSJeff LaBundy if (gpio_sel[i] >= num_gpio) { 1648e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s GPIO: %u\n", 1649e505edaeSJeff LaBundy fwnode_get_name(child_node), gpio_sel[i]); 1650e505edaeSJeff LaBundy return -EINVAL; 1651e505edaeSJeff LaBundy } 1652e505edaeSJeff LaBundy 1653e505edaeSJeff LaBundy gpio_setup = iqs7222->gpio_setup[gpio_sel[i]]; 1654e505edaeSJeff LaBundy 1655e505edaeSJeff LaBundy if (gpio_setup[2] && child_link != gpio_setup[2]) { 1656e505edaeSJeff LaBundy dev_err(&client->dev, 1657e505edaeSJeff LaBundy "Conflicting GPIO %u event types\n", 1658e505edaeSJeff LaBundy gpio_sel[i]); 1659e505edaeSJeff LaBundy return -EINVAL; 1660e505edaeSJeff LaBundy } 1661e505edaeSJeff LaBundy 1662e505edaeSJeff LaBundy gpio_setup[0] |= IQS7222_GPIO_SETUP_0_GPIO_EN; 1663e505edaeSJeff LaBundy gpio_setup[1] |= child_enable; 1664e505edaeSJeff LaBundy gpio_setup[2] = child_link; 1665e505edaeSJeff LaBundy } 1666e505edaeSJeff LaBundy 1667e505edaeSJeff LaBundy return 0; 1668e505edaeSJeff LaBundy } 1669e505edaeSJeff LaBundy 1670e505edaeSJeff LaBundy static int iqs7222_parse_props(struct iqs7222_private *iqs7222, 1671bbd16b0dSJeff LaBundy struct fwnode_handle *reg_grp_node, 1672bbd16b0dSJeff LaBundy int reg_grp_index, 1673e505edaeSJeff LaBundy enum iqs7222_reg_grp_id reg_grp, 1674e505edaeSJeff LaBundy enum iqs7222_reg_key_id reg_key) 1675e505edaeSJeff LaBundy { 1676bbd16b0dSJeff LaBundy u16 *setup = iqs7222_setup(iqs7222, reg_grp, reg_grp_index); 1677e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 1678e505edaeSJeff LaBundy int i; 1679e505edaeSJeff LaBundy 1680bbd16b0dSJeff LaBundy if (!setup) 1681e505edaeSJeff LaBundy return 0; 1682e505edaeSJeff LaBundy 1683e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_props); i++) { 1684e505edaeSJeff LaBundy const char *name = iqs7222_props[i].name; 1685e505edaeSJeff LaBundy int reg_offset = iqs7222_props[i].reg_offset; 1686e505edaeSJeff LaBundy int reg_shift = iqs7222_props[i].reg_shift; 1687e505edaeSJeff LaBundy int reg_width = iqs7222_props[i].reg_width; 1688e505edaeSJeff LaBundy int val_pitch = iqs7222_props[i].val_pitch ? : 1; 1689e505edaeSJeff LaBundy int val_min = iqs7222_props[i].val_min; 1690e505edaeSJeff LaBundy int val_max = iqs7222_props[i].val_max; 1691e505edaeSJeff LaBundy bool invert = iqs7222_props[i].invert; 1692e505edaeSJeff LaBundy const char *label = iqs7222_props[i].label ? : name; 1693e505edaeSJeff LaBundy unsigned int val; 1694e505edaeSJeff LaBundy int error; 1695e505edaeSJeff LaBundy 1696e505edaeSJeff LaBundy if (iqs7222_props[i].reg_grp != reg_grp || 1697e505edaeSJeff LaBundy iqs7222_props[i].reg_key != reg_key) 1698e505edaeSJeff LaBundy continue; 1699e505edaeSJeff LaBundy 1700e505edaeSJeff LaBundy /* 1701e505edaeSJeff LaBundy * Boolean register fields are one bit wide; they are forcibly 1702e505edaeSJeff LaBundy * reset to provide a means to undo changes by a bootloader if 1703e505edaeSJeff LaBundy * necessary. 1704e505edaeSJeff LaBundy * 1705e505edaeSJeff LaBundy * Scalar fields, on the other hand, are left untouched unless 1706e505edaeSJeff LaBundy * their corresponding properties are present. 1707e505edaeSJeff LaBundy */ 1708e505edaeSJeff LaBundy if (reg_width == 1) { 1709e505edaeSJeff LaBundy if (invert) 1710e505edaeSJeff LaBundy setup[reg_offset] |= BIT(reg_shift); 1711e505edaeSJeff LaBundy else 1712e505edaeSJeff LaBundy setup[reg_offset] &= ~BIT(reg_shift); 1713e505edaeSJeff LaBundy } 1714e505edaeSJeff LaBundy 1715e505edaeSJeff LaBundy if (!fwnode_property_present(reg_grp_node, name)) 1716e505edaeSJeff LaBundy continue; 1717e505edaeSJeff LaBundy 1718e505edaeSJeff LaBundy if (reg_width == 1) { 1719e505edaeSJeff LaBundy if (invert) 1720e505edaeSJeff LaBundy setup[reg_offset] &= ~BIT(reg_shift); 1721e505edaeSJeff LaBundy else 1722e505edaeSJeff LaBundy setup[reg_offset] |= BIT(reg_shift); 1723e505edaeSJeff LaBundy 1724e505edaeSJeff LaBundy continue; 1725e505edaeSJeff LaBundy } 1726e505edaeSJeff LaBundy 1727e505edaeSJeff LaBundy error = fwnode_property_read_u32(reg_grp_node, name, &val); 1728e505edaeSJeff LaBundy if (error) { 1729e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to read %s %s: %d\n", 1730e505edaeSJeff LaBundy fwnode_get_name(reg_grp_node), label, error); 1731e505edaeSJeff LaBundy return error; 1732e505edaeSJeff LaBundy } 1733e505edaeSJeff LaBundy 1734e505edaeSJeff LaBundy if (!val_max) 1735e505edaeSJeff LaBundy val_max = GENMASK(reg_width - 1, 0) * val_pitch; 1736e505edaeSJeff LaBundy 1737e505edaeSJeff LaBundy if (val < val_min || val > val_max) { 1738e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s %s: %u\n", 1739e505edaeSJeff LaBundy fwnode_get_name(reg_grp_node), label, val); 1740e505edaeSJeff LaBundy return -EINVAL; 1741e505edaeSJeff LaBundy } 1742e505edaeSJeff LaBundy 1743e505edaeSJeff LaBundy setup[reg_offset] &= ~GENMASK(reg_shift + reg_width - 1, 1744e505edaeSJeff LaBundy reg_shift); 1745e505edaeSJeff LaBundy setup[reg_offset] |= (val / val_pitch << reg_shift); 1746e505edaeSJeff LaBundy } 1747e505edaeSJeff LaBundy 1748e505edaeSJeff LaBundy return 0; 1749e505edaeSJeff LaBundy } 1750e505edaeSJeff LaBundy 1751bbd16b0dSJeff LaBundy static int iqs7222_parse_event(struct iqs7222_private *iqs7222, 1752bbd16b0dSJeff LaBundy struct fwnode_handle *event_node, 1753bbd16b0dSJeff LaBundy int reg_grp_index, 1754bbd16b0dSJeff LaBundy enum iqs7222_reg_grp_id reg_grp, 1755bbd16b0dSJeff LaBundy enum iqs7222_reg_key_id reg_key, 1756bbd16b0dSJeff LaBundy u16 event_enable, u16 event_link, 1757bbd16b0dSJeff LaBundy unsigned int *event_type, 1758bbd16b0dSJeff LaBundy unsigned int *event_code) 1759bbd16b0dSJeff LaBundy { 1760bbd16b0dSJeff LaBundy struct i2c_client *client = iqs7222->client; 1761bbd16b0dSJeff LaBundy int error; 1762bbd16b0dSJeff LaBundy 1763bbd16b0dSJeff LaBundy error = iqs7222_parse_props(iqs7222, event_node, reg_grp_index, 1764bbd16b0dSJeff LaBundy reg_grp, reg_key); 1765bbd16b0dSJeff LaBundy if (error) 1766bbd16b0dSJeff LaBundy return error; 1767bbd16b0dSJeff LaBundy 1768bbd16b0dSJeff LaBundy error = iqs7222_gpio_select(iqs7222, event_node, event_enable, 1769bbd16b0dSJeff LaBundy event_link); 1770bbd16b0dSJeff LaBundy if (error) 1771bbd16b0dSJeff LaBundy return error; 1772bbd16b0dSJeff LaBundy 1773bbd16b0dSJeff LaBundy error = fwnode_property_read_u32(event_node, "linux,code", event_code); 1774bbd16b0dSJeff LaBundy if (error == -EINVAL) { 1775bbd16b0dSJeff LaBundy return 0; 1776bbd16b0dSJeff LaBundy } else if (error) { 1777bbd16b0dSJeff LaBundy dev_err(&client->dev, "Failed to read %s code: %d\n", 1778bbd16b0dSJeff LaBundy fwnode_get_name(event_node), error); 1779bbd16b0dSJeff LaBundy return error; 1780bbd16b0dSJeff LaBundy } 1781bbd16b0dSJeff LaBundy 1782bbd16b0dSJeff LaBundy if (!event_type) { 1783bbd16b0dSJeff LaBundy input_set_capability(iqs7222->keypad, EV_KEY, *event_code); 1784bbd16b0dSJeff LaBundy return 0; 1785bbd16b0dSJeff LaBundy } 1786bbd16b0dSJeff LaBundy 1787bbd16b0dSJeff LaBundy error = fwnode_property_read_u32(event_node, "linux,input-type", 1788bbd16b0dSJeff LaBundy event_type); 1789bbd16b0dSJeff LaBundy if (error == -EINVAL) { 1790bbd16b0dSJeff LaBundy *event_type = EV_KEY; 1791bbd16b0dSJeff LaBundy } else if (error) { 1792bbd16b0dSJeff LaBundy dev_err(&client->dev, "Failed to read %s input type: %d\n", 1793bbd16b0dSJeff LaBundy fwnode_get_name(event_node), error); 1794bbd16b0dSJeff LaBundy return error; 1795bbd16b0dSJeff LaBundy } else if (*event_type != EV_KEY && *event_type != EV_SW) { 1796bbd16b0dSJeff LaBundy dev_err(&client->dev, "Invalid %s input type: %d\n", 1797bbd16b0dSJeff LaBundy fwnode_get_name(event_node), *event_type); 1798bbd16b0dSJeff LaBundy return -EINVAL; 1799bbd16b0dSJeff LaBundy } 1800bbd16b0dSJeff LaBundy 1801bbd16b0dSJeff LaBundy input_set_capability(iqs7222->keypad, *event_type, *event_code); 1802bbd16b0dSJeff LaBundy 1803bbd16b0dSJeff LaBundy return 0; 1804bbd16b0dSJeff LaBundy } 1805bbd16b0dSJeff LaBundy 1806bbd16b0dSJeff LaBundy static int iqs7222_parse_cycle(struct iqs7222_private *iqs7222, 1807bbd16b0dSJeff LaBundy struct fwnode_handle *cycle_node, int cycle_index) 1808e505edaeSJeff LaBundy { 1809e505edaeSJeff LaBundy u16 *cycle_setup = iqs7222->cycle_setup[cycle_index]; 1810e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 1811e505edaeSJeff LaBundy unsigned int pins[9]; 1812e505edaeSJeff LaBundy int error, count, i; 1813e505edaeSJeff LaBundy 1814e505edaeSJeff LaBundy /* 1815e505edaeSJeff LaBundy * Each channel shares a cycle with one other channel; the mapping of 1816e505edaeSJeff LaBundy * channels to cycles is fixed. Properties defined for a cycle impact 1817e505edaeSJeff LaBundy * both channels tied to the cycle. 1818bbd16b0dSJeff LaBundy * 1819e505edaeSJeff LaBundy * Unlike channels which are restricted to a select range of CRx pins 1820e505edaeSJeff LaBundy * based on channel number, any cycle can claim any of the device's 9 1821e505edaeSJeff LaBundy * CTx pins (CTx0-8). 1822e505edaeSJeff LaBundy */ 1823e505edaeSJeff LaBundy if (!fwnode_property_present(cycle_node, "azoteq,tx-enable")) 1824e505edaeSJeff LaBundy return 0; 1825e505edaeSJeff LaBundy 1826e505edaeSJeff LaBundy count = fwnode_property_count_u32(cycle_node, "azoteq,tx-enable"); 1827eba697b3SDan Carpenter if (count < 0) { 1828e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to count %s CTx pins: %d\n", 1829e505edaeSJeff LaBundy fwnode_get_name(cycle_node), count); 1830e505edaeSJeff LaBundy return count; 1831eba697b3SDan Carpenter } else if (count > ARRAY_SIZE(pins)) { 1832eba697b3SDan Carpenter dev_err(&client->dev, "Invalid number of %s CTx pins\n", 1833eba697b3SDan Carpenter fwnode_get_name(cycle_node)); 1834eba697b3SDan Carpenter return -EINVAL; 1835e505edaeSJeff LaBundy } 1836e505edaeSJeff LaBundy 1837e505edaeSJeff LaBundy error = fwnode_property_read_u32_array(cycle_node, "azoteq,tx-enable", 1838e505edaeSJeff LaBundy pins, count); 1839e505edaeSJeff LaBundy if (error) { 1840e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to read %s CTx pins: %d\n", 1841e505edaeSJeff LaBundy fwnode_get_name(cycle_node), error); 1842e505edaeSJeff LaBundy return error; 1843e505edaeSJeff LaBundy } 1844e505edaeSJeff LaBundy 1845e505edaeSJeff LaBundy cycle_setup[1] &= ~GENMASK(7 + ARRAY_SIZE(pins) - 1, 7); 1846e505edaeSJeff LaBundy 1847e505edaeSJeff LaBundy for (i = 0; i < count; i++) { 1848e505edaeSJeff LaBundy if (pins[i] > 8) { 1849e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s CTx pin: %u\n", 1850e505edaeSJeff LaBundy fwnode_get_name(cycle_node), pins[i]); 1851e505edaeSJeff LaBundy return -EINVAL; 1852e505edaeSJeff LaBundy } 1853e505edaeSJeff LaBundy 1854e505edaeSJeff LaBundy cycle_setup[1] |= BIT(pins[i] + 7); 1855e505edaeSJeff LaBundy } 1856e505edaeSJeff LaBundy 1857e505edaeSJeff LaBundy return 0; 1858e505edaeSJeff LaBundy } 1859e505edaeSJeff LaBundy 1860bbd16b0dSJeff LaBundy static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, 1861bbd16b0dSJeff LaBundy struct fwnode_handle *chan_node, int chan_index) 1862e505edaeSJeff LaBundy { 1863e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 1864e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 1865e505edaeSJeff LaBundy int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; 1866e505edaeSJeff LaBundy int ext_chan = rounddown(num_chan, 10); 1867e505edaeSJeff LaBundy int error, i; 1868e505edaeSJeff LaBundy u16 *chan_setup = iqs7222->chan_setup[chan_index]; 1869e505edaeSJeff LaBundy u16 *sys_setup = iqs7222->sys_setup; 1870e505edaeSJeff LaBundy unsigned int val; 1871e505edaeSJeff LaBundy 1872d56111edSJeff LaBundy if (dev_desc->allow_offset && 1873d56111edSJeff LaBundy fwnode_property_present(chan_node, "azoteq,ulp-allow")) 1874e505edaeSJeff LaBundy sys_setup[dev_desc->allow_offset] &= ~BIT(chan_index); 1875e505edaeSJeff LaBundy 1876e505edaeSJeff LaBundy chan_setup[0] |= IQS7222_CHAN_SETUP_0_CHAN_EN; 1877e505edaeSJeff LaBundy 1878e505edaeSJeff LaBundy /* 1879e505edaeSJeff LaBundy * The reference channel function allows for differential measurements 1880e505edaeSJeff LaBundy * and is only available in the case of IQS7222A or IQS7222C. 1881e505edaeSJeff LaBundy */ 1882e505edaeSJeff LaBundy if (dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_col > 4 && 1883e505edaeSJeff LaBundy fwnode_property_present(chan_node, "azoteq,ref-select")) { 1884e505edaeSJeff LaBundy u16 *ref_setup; 1885e505edaeSJeff LaBundy 1886e505edaeSJeff LaBundy error = fwnode_property_read_u32(chan_node, "azoteq,ref-select", 1887e505edaeSJeff LaBundy &val); 1888e505edaeSJeff LaBundy if (error) { 1889e505edaeSJeff LaBundy dev_err(&client->dev, 1890e505edaeSJeff LaBundy "Failed to read %s reference channel: %d\n", 1891e505edaeSJeff LaBundy fwnode_get_name(chan_node), error); 1892e505edaeSJeff LaBundy return error; 1893e505edaeSJeff LaBundy } 1894e505edaeSJeff LaBundy 1895e505edaeSJeff LaBundy if (val >= ext_chan) { 1896e505edaeSJeff LaBundy dev_err(&client->dev, 1897e505edaeSJeff LaBundy "Invalid %s reference channel: %u\n", 1898e505edaeSJeff LaBundy fwnode_get_name(chan_node), val); 1899e505edaeSJeff LaBundy return -EINVAL; 1900e505edaeSJeff LaBundy } 1901e505edaeSJeff LaBundy 1902e505edaeSJeff LaBundy ref_setup = iqs7222->chan_setup[val]; 1903e505edaeSJeff LaBundy 1904e505edaeSJeff LaBundy /* 1905e505edaeSJeff LaBundy * Configure the current channel as a follower of the selected 1906e505edaeSJeff LaBundy * reference channel. 1907e505edaeSJeff LaBundy */ 1908e505edaeSJeff LaBundy chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW; 1909e505edaeSJeff LaBundy chan_setup[4] = val * 42 + 1048; 1910e505edaeSJeff LaBundy 1911404f3b48SJeff LaBundy error = fwnode_property_read_u32(chan_node, "azoteq,ref-weight", 1912404f3b48SJeff LaBundy &val); 1913404f3b48SJeff LaBundy if (!error) { 1914e505edaeSJeff LaBundy if (val > U16_MAX) { 1915e505edaeSJeff LaBundy dev_err(&client->dev, 1916e505edaeSJeff LaBundy "Invalid %s reference weight: %u\n", 1917e505edaeSJeff LaBundy fwnode_get_name(chan_node), val); 1918e505edaeSJeff LaBundy return -EINVAL; 1919e505edaeSJeff LaBundy } 1920e505edaeSJeff LaBundy 1921e505edaeSJeff LaBundy chan_setup[5] = val; 1922404f3b48SJeff LaBundy } else if (error != -EINVAL) { 1923404f3b48SJeff LaBundy dev_err(&client->dev, 1924404f3b48SJeff LaBundy "Failed to read %s reference weight: %d\n", 1925404f3b48SJeff LaBundy fwnode_get_name(chan_node), error); 1926404f3b48SJeff LaBundy return error; 1927e505edaeSJeff LaBundy } 1928e505edaeSJeff LaBundy 1929e505edaeSJeff LaBundy /* 1930e505edaeSJeff LaBundy * Configure the selected channel as a reference channel which 1931e505edaeSJeff LaBundy * serves the current channel. 1932e505edaeSJeff LaBundy */ 1933e505edaeSJeff LaBundy ref_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF; 1934e505edaeSJeff LaBundy ref_setup[5] |= BIT(chan_index); 1935e505edaeSJeff LaBundy 1936e505edaeSJeff LaBundy ref_setup[4] = dev_desc->touch_link; 1937e505edaeSJeff LaBundy if (fwnode_property_present(chan_node, "azoteq,use-prox")) 1938e505edaeSJeff LaBundy ref_setup[4] -= 2; 1939e505edaeSJeff LaBundy } 1940e505edaeSJeff LaBundy 1941e505edaeSJeff LaBundy if (fwnode_property_present(chan_node, "azoteq,rx-enable")) { 1942e505edaeSJeff LaBundy /* 1943e505edaeSJeff LaBundy * Each channel can claim up to 4 CRx pins. The first half of 1944e505edaeSJeff LaBundy * the channels can use CRx0-3, while the second half can use 1945e505edaeSJeff LaBundy * CRx4-7. 1946e505edaeSJeff LaBundy */ 1947e505edaeSJeff LaBundy unsigned int pins[4]; 1948e505edaeSJeff LaBundy int count; 1949e505edaeSJeff LaBundy 1950e505edaeSJeff LaBundy count = fwnode_property_count_u32(chan_node, 1951e505edaeSJeff LaBundy "azoteq,rx-enable"); 1952eba697b3SDan Carpenter if (count < 0) { 1953e505edaeSJeff LaBundy dev_err(&client->dev, 1954e505edaeSJeff LaBundy "Failed to count %s CRx pins: %d\n", 1955e505edaeSJeff LaBundy fwnode_get_name(chan_node), count); 1956e505edaeSJeff LaBundy return count; 1957eba697b3SDan Carpenter } else if (count > ARRAY_SIZE(pins)) { 1958eba697b3SDan Carpenter dev_err(&client->dev, 1959eba697b3SDan Carpenter "Invalid number of %s CRx pins\n", 1960eba697b3SDan Carpenter fwnode_get_name(chan_node)); 1961eba697b3SDan Carpenter return -EINVAL; 1962e505edaeSJeff LaBundy } 1963e505edaeSJeff LaBundy 1964e505edaeSJeff LaBundy error = fwnode_property_read_u32_array(chan_node, 1965e505edaeSJeff LaBundy "azoteq,rx-enable", 1966e505edaeSJeff LaBundy pins, count); 1967e505edaeSJeff LaBundy if (error) { 1968e505edaeSJeff LaBundy dev_err(&client->dev, 1969e505edaeSJeff LaBundy "Failed to read %s CRx pins: %d\n", 1970e505edaeSJeff LaBundy fwnode_get_name(chan_node), error); 1971e505edaeSJeff LaBundy return error; 1972e505edaeSJeff LaBundy } 1973e505edaeSJeff LaBundy 1974e505edaeSJeff LaBundy chan_setup[0] &= ~GENMASK(4 + ARRAY_SIZE(pins) - 1, 4); 1975e505edaeSJeff LaBundy 1976e505edaeSJeff LaBundy for (i = 0; i < count; i++) { 1977e505edaeSJeff LaBundy int min_crx = chan_index < ext_chan / 2 ? 0 : 4; 1978e505edaeSJeff LaBundy 1979e505edaeSJeff LaBundy if (pins[i] < min_crx || pins[i] > min_crx + 3) { 1980e505edaeSJeff LaBundy dev_err(&client->dev, 1981e505edaeSJeff LaBundy "Invalid %s CRx pin: %u\n", 1982e505edaeSJeff LaBundy fwnode_get_name(chan_node), pins[i]); 1983e505edaeSJeff LaBundy return -EINVAL; 1984e505edaeSJeff LaBundy } 1985e505edaeSJeff LaBundy 1986e505edaeSJeff LaBundy chan_setup[0] |= BIT(pins[i] + 4 - min_crx); 1987e505edaeSJeff LaBundy } 1988e505edaeSJeff LaBundy } 1989e505edaeSJeff LaBundy 1990e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_kp_events); i++) { 1991e505edaeSJeff LaBundy const char *event_name = iqs7222_kp_events[i].name; 1992e505edaeSJeff LaBundy u16 event_enable = iqs7222_kp_events[i].enable; 1993e505edaeSJeff LaBundy struct fwnode_handle *event_node; 1994e505edaeSJeff LaBundy 1995e505edaeSJeff LaBundy event_node = fwnode_get_named_child_node(chan_node, event_name); 1996e505edaeSJeff LaBundy if (!event_node) 1997e505edaeSJeff LaBundy continue; 1998e505edaeSJeff LaBundy 1999404f3b48SJeff LaBundy error = fwnode_property_read_u32(event_node, 2000e505edaeSJeff LaBundy "azoteq,timeout-press-ms", 2001404f3b48SJeff LaBundy &val); 2002404f3b48SJeff LaBundy if (!error) { 2003e505edaeSJeff LaBundy /* 2004e505edaeSJeff LaBundy * The IQS7222B employs a global pair of press timeout 2005e505edaeSJeff LaBundy * registers as opposed to channel-specific registers. 2006e505edaeSJeff LaBundy */ 2007e505edaeSJeff LaBundy u16 *setup = dev_desc->reg_grps 2008e505edaeSJeff LaBundy [IQS7222_REG_GRP_BTN].num_col > 2 ? 2009e505edaeSJeff LaBundy &iqs7222->btn_setup[chan_index][2] : 2010e505edaeSJeff LaBundy &sys_setup[9]; 2011e505edaeSJeff LaBundy 2012e505edaeSJeff LaBundy if (val > U8_MAX * 500) { 2013e505edaeSJeff LaBundy dev_err(&client->dev, 2014e505edaeSJeff LaBundy "Invalid %s press timeout: %u\n", 2015bbd16b0dSJeff LaBundy fwnode_get_name(event_node), val); 2016bbd16b0dSJeff LaBundy fwnode_handle_put(event_node); 2017e505edaeSJeff LaBundy return -EINVAL; 2018e505edaeSJeff LaBundy } 2019e505edaeSJeff LaBundy 2020e505edaeSJeff LaBundy *setup &= ~(U8_MAX << i * 8); 2021e505edaeSJeff LaBundy *setup |= (val / 500 << i * 8); 2022404f3b48SJeff LaBundy } else if (error != -EINVAL) { 2023404f3b48SJeff LaBundy dev_err(&client->dev, 2024404f3b48SJeff LaBundy "Failed to read %s press timeout: %d\n", 2025404f3b48SJeff LaBundy fwnode_get_name(event_node), error); 2026404f3b48SJeff LaBundy fwnode_handle_put(event_node); 2027404f3b48SJeff LaBundy return error; 2028e505edaeSJeff LaBundy } 2029e505edaeSJeff LaBundy 2030bbd16b0dSJeff LaBundy error = iqs7222_parse_event(iqs7222, event_node, chan_index, 2031bbd16b0dSJeff LaBundy IQS7222_REG_GRP_BTN, 2032bbd16b0dSJeff LaBundy iqs7222_kp_events[i].reg_key, 2033bbd16b0dSJeff LaBundy BIT(chan_index), 2034bbd16b0dSJeff LaBundy dev_desc->touch_link - (i ? 0 : 2), 2035bbd16b0dSJeff LaBundy &iqs7222->kp_type[chan_index][i], 2036bbd16b0dSJeff LaBundy &iqs7222->kp_code[chan_index][i]); 2037bbd16b0dSJeff LaBundy fwnode_handle_put(event_node); 2038bbd16b0dSJeff LaBundy if (error) 2039e505edaeSJeff LaBundy return error; 2040e505edaeSJeff LaBundy 2041e505edaeSJeff LaBundy if (!dev_desc->event_offset) 2042e505edaeSJeff LaBundy continue; 2043e505edaeSJeff LaBundy 2044e505edaeSJeff LaBundy sys_setup[dev_desc->event_offset] |= event_enable; 2045e505edaeSJeff LaBundy } 2046e505edaeSJeff LaBundy 2047e505edaeSJeff LaBundy /* 2048e505edaeSJeff LaBundy * The following call handles a special pair of properties that apply 2049e505edaeSJeff LaBundy * to a channel node, but reside within the button (event) group. 2050e505edaeSJeff LaBundy */ 2051bbd16b0dSJeff LaBundy return iqs7222_parse_props(iqs7222, chan_node, chan_index, 2052e505edaeSJeff LaBundy IQS7222_REG_GRP_BTN, 2053e505edaeSJeff LaBundy IQS7222_REG_KEY_DEBOUNCE); 2054e505edaeSJeff LaBundy } 2055e505edaeSJeff LaBundy 2056bbd16b0dSJeff LaBundy static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, 2057bbd16b0dSJeff LaBundy struct fwnode_handle *sldr_node, int sldr_index) 2058e505edaeSJeff LaBundy { 2059e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 2060e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 2061e505edaeSJeff LaBundy int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; 2062e505edaeSJeff LaBundy int ext_chan = rounddown(num_chan, 10); 2063e505edaeSJeff LaBundy int count, error, reg_offset, i; 206495215d3dSJeff LaBundy u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset]; 2065e505edaeSJeff LaBundy u16 *sldr_setup = iqs7222->sldr_setup[sldr_index]; 2066e505edaeSJeff LaBundy unsigned int chan_sel[4], val; 2067e505edaeSJeff LaBundy 2068e505edaeSJeff LaBundy /* 2069e505edaeSJeff LaBundy * Each slider can be spread across 3 to 4 channels. It is possible to 2070e505edaeSJeff LaBundy * select only 2 channels, but doing so prevents the slider from using 2071e505edaeSJeff LaBundy * the specified resolution. 2072e505edaeSJeff LaBundy */ 2073e505edaeSJeff LaBundy count = fwnode_property_count_u32(sldr_node, "azoteq,channel-select"); 2074eba697b3SDan Carpenter if (count < 0) { 2075e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to count %s channels: %d\n", 2076e505edaeSJeff LaBundy fwnode_get_name(sldr_node), count); 2077e505edaeSJeff LaBundy return count; 2078eba697b3SDan Carpenter } else if (count < 3 || count > ARRAY_SIZE(chan_sel)) { 2079eba697b3SDan Carpenter dev_err(&client->dev, "Invalid number of %s channels\n", 2080eba697b3SDan Carpenter fwnode_get_name(sldr_node)); 2081eba697b3SDan Carpenter return -EINVAL; 2082e505edaeSJeff LaBundy } 2083e505edaeSJeff LaBundy 2084e505edaeSJeff LaBundy error = fwnode_property_read_u32_array(sldr_node, 2085e505edaeSJeff LaBundy "azoteq,channel-select", 2086e505edaeSJeff LaBundy chan_sel, count); 2087e505edaeSJeff LaBundy if (error) { 2088e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to read %s channels: %d\n", 2089e505edaeSJeff LaBundy fwnode_get_name(sldr_node), error); 2090e505edaeSJeff LaBundy return error; 2091e505edaeSJeff LaBundy } 2092e505edaeSJeff LaBundy 2093e505edaeSJeff LaBundy /* 2094e505edaeSJeff LaBundy * Resolution and top speed, if small enough, are packed into a single 2095e505edaeSJeff LaBundy * register. Otherwise, each occupies its own register and the rest of 2096e505edaeSJeff LaBundy * the slider-related register addresses are offset by one. 2097e505edaeSJeff LaBundy */ 2098e505edaeSJeff LaBundy reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1; 2099e505edaeSJeff LaBundy 2100e505edaeSJeff LaBundy sldr_setup[0] |= count; 210195215d3dSJeff LaBundy sldr_setup[3 + reg_offset] &= ~GENMASK(ext_chan - 1, 0); 2102e505edaeSJeff LaBundy 2103e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(chan_sel); i++) { 2104e505edaeSJeff LaBundy sldr_setup[5 + reg_offset + i] = 0; 2105e505edaeSJeff LaBundy if (i >= count) 2106e505edaeSJeff LaBundy continue; 2107e505edaeSJeff LaBundy 2108e505edaeSJeff LaBundy if (chan_sel[i] >= ext_chan) { 2109e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s channel: %u\n", 2110e505edaeSJeff LaBundy fwnode_get_name(sldr_node), chan_sel[i]); 2111e505edaeSJeff LaBundy return -EINVAL; 2112e505edaeSJeff LaBundy } 2113e505edaeSJeff LaBundy 2114e505edaeSJeff LaBundy /* 2115e505edaeSJeff LaBundy * The following fields indicate which channels participate in 2116e505edaeSJeff LaBundy * the slider, as well as each channel's relative placement. 2117e505edaeSJeff LaBundy */ 2118e505edaeSJeff LaBundy sldr_setup[3 + reg_offset] |= BIT(chan_sel[i]); 2119e505edaeSJeff LaBundy sldr_setup[5 + reg_offset + i] = chan_sel[i] * 42 + 1080; 2120e505edaeSJeff LaBundy } 2121e505edaeSJeff LaBundy 2122e505edaeSJeff LaBundy sldr_setup[4 + reg_offset] = dev_desc->touch_link; 2123e505edaeSJeff LaBundy if (fwnode_property_present(sldr_node, "azoteq,use-prox")) 2124e505edaeSJeff LaBundy sldr_setup[4 + reg_offset] -= 2; 2125e505edaeSJeff LaBundy 2126404f3b48SJeff LaBundy error = fwnode_property_read_u32(sldr_node, "azoteq,slider-size", &val); 2127404f3b48SJeff LaBundy if (!error) { 21282f6fd232SJeff LaBundy if (val > dev_desc->sldr_res) { 2129e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s size: %u\n", 2130e505edaeSJeff LaBundy fwnode_get_name(sldr_node), val); 2131e505edaeSJeff LaBundy return -EINVAL; 2132e505edaeSJeff LaBundy } 2133e505edaeSJeff LaBundy 2134e505edaeSJeff LaBundy if (reg_offset) { 2135e505edaeSJeff LaBundy sldr_setup[3] = val; 2136e505edaeSJeff LaBundy } else { 2137e505edaeSJeff LaBundy sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_RES_MASK; 2138e505edaeSJeff LaBundy sldr_setup[2] |= (val / 16 << 2139e505edaeSJeff LaBundy IQS7222_SLDR_SETUP_2_RES_SHIFT); 2140e505edaeSJeff LaBundy } 2141404f3b48SJeff LaBundy } else if (error != -EINVAL) { 2142404f3b48SJeff LaBundy dev_err(&client->dev, "Failed to read %s size: %d\n", 2143404f3b48SJeff LaBundy fwnode_get_name(sldr_node), error); 2144404f3b48SJeff LaBundy return error; 2145e505edaeSJeff LaBundy } 2146e505edaeSJeff LaBundy 21472f6fd232SJeff LaBundy if (!(reg_offset ? sldr_setup[3] 21482f6fd232SJeff LaBundy : sldr_setup[2] & IQS7222_SLDR_SETUP_2_RES_MASK)) { 21492f6fd232SJeff LaBundy dev_err(&client->dev, "Undefined %s size\n", 21502f6fd232SJeff LaBundy fwnode_get_name(sldr_node)); 21512f6fd232SJeff LaBundy return -EINVAL; 21522f6fd232SJeff LaBundy } 21532f6fd232SJeff LaBundy 2154404f3b48SJeff LaBundy error = fwnode_property_read_u32(sldr_node, "azoteq,top-speed", &val); 2155404f3b48SJeff LaBundy if (!error) { 2156e505edaeSJeff LaBundy if (val > (reg_offset ? U16_MAX : U8_MAX * 4)) { 2157e505edaeSJeff LaBundy dev_err(&client->dev, "Invalid %s top speed: %u\n", 2158e505edaeSJeff LaBundy fwnode_get_name(sldr_node), val); 2159e505edaeSJeff LaBundy return -EINVAL; 2160e505edaeSJeff LaBundy } 2161e505edaeSJeff LaBundy 2162e505edaeSJeff LaBundy if (reg_offset) { 2163e505edaeSJeff LaBundy sldr_setup[2] = val; 2164e505edaeSJeff LaBundy } else { 2165e505edaeSJeff LaBundy sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK; 2166e505edaeSJeff LaBundy sldr_setup[2] |= (val / 4); 2167e505edaeSJeff LaBundy } 2168404f3b48SJeff LaBundy } else if (error != -EINVAL) { 2169404f3b48SJeff LaBundy dev_err(&client->dev, "Failed to read %s top speed: %d\n", 2170404f3b48SJeff LaBundy fwnode_get_name(sldr_node), error); 2171404f3b48SJeff LaBundy return error; 2172e505edaeSJeff LaBundy } 2173e505edaeSJeff LaBundy 2174404f3b48SJeff LaBundy error = fwnode_property_read_u32(sldr_node, "linux,axis", &val); 2175404f3b48SJeff LaBundy if (!error) { 2176e505edaeSJeff LaBundy u16 sldr_max = sldr_setup[3] - 1; 2177e505edaeSJeff LaBundy 2178e505edaeSJeff LaBundy if (!reg_offset) { 2179e505edaeSJeff LaBundy sldr_max = sldr_setup[2]; 2180e505edaeSJeff LaBundy 2181e505edaeSJeff LaBundy sldr_max &= IQS7222_SLDR_SETUP_2_RES_MASK; 2182e505edaeSJeff LaBundy sldr_max >>= IQS7222_SLDR_SETUP_2_RES_SHIFT; 2183e505edaeSJeff LaBundy 2184e505edaeSJeff LaBundy sldr_max = sldr_max * 16 - 1; 2185e505edaeSJeff LaBundy } 2186e505edaeSJeff LaBundy 2187e505edaeSJeff LaBundy input_set_abs_params(iqs7222->keypad, val, 0, sldr_max, 0, 0); 2188e505edaeSJeff LaBundy iqs7222->sl_axis[sldr_index] = val; 2189404f3b48SJeff LaBundy } else if (error != -EINVAL) { 2190404f3b48SJeff LaBundy dev_err(&client->dev, "Failed to read %s axis: %d\n", 2191404f3b48SJeff LaBundy fwnode_get_name(sldr_node), error); 2192404f3b48SJeff LaBundy return error; 2193e505edaeSJeff LaBundy } 2194e505edaeSJeff LaBundy 2195e505edaeSJeff LaBundy if (dev_desc->wheel_enable) { 2196e505edaeSJeff LaBundy sldr_setup[0] &= ~dev_desc->wheel_enable; 2197e505edaeSJeff LaBundy if (iqs7222->sl_axis[sldr_index] == ABS_WHEEL) 2198e505edaeSJeff LaBundy sldr_setup[0] |= dev_desc->wheel_enable; 2199e505edaeSJeff LaBundy } 2200e505edaeSJeff LaBundy 220156a0c54cSJeff LaBundy /* 220256a0c54cSJeff LaBundy * The absence of a register offset makes it safe to assume the device 220356a0c54cSJeff LaBundy * supports gestures, each of which is first disabled until explicitly 220456a0c54cSJeff LaBundy * enabled. 220556a0c54cSJeff LaBundy */ 220656a0c54cSJeff LaBundy if (!reg_offset) 220756a0c54cSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) 220856a0c54cSJeff LaBundy sldr_setup[9] &= ~iqs7222_sl_events[i].enable; 220956a0c54cSJeff LaBundy 2210e505edaeSJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) { 2211e505edaeSJeff LaBundy const char *event_name = iqs7222_sl_events[i].name; 2212e505edaeSJeff LaBundy struct fwnode_handle *event_node; 2213bbd16b0dSJeff LaBundy enum iqs7222_reg_key_id reg_key; 2214e505edaeSJeff LaBundy 2215e505edaeSJeff LaBundy event_node = fwnode_get_named_child_node(sldr_node, event_name); 2216e505edaeSJeff LaBundy if (!event_node) 2217e505edaeSJeff LaBundy continue; 2218e505edaeSJeff LaBundy 22198d4c313cSJeff LaBundy /* 22208d4c313cSJeff LaBundy * Depending on the device, gestures are either offered using 22218d4c313cSJeff LaBundy * one of two timing resolutions, or are not supported at all. 22228d4c313cSJeff LaBundy */ 2223bbd16b0dSJeff LaBundy if (reg_offset) 2224bbd16b0dSJeff LaBundy reg_key = IQS7222_REG_KEY_RESERVED; 22258d4c313cSJeff LaBundy else if (dev_desc->legacy_gesture && 22268d4c313cSJeff LaBundy iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_TAP) 22278d4c313cSJeff LaBundy reg_key = IQS7222_REG_KEY_TAP_LEGACY; 22288d4c313cSJeff LaBundy else if (dev_desc->legacy_gesture && 22298d4c313cSJeff LaBundy iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_AXIAL) 22308d4c313cSJeff LaBundy reg_key = IQS7222_REG_KEY_AXIAL_LEGACY; 2231bbd16b0dSJeff LaBundy else 2232bbd16b0dSJeff LaBundy reg_key = iqs7222_sl_events[i].reg_key; 2233e505edaeSJeff LaBundy 223495215d3dSJeff LaBundy /* 223595215d3dSJeff LaBundy * The press/release event does not expose a direct GPIO link, 223695215d3dSJeff LaBundy * but one can be emulated by tying each of the participating 223795215d3dSJeff LaBundy * channels to the same GPIO. 223895215d3dSJeff LaBundy */ 2239bbd16b0dSJeff LaBundy error = iqs7222_parse_event(iqs7222, event_node, sldr_index, 2240bbd16b0dSJeff LaBundy IQS7222_REG_GRP_SLDR, reg_key, 224195215d3dSJeff LaBundy i ? iqs7222_sl_events[i].enable 224295215d3dSJeff LaBundy : sldr_setup[3 + reg_offset], 224395215d3dSJeff LaBundy i ? 1568 + sldr_index * 30 2244bbd16b0dSJeff LaBundy : sldr_setup[4 + reg_offset], 2245bbd16b0dSJeff LaBundy NULL, 2246bbd16b0dSJeff LaBundy &iqs7222->sl_code[sldr_index][i]); 2247bbd16b0dSJeff LaBundy fwnode_handle_put(event_node); 224895215d3dSJeff LaBundy if (error) 224995215d3dSJeff LaBundy return error; 225095215d3dSJeff LaBundy 225195215d3dSJeff LaBundy if (!reg_offset) 225295215d3dSJeff LaBundy sldr_setup[9] |= iqs7222_sl_events[i].enable; 225395215d3dSJeff LaBundy 2254e505edaeSJeff LaBundy if (!dev_desc->event_offset) 2255e505edaeSJeff LaBundy continue; 2256e505edaeSJeff LaBundy 225795215d3dSJeff LaBundy /* 225895215d3dSJeff LaBundy * The press/release event is determined based on whether the 225995215d3dSJeff LaBundy * coordinate field reports 0xFFFF and solely relies on touch 226095215d3dSJeff LaBundy * or proximity interrupts to be unmasked. 226195215d3dSJeff LaBundy */ 226295215d3dSJeff LaBundy if (i && !reg_offset) 226395215d3dSJeff LaBundy *event_mask |= (IQS7222_EVENT_MASK_SLDR << sldr_index); 226495215d3dSJeff LaBundy else if (sldr_setup[4 + reg_offset] == dev_desc->touch_link) 226595215d3dSJeff LaBundy *event_mask |= IQS7222_EVENT_MASK_TOUCH; 226695215d3dSJeff LaBundy else 226795215d3dSJeff LaBundy *event_mask |= IQS7222_EVENT_MASK_PROX; 2268e505edaeSJeff LaBundy } 2269e505edaeSJeff LaBundy 2270e505edaeSJeff LaBundy /* 2271e505edaeSJeff LaBundy * The following call handles a special pair of properties that shift 2272e505edaeSJeff LaBundy * to make room for a wheel enable control in the case of IQS7222C. 2273e505edaeSJeff LaBundy */ 2274bbd16b0dSJeff LaBundy return iqs7222_parse_props(iqs7222, sldr_node, sldr_index, 2275e505edaeSJeff LaBundy IQS7222_REG_GRP_SLDR, 2276e505edaeSJeff LaBundy dev_desc->wheel_enable ? 2277e505edaeSJeff LaBundy IQS7222_REG_KEY_WHEEL : 2278e505edaeSJeff LaBundy IQS7222_REG_KEY_NO_WHEEL); 2279e505edaeSJeff LaBundy } 2280e505edaeSJeff LaBundy 2281bbd16b0dSJeff LaBundy static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS]) 2282bbd16b0dSJeff LaBundy (struct iqs7222_private *iqs7222, 2283bbd16b0dSJeff LaBundy struct fwnode_handle *reg_grp_node, 2284bbd16b0dSJeff LaBundy int reg_grp_index) = { 2285bbd16b0dSJeff LaBundy [IQS7222_REG_GRP_CYCLE] = iqs7222_parse_cycle, 2286bbd16b0dSJeff LaBundy [IQS7222_REG_GRP_CHAN] = iqs7222_parse_chan, 2287bbd16b0dSJeff LaBundy [IQS7222_REG_GRP_SLDR] = iqs7222_parse_sldr, 2288bbd16b0dSJeff LaBundy }; 2289bbd16b0dSJeff LaBundy 2290bbd16b0dSJeff LaBundy static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222, 2291bbd16b0dSJeff LaBundy enum iqs7222_reg_grp_id reg_grp, 2292bbd16b0dSJeff LaBundy int reg_grp_index) 2293bbd16b0dSJeff LaBundy { 2294bbd16b0dSJeff LaBundy struct i2c_client *client = iqs7222->client; 2295bbd16b0dSJeff LaBundy struct fwnode_handle *reg_grp_node; 2296bbd16b0dSJeff LaBundy int error; 2297bbd16b0dSJeff LaBundy 2298bbd16b0dSJeff LaBundy if (iqs7222_reg_grp_names[reg_grp]) { 2299bbd16b0dSJeff LaBundy char reg_grp_name[16]; 2300bbd16b0dSJeff LaBundy 2301bbd16b0dSJeff LaBundy snprintf(reg_grp_name, sizeof(reg_grp_name), "%s-%d", 2302bbd16b0dSJeff LaBundy iqs7222_reg_grp_names[reg_grp], reg_grp_index); 2303bbd16b0dSJeff LaBundy 2304bbd16b0dSJeff LaBundy reg_grp_node = device_get_named_child_node(&client->dev, 2305bbd16b0dSJeff LaBundy reg_grp_name); 2306bbd16b0dSJeff LaBundy } else { 2307bbd16b0dSJeff LaBundy reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev)); 2308bbd16b0dSJeff LaBundy } 2309bbd16b0dSJeff LaBundy 2310bbd16b0dSJeff LaBundy if (!reg_grp_node) 2311bbd16b0dSJeff LaBundy return 0; 2312bbd16b0dSJeff LaBundy 2313bbd16b0dSJeff LaBundy error = iqs7222_parse_props(iqs7222, reg_grp_node, reg_grp_index, 2314bbd16b0dSJeff LaBundy reg_grp, IQS7222_REG_KEY_NONE); 2315bbd16b0dSJeff LaBundy 2316bbd16b0dSJeff LaBundy if (!error && iqs7222_parse_extra[reg_grp]) 2317bbd16b0dSJeff LaBundy error = iqs7222_parse_extra[reg_grp](iqs7222, reg_grp_node, 2318bbd16b0dSJeff LaBundy reg_grp_index); 2319bbd16b0dSJeff LaBundy 2320bbd16b0dSJeff LaBundy fwnode_handle_put(reg_grp_node); 2321bbd16b0dSJeff LaBundy 2322bbd16b0dSJeff LaBundy return error; 2323bbd16b0dSJeff LaBundy } 2324bbd16b0dSJeff LaBundy 2325e505edaeSJeff LaBundy static int iqs7222_parse_all(struct iqs7222_private *iqs7222) 2326e505edaeSJeff LaBundy { 2327e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 2328e505edaeSJeff LaBundy const struct iqs7222_reg_grp_desc *reg_grps = dev_desc->reg_grps; 2329e505edaeSJeff LaBundy u16 *sys_setup = iqs7222->sys_setup; 2330bbd16b0dSJeff LaBundy int error, i, j; 2331e505edaeSJeff LaBundy 2332d56111edSJeff LaBundy if (dev_desc->allow_offset) 2333d56111edSJeff LaBundy sys_setup[dev_desc->allow_offset] = U16_MAX; 2334d56111edSJeff LaBundy 2335e505edaeSJeff LaBundy if (dev_desc->event_offset) 2336e505edaeSJeff LaBundy sys_setup[dev_desc->event_offset] = IQS7222_EVENT_MASK_ATI; 2337e505edaeSJeff LaBundy 2338e505edaeSJeff LaBundy for (i = 0; i < reg_grps[IQS7222_REG_GRP_GPIO].num_row; i++) { 2339e505edaeSJeff LaBundy u16 *gpio_setup = iqs7222->gpio_setup[i]; 2340e505edaeSJeff LaBundy 2341e505edaeSJeff LaBundy gpio_setup[0] &= ~IQS7222_GPIO_SETUP_0_GPIO_EN; 2342e505edaeSJeff LaBundy gpio_setup[1] = 0; 2343e505edaeSJeff LaBundy gpio_setup[2] = 0; 2344e505edaeSJeff LaBundy 2345e505edaeSJeff LaBundy if (reg_grps[IQS7222_REG_GRP_GPIO].num_row == 1) 2346e505edaeSJeff LaBundy continue; 2347e505edaeSJeff LaBundy 2348e505edaeSJeff LaBundy /* 2349e505edaeSJeff LaBundy * The IQS7222C exposes multiple GPIO and must be informed 2350e505edaeSJeff LaBundy * as to which GPIO this group represents. 2351e505edaeSJeff LaBundy */ 2352e505edaeSJeff LaBundy for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++) 2353e505edaeSJeff LaBundy gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]); 2354e505edaeSJeff LaBundy 2355e505edaeSJeff LaBundy gpio_setup[0] |= BIT(iqs7222_gpio_links[i]); 2356e505edaeSJeff LaBundy } 2357e505edaeSJeff LaBundy 2358e505edaeSJeff LaBundy for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) { 2359e505edaeSJeff LaBundy u16 *chan_setup = iqs7222->chan_setup[i]; 2360e505edaeSJeff LaBundy 2361e505edaeSJeff LaBundy chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_REF_MODE_MASK; 2362e505edaeSJeff LaBundy chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_CHAN_EN; 2363e505edaeSJeff LaBundy 2364e505edaeSJeff LaBundy chan_setup[5] = 0; 2365e505edaeSJeff LaBundy } 2366e505edaeSJeff LaBundy 2367e505edaeSJeff LaBundy for (i = 0; i < reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) { 2368e505edaeSJeff LaBundy u16 *sldr_setup = iqs7222->sldr_setup[i]; 2369e505edaeSJeff LaBundy 2370e505edaeSJeff LaBundy sldr_setup[0] &= ~IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK; 2371bbd16b0dSJeff LaBundy } 2372e505edaeSJeff LaBundy 2373bbd16b0dSJeff LaBundy for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) { 2374bbd16b0dSJeff LaBundy for (j = 0; j < reg_grps[i].num_row; j++) { 2375bbd16b0dSJeff LaBundy error = iqs7222_parse_reg_grp(iqs7222, i, j); 2376e505edaeSJeff LaBundy if (error) 2377e505edaeSJeff LaBundy return error; 2378e505edaeSJeff LaBundy } 2379bbd16b0dSJeff LaBundy } 2380e505edaeSJeff LaBundy 2381bbd16b0dSJeff LaBundy return 0; 2382e505edaeSJeff LaBundy } 2383e505edaeSJeff LaBundy 2384e505edaeSJeff LaBundy static int iqs7222_report(struct iqs7222_private *iqs7222) 2385e505edaeSJeff LaBundy { 2386e505edaeSJeff LaBundy const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 2387e505edaeSJeff LaBundy struct i2c_client *client = iqs7222->client; 2388e505edaeSJeff LaBundy int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; 2389e505edaeSJeff LaBundy int num_stat = dev_desc->reg_grps[IQS7222_REG_GRP_STAT].num_col; 2390e505edaeSJeff LaBundy int error, i, j; 2391e505edaeSJeff LaBundy __le16 status[IQS7222_MAX_COLS_STAT]; 2392e505edaeSJeff LaBundy 2393e505edaeSJeff LaBundy error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status, 2394e505edaeSJeff LaBundy num_stat); 2395e505edaeSJeff LaBundy if (error) 2396e505edaeSJeff LaBundy return error; 2397e505edaeSJeff LaBundy 2398e505edaeSJeff LaBundy if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_RESET) { 2399e505edaeSJeff LaBundy dev_err(&client->dev, "Unexpected device reset\n"); 2400e505edaeSJeff LaBundy return iqs7222_dev_init(iqs7222, WRITE); 2401e505edaeSJeff LaBundy } 2402e505edaeSJeff LaBundy 2403e505edaeSJeff LaBundy if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ERROR) { 2404e505edaeSJeff LaBundy dev_err(&client->dev, "Unexpected ATI error\n"); 2405e505edaeSJeff LaBundy return iqs7222_ati_trigger(iqs7222); 2406e505edaeSJeff LaBundy } 2407e505edaeSJeff LaBundy 2408e505edaeSJeff LaBundy if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ACTIVE) 2409e505edaeSJeff LaBundy return 0; 2410e505edaeSJeff LaBundy 2411e505edaeSJeff LaBundy for (i = 0; i < num_chan; i++) { 2412e505edaeSJeff LaBundy u16 *chan_setup = iqs7222->chan_setup[i]; 2413e505edaeSJeff LaBundy 2414e505edaeSJeff LaBundy if (!(chan_setup[0] & IQS7222_CHAN_SETUP_0_CHAN_EN)) 2415e505edaeSJeff LaBundy continue; 2416e505edaeSJeff LaBundy 2417e505edaeSJeff LaBundy for (j = 0; j < ARRAY_SIZE(iqs7222_kp_events); j++) { 2418e505edaeSJeff LaBundy /* 2419e505edaeSJeff LaBundy * Proximity state begins at offset 2 and spills into 2420e505edaeSJeff LaBundy * offset 3 for devices with more than 16 channels. 2421e505edaeSJeff LaBundy * 2422e505edaeSJeff LaBundy * Touch state begins at the first offset immediately 2423e505edaeSJeff LaBundy * following proximity state. 2424e505edaeSJeff LaBundy */ 2425e505edaeSJeff LaBundy int k = 2 + j * (num_chan > 16 ? 2 : 1); 2426e505edaeSJeff LaBundy u16 state = le16_to_cpu(status[k + i / 16]); 2427e505edaeSJeff LaBundy 2428514c13b1SJeff LaBundy if (!iqs7222->kp_type[i][j]) 2429514c13b1SJeff LaBundy continue; 2430514c13b1SJeff LaBundy 2431e505edaeSJeff LaBundy input_event(iqs7222->keypad, 2432e505edaeSJeff LaBundy iqs7222->kp_type[i][j], 2433e505edaeSJeff LaBundy iqs7222->kp_code[i][j], 2434e505edaeSJeff LaBundy !!(state & BIT(i % 16))); 2435e505edaeSJeff LaBundy } 2436e505edaeSJeff LaBundy } 2437e505edaeSJeff LaBundy 2438e505edaeSJeff LaBundy for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) { 2439e505edaeSJeff LaBundy u16 *sldr_setup = iqs7222->sldr_setup[i]; 2440e505edaeSJeff LaBundy u16 sldr_pos = le16_to_cpu(status[4 + i]); 2441e505edaeSJeff LaBundy u16 state = le16_to_cpu(status[6 + i]); 2442e505edaeSJeff LaBundy 2443e505edaeSJeff LaBundy if (!(sldr_setup[0] & IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK)) 2444e505edaeSJeff LaBundy continue; 2445e505edaeSJeff LaBundy 2446e505edaeSJeff LaBundy if (sldr_pos < dev_desc->sldr_res) 2447e505edaeSJeff LaBundy input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i], 2448e505edaeSJeff LaBundy sldr_pos); 2449e505edaeSJeff LaBundy 245095215d3dSJeff LaBundy input_report_key(iqs7222->keypad, iqs7222->sl_code[i][0], 2451e505edaeSJeff LaBundy sldr_pos < dev_desc->sldr_res); 2452e505edaeSJeff LaBundy 2453e505edaeSJeff LaBundy /* 245495215d3dSJeff LaBundy * A maximum resolution indicates the device does not support 245595215d3dSJeff LaBundy * gestures, in which case the remaining fields are ignored. 2456e505edaeSJeff LaBundy */ 245795215d3dSJeff LaBundy if (dev_desc->sldr_res == U16_MAX) 2458e505edaeSJeff LaBundy continue; 2459e505edaeSJeff LaBundy 246095215d3dSJeff LaBundy if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_SLDR << i)) 246195215d3dSJeff LaBundy continue; 246295215d3dSJeff LaBundy 246395215d3dSJeff LaBundy /* 246495215d3dSJeff LaBundy * Skip the press/release event, as it does not have separate 246595215d3dSJeff LaBundy * status fields and is handled separately. 246695215d3dSJeff LaBundy */ 246795215d3dSJeff LaBundy for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++) { 246895215d3dSJeff LaBundy u16 mask = iqs7222_sl_events[j].mask; 246995215d3dSJeff LaBundy u16 val = iqs7222_sl_events[j].val; 247095215d3dSJeff LaBundy 2471e505edaeSJeff LaBundy input_report_key(iqs7222->keypad, 2472e505edaeSJeff LaBundy iqs7222->sl_code[i][j], 2473e505edaeSJeff LaBundy (state & mask) == val); 2474e505edaeSJeff LaBundy } 247595215d3dSJeff LaBundy 247695215d3dSJeff LaBundy input_sync(iqs7222->keypad); 247795215d3dSJeff LaBundy 247895215d3dSJeff LaBundy for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++) 247995215d3dSJeff LaBundy input_report_key(iqs7222->keypad, 248095215d3dSJeff LaBundy iqs7222->sl_code[i][j], 0); 2481e505edaeSJeff LaBundy } 2482e505edaeSJeff LaBundy 2483e505edaeSJeff LaBundy input_sync(iqs7222->keypad); 2484e505edaeSJeff LaBundy 2485e505edaeSJeff LaBundy return 0; 2486e505edaeSJeff LaBundy } 2487e505edaeSJeff LaBundy 2488e505edaeSJeff LaBundy static irqreturn_t iqs7222_irq(int irq, void *context) 2489e505edaeSJeff LaBundy { 2490e505edaeSJeff LaBundy struct iqs7222_private *iqs7222 = context; 2491e505edaeSJeff LaBundy 2492e505edaeSJeff LaBundy return iqs7222_report(iqs7222) ? IRQ_NONE : IRQ_HANDLED; 2493e505edaeSJeff LaBundy } 2494e505edaeSJeff LaBundy 2495e505edaeSJeff LaBundy static int iqs7222_probe(struct i2c_client *client) 2496e505edaeSJeff LaBundy { 2497e505edaeSJeff LaBundy struct iqs7222_private *iqs7222; 2498e505edaeSJeff LaBundy unsigned long irq_flags; 2499e505edaeSJeff LaBundy int error, irq; 2500e505edaeSJeff LaBundy 2501e505edaeSJeff LaBundy iqs7222 = devm_kzalloc(&client->dev, sizeof(*iqs7222), GFP_KERNEL); 2502e505edaeSJeff LaBundy if (!iqs7222) 2503e505edaeSJeff LaBundy return -ENOMEM; 2504e505edaeSJeff LaBundy 2505e505edaeSJeff LaBundy i2c_set_clientdata(client, iqs7222); 2506e505edaeSJeff LaBundy iqs7222->client = client; 2507e505edaeSJeff LaBundy 2508e505edaeSJeff LaBundy iqs7222->keypad = devm_input_allocate_device(&client->dev); 2509e505edaeSJeff LaBundy if (!iqs7222->keypad) 2510e505edaeSJeff LaBundy return -ENOMEM; 2511e505edaeSJeff LaBundy 2512e505edaeSJeff LaBundy iqs7222->keypad->name = client->name; 2513e505edaeSJeff LaBundy iqs7222->keypad->id.bustype = BUS_I2C; 2514e505edaeSJeff LaBundy 2515e505edaeSJeff LaBundy /* 2516e505edaeSJeff LaBundy * The RDY pin behaves as an interrupt, but must also be polled ahead 2517e505edaeSJeff LaBundy * of unsolicited I2C communication. As such, it is first opened as a 2518e505edaeSJeff LaBundy * GPIO and then passed to gpiod_to_irq() to register the interrupt. 2519e505edaeSJeff LaBundy */ 2520e505edaeSJeff LaBundy iqs7222->irq_gpio = devm_gpiod_get(&client->dev, "irq", GPIOD_IN); 2521e505edaeSJeff LaBundy if (IS_ERR(iqs7222->irq_gpio)) { 2522e505edaeSJeff LaBundy error = PTR_ERR(iqs7222->irq_gpio); 2523e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n", 2524e505edaeSJeff LaBundy error); 2525e505edaeSJeff LaBundy return error; 2526e505edaeSJeff LaBundy } 2527e505edaeSJeff LaBundy 2528e505edaeSJeff LaBundy iqs7222->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", 2529e505edaeSJeff LaBundy GPIOD_OUT_HIGH); 2530e505edaeSJeff LaBundy if (IS_ERR(iqs7222->reset_gpio)) { 2531e505edaeSJeff LaBundy error = PTR_ERR(iqs7222->reset_gpio); 2532e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to request reset GPIO: %d\n", 2533e505edaeSJeff LaBundy error); 2534e505edaeSJeff LaBundy return error; 2535e505edaeSJeff LaBundy } 2536e505edaeSJeff LaBundy 2537e505edaeSJeff LaBundy error = iqs7222_hard_reset(iqs7222); 2538e505edaeSJeff LaBundy if (error) 2539e505edaeSJeff LaBundy return error; 2540e505edaeSJeff LaBundy 2541e505edaeSJeff LaBundy error = iqs7222_dev_info(iqs7222); 2542e505edaeSJeff LaBundy if (error) 2543e505edaeSJeff LaBundy return error; 2544e505edaeSJeff LaBundy 2545e505edaeSJeff LaBundy error = iqs7222_dev_init(iqs7222, READ); 2546e505edaeSJeff LaBundy if (error) 2547e505edaeSJeff LaBundy return error; 2548e505edaeSJeff LaBundy 2549e505edaeSJeff LaBundy error = iqs7222_parse_all(iqs7222); 2550e505edaeSJeff LaBundy if (error) 2551e505edaeSJeff LaBundy return error; 2552e505edaeSJeff LaBundy 2553e505edaeSJeff LaBundy error = iqs7222_dev_init(iqs7222, WRITE); 2554e505edaeSJeff LaBundy if (error) 2555e505edaeSJeff LaBundy return error; 2556e505edaeSJeff LaBundy 2557e505edaeSJeff LaBundy error = iqs7222_report(iqs7222); 2558e505edaeSJeff LaBundy if (error) 2559e505edaeSJeff LaBundy return error; 2560e505edaeSJeff LaBundy 2561e505edaeSJeff LaBundy error = input_register_device(iqs7222->keypad); 2562e505edaeSJeff LaBundy if (error) { 2563e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to register device: %d\n", error); 2564e505edaeSJeff LaBundy return error; 2565e505edaeSJeff LaBundy } 2566e505edaeSJeff LaBundy 2567e505edaeSJeff LaBundy irq = gpiod_to_irq(iqs7222->irq_gpio); 2568e505edaeSJeff LaBundy if (irq < 0) 2569e505edaeSJeff LaBundy return irq; 2570e505edaeSJeff LaBundy 2571e505edaeSJeff LaBundy irq_flags = gpiod_is_active_low(iqs7222->irq_gpio) ? IRQF_TRIGGER_LOW 2572e505edaeSJeff LaBundy : IRQF_TRIGGER_HIGH; 2573e505edaeSJeff LaBundy irq_flags |= IRQF_ONESHOT; 2574e505edaeSJeff LaBundy 2575e505edaeSJeff LaBundy error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7222_irq, 2576e505edaeSJeff LaBundy irq_flags, client->name, iqs7222); 2577e505edaeSJeff LaBundy if (error) 2578e505edaeSJeff LaBundy dev_err(&client->dev, "Failed to request IRQ: %d\n", error); 2579e505edaeSJeff LaBundy 2580e505edaeSJeff LaBundy return error; 2581e505edaeSJeff LaBundy } 2582e505edaeSJeff LaBundy 2583e505edaeSJeff LaBundy static const struct of_device_id iqs7222_of_match[] = { 2584e505edaeSJeff LaBundy { .compatible = "azoteq,iqs7222a" }, 2585e505edaeSJeff LaBundy { .compatible = "azoteq,iqs7222b" }, 2586e505edaeSJeff LaBundy { .compatible = "azoteq,iqs7222c" }, 2587e505edaeSJeff LaBundy { } 2588e505edaeSJeff LaBundy }; 2589e505edaeSJeff LaBundy MODULE_DEVICE_TABLE(of, iqs7222_of_match); 2590e505edaeSJeff LaBundy 2591e505edaeSJeff LaBundy static struct i2c_driver iqs7222_i2c_driver = { 2592e505edaeSJeff LaBundy .driver = { 2593e505edaeSJeff LaBundy .name = "iqs7222", 2594e505edaeSJeff LaBundy .of_match_table = iqs7222_of_match, 2595e505edaeSJeff LaBundy }, 2596d8bde56dSUwe Kleine-König .probe = iqs7222_probe, 2597e505edaeSJeff LaBundy }; 2598e505edaeSJeff LaBundy module_i2c_driver(iqs7222_i2c_driver); 2599e505edaeSJeff LaBundy 2600e505edaeSJeff LaBundy MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); 2601e505edaeSJeff LaBundy MODULE_DESCRIPTION("Azoteq IQS7222A/B/C Capacitive Touch Controller"); 2602e505edaeSJeff LaBundy MODULE_LICENSE("GPL"); 2603