162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Azoteq IQS7222A/B/C/D Capacitive Touch Controller 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2022 Jeff LaBundy <jeff@labundy.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bits.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1362306a36Sopenharmony_ci#include <linux/i2c.h> 1462306a36Sopenharmony_ci#include <linux/input.h> 1562306a36Sopenharmony_ci#include <linux/input/touchscreen.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/ktime.h> 1962306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/property.h> 2262306a36Sopenharmony_ci#include <linux/slab.h> 2362306a36Sopenharmony_ci#include <asm/unaligned.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define IQS7222_PROD_NUM 0x00 2662306a36Sopenharmony_ci#define IQS7222_PROD_NUM_A 840 2762306a36Sopenharmony_ci#define IQS7222_PROD_NUM_B 698 2862306a36Sopenharmony_ci#define IQS7222_PROD_NUM_C 863 2962306a36Sopenharmony_ci#define IQS7222_PROD_NUM_D 1046 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define IQS7222_SYS_STATUS 0x10 3262306a36Sopenharmony_ci#define IQS7222_SYS_STATUS_RESET BIT(3) 3362306a36Sopenharmony_ci#define IQS7222_SYS_STATUS_ATI_ERROR BIT(1) 3462306a36Sopenharmony_ci#define IQS7222_SYS_STATUS_ATI_ACTIVE BIT(0) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define IQS7222_CHAN_SETUP_0_REF_MODE_MASK GENMASK(15, 14) 3762306a36Sopenharmony_ci#define IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW BIT(15) 3862306a36Sopenharmony_ci#define IQS7222_CHAN_SETUP_0_REF_MODE_REF BIT(14) 3962306a36Sopenharmony_ci#define IQS7222_CHAN_SETUP_0_CHAN_EN BIT(8) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK GENMASK(2, 0) 4262306a36Sopenharmony_ci#define IQS7222_SLDR_SETUP_2_RES_MASK GENMASK(15, 8) 4362306a36Sopenharmony_ci#define IQS7222_SLDR_SETUP_2_RES_SHIFT 8 4462306a36Sopenharmony_ci#define IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK GENMASK(7, 0) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define IQS7222_GPIO_SETUP_0_GPIO_EN BIT(0) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define IQS7222_SYS_SETUP 0xD0 4962306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_INTF_MODE_MASK GENMASK(7, 6) 5062306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_INTF_MODE_TOUCH BIT(7) 5162306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_INTF_MODE_EVENT BIT(6) 5262306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_PWR_MODE_MASK GENMASK(5, 4) 5362306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_PWR_MODE_AUTO IQS7222_SYS_SETUP_PWR_MODE_MASK 5462306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_REDO_ATI BIT(2) 5562306a36Sopenharmony_ci#define IQS7222_SYS_SETUP_ACK_RESET BIT(0) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_ATI BIT(12) 5862306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_SLDR BIT(10) 5962306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_TPAD IQS7222_EVENT_MASK_SLDR 6062306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_TOUCH BIT(1) 6162306a36Sopenharmony_ci#define IQS7222_EVENT_MASK_PROX BIT(0) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define IQS7222_COMMS_HOLD BIT(0) 6462306a36Sopenharmony_ci#define IQS7222_COMMS_ERROR 0xEEEE 6562306a36Sopenharmony_ci#define IQS7222_COMMS_RETRY_MS 50 6662306a36Sopenharmony_ci#define IQS7222_COMMS_TIMEOUT_MS 100 6762306a36Sopenharmony_ci#define IQS7222_RESET_TIMEOUT_MS 250 6862306a36Sopenharmony_ci#define IQS7222_ATI_TIMEOUT_MS 2000 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define IQS7222_MAX_COLS_STAT 8 7162306a36Sopenharmony_ci#define IQS7222_MAX_COLS_CYCLE 3 7262306a36Sopenharmony_ci#define IQS7222_MAX_COLS_GLBL 3 7362306a36Sopenharmony_ci#define IQS7222_MAX_COLS_BTN 3 7462306a36Sopenharmony_ci#define IQS7222_MAX_COLS_CHAN 6 7562306a36Sopenharmony_ci#define IQS7222_MAX_COLS_FILT 2 7662306a36Sopenharmony_ci#define IQS7222_MAX_COLS_SLDR 11 7762306a36Sopenharmony_ci#define IQS7222_MAX_COLS_TPAD 24 7862306a36Sopenharmony_ci#define IQS7222_MAX_COLS_GPIO 3 7962306a36Sopenharmony_ci#define IQS7222_MAX_COLS_SYS 13 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define IQS7222_MAX_CHAN 20 8262306a36Sopenharmony_ci#define IQS7222_MAX_SLDR 2 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define IQS7222_NUM_RETRIES 5 8562306a36Sopenharmony_ci#define IQS7222_REG_OFFSET 0x100 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cienum iqs7222_reg_key_id { 8862306a36Sopenharmony_ci IQS7222_REG_KEY_NONE, 8962306a36Sopenharmony_ci IQS7222_REG_KEY_PROX, 9062306a36Sopenharmony_ci IQS7222_REG_KEY_TOUCH, 9162306a36Sopenharmony_ci IQS7222_REG_KEY_DEBOUNCE, 9262306a36Sopenharmony_ci IQS7222_REG_KEY_TAP, 9362306a36Sopenharmony_ci IQS7222_REG_KEY_TAP_LEGACY, 9462306a36Sopenharmony_ci IQS7222_REG_KEY_AXIAL, 9562306a36Sopenharmony_ci IQS7222_REG_KEY_AXIAL_LEGACY, 9662306a36Sopenharmony_ci IQS7222_REG_KEY_WHEEL, 9762306a36Sopenharmony_ci IQS7222_REG_KEY_NO_WHEEL, 9862306a36Sopenharmony_ci IQS7222_REG_KEY_RESERVED 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cienum iqs7222_reg_grp_id { 10262306a36Sopenharmony_ci IQS7222_REG_GRP_STAT, 10362306a36Sopenharmony_ci IQS7222_REG_GRP_FILT, 10462306a36Sopenharmony_ci IQS7222_REG_GRP_CYCLE, 10562306a36Sopenharmony_ci IQS7222_REG_GRP_GLBL, 10662306a36Sopenharmony_ci IQS7222_REG_GRP_BTN, 10762306a36Sopenharmony_ci IQS7222_REG_GRP_CHAN, 10862306a36Sopenharmony_ci IQS7222_REG_GRP_SLDR, 10962306a36Sopenharmony_ci IQS7222_REG_GRP_TPAD, 11062306a36Sopenharmony_ci IQS7222_REG_GRP_GPIO, 11162306a36Sopenharmony_ci IQS7222_REG_GRP_SYS, 11262306a36Sopenharmony_ci IQS7222_NUM_REG_GRPS 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic const char * const iqs7222_reg_grp_names[IQS7222_NUM_REG_GRPS] = { 11662306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = "cycle-%d", 11762306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = "channel-%d", 11862306a36Sopenharmony_ci [IQS7222_REG_GRP_SLDR] = "slider-%d", 11962306a36Sopenharmony_ci [IQS7222_REG_GRP_TPAD] = "trackpad", 12062306a36Sopenharmony_ci [IQS7222_REG_GRP_GPIO] = "gpio-%d", 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = { 12462306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = IQS7222_MAX_COLS_STAT, 12562306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = IQS7222_MAX_COLS_CYCLE, 12662306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = IQS7222_MAX_COLS_GLBL, 12762306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = IQS7222_MAX_COLS_BTN, 12862306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN, 12962306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT, 13062306a36Sopenharmony_ci [IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR, 13162306a36Sopenharmony_ci [IQS7222_REG_GRP_TPAD] = IQS7222_MAX_COLS_TPAD, 13262306a36Sopenharmony_ci [IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO, 13362306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS, 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, }; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistruct iqs7222_event_desc { 13962306a36Sopenharmony_ci const char *name; 14062306a36Sopenharmony_ci u16 link; 14162306a36Sopenharmony_ci u16 mask; 14262306a36Sopenharmony_ci u16 val; 14362306a36Sopenharmony_ci u16 strict; 14462306a36Sopenharmony_ci u16 enable; 14562306a36Sopenharmony_ci enum iqs7222_reg_key_id reg_key; 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic const struct iqs7222_event_desc iqs7222_kp_events[] = { 14962306a36Sopenharmony_ci { 15062306a36Sopenharmony_ci .name = "event-prox", 15162306a36Sopenharmony_ci .enable = IQS7222_EVENT_MASK_PROX, 15262306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_PROX, 15362306a36Sopenharmony_ci }, 15462306a36Sopenharmony_ci { 15562306a36Sopenharmony_ci .name = "event-touch", 15662306a36Sopenharmony_ci .enable = IQS7222_EVENT_MASK_TOUCH, 15762306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TOUCH, 15862306a36Sopenharmony_ci }, 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic const struct iqs7222_event_desc iqs7222_sl_events[] = { 16262306a36Sopenharmony_ci { .name = "event-press", }, 16362306a36Sopenharmony_ci { 16462306a36Sopenharmony_ci .name = "event-tap", 16562306a36Sopenharmony_ci .mask = BIT(0), 16662306a36Sopenharmony_ci .val = BIT(0), 16762306a36Sopenharmony_ci .enable = BIT(0), 16862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TAP, 16962306a36Sopenharmony_ci }, 17062306a36Sopenharmony_ci { 17162306a36Sopenharmony_ci .name = "event-swipe-pos", 17262306a36Sopenharmony_ci .mask = BIT(5) | BIT(1), 17362306a36Sopenharmony_ci .val = BIT(1), 17462306a36Sopenharmony_ci .enable = BIT(1), 17562306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 17662306a36Sopenharmony_ci }, 17762306a36Sopenharmony_ci { 17862306a36Sopenharmony_ci .name = "event-swipe-neg", 17962306a36Sopenharmony_ci .mask = BIT(5) | BIT(1), 18062306a36Sopenharmony_ci .val = BIT(5) | BIT(1), 18162306a36Sopenharmony_ci .enable = BIT(1), 18262306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 18362306a36Sopenharmony_ci }, 18462306a36Sopenharmony_ci { 18562306a36Sopenharmony_ci .name = "event-flick-pos", 18662306a36Sopenharmony_ci .mask = BIT(5) | BIT(2), 18762306a36Sopenharmony_ci .val = BIT(2), 18862306a36Sopenharmony_ci .enable = BIT(2), 18962306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 19062306a36Sopenharmony_ci }, 19162306a36Sopenharmony_ci { 19262306a36Sopenharmony_ci .name = "event-flick-neg", 19362306a36Sopenharmony_ci .mask = BIT(5) | BIT(2), 19462306a36Sopenharmony_ci .val = BIT(5) | BIT(2), 19562306a36Sopenharmony_ci .enable = BIT(2), 19662306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 19762306a36Sopenharmony_ci }, 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic const struct iqs7222_event_desc iqs7222_tp_events[] = { 20162306a36Sopenharmony_ci { 20262306a36Sopenharmony_ci .name = "event-press", 20362306a36Sopenharmony_ci .link = BIT(7), 20462306a36Sopenharmony_ci }, 20562306a36Sopenharmony_ci { 20662306a36Sopenharmony_ci .name = "event-tap", 20762306a36Sopenharmony_ci .link = BIT(0), 20862306a36Sopenharmony_ci .mask = BIT(0), 20962306a36Sopenharmony_ci .val = BIT(0), 21062306a36Sopenharmony_ci .enable = BIT(0), 21162306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TAP, 21262306a36Sopenharmony_ci }, 21362306a36Sopenharmony_ci { 21462306a36Sopenharmony_ci .name = "event-swipe-x-pos", 21562306a36Sopenharmony_ci .link = BIT(2), 21662306a36Sopenharmony_ci .mask = BIT(2) | BIT(1), 21762306a36Sopenharmony_ci .val = BIT(2), 21862306a36Sopenharmony_ci .strict = BIT(4), 21962306a36Sopenharmony_ci .enable = BIT(1), 22062306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 22162306a36Sopenharmony_ci }, 22262306a36Sopenharmony_ci { 22362306a36Sopenharmony_ci .name = "event-swipe-y-pos", 22462306a36Sopenharmony_ci .link = BIT(3), 22562306a36Sopenharmony_ci .mask = BIT(3) | BIT(1), 22662306a36Sopenharmony_ci .val = BIT(3), 22762306a36Sopenharmony_ci .strict = BIT(3), 22862306a36Sopenharmony_ci .enable = BIT(1), 22962306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 23062306a36Sopenharmony_ci }, 23162306a36Sopenharmony_ci { 23262306a36Sopenharmony_ci .name = "event-swipe-x-neg", 23362306a36Sopenharmony_ci .link = BIT(4), 23462306a36Sopenharmony_ci .mask = BIT(4) | BIT(1), 23562306a36Sopenharmony_ci .val = BIT(4), 23662306a36Sopenharmony_ci .strict = BIT(4), 23762306a36Sopenharmony_ci .enable = BIT(1), 23862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 23962306a36Sopenharmony_ci }, 24062306a36Sopenharmony_ci { 24162306a36Sopenharmony_ci .name = "event-swipe-y-neg", 24262306a36Sopenharmony_ci .link = BIT(5), 24362306a36Sopenharmony_ci .mask = BIT(5) | BIT(1), 24462306a36Sopenharmony_ci .val = BIT(5), 24562306a36Sopenharmony_ci .strict = BIT(3), 24662306a36Sopenharmony_ci .enable = BIT(1), 24762306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 24862306a36Sopenharmony_ci }, 24962306a36Sopenharmony_ci { 25062306a36Sopenharmony_ci .name = "event-flick-x-pos", 25162306a36Sopenharmony_ci .link = BIT(2), 25262306a36Sopenharmony_ci .mask = BIT(2) | BIT(1), 25362306a36Sopenharmony_ci .val = BIT(2) | BIT(1), 25462306a36Sopenharmony_ci .strict = BIT(4), 25562306a36Sopenharmony_ci .enable = BIT(2), 25662306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 25762306a36Sopenharmony_ci }, 25862306a36Sopenharmony_ci { 25962306a36Sopenharmony_ci .name = "event-flick-y-pos", 26062306a36Sopenharmony_ci .link = BIT(3), 26162306a36Sopenharmony_ci .mask = BIT(3) | BIT(1), 26262306a36Sopenharmony_ci .val = BIT(3) | BIT(1), 26362306a36Sopenharmony_ci .strict = BIT(3), 26462306a36Sopenharmony_ci .enable = BIT(2), 26562306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 26662306a36Sopenharmony_ci }, 26762306a36Sopenharmony_ci { 26862306a36Sopenharmony_ci .name = "event-flick-x-neg", 26962306a36Sopenharmony_ci .link = BIT(4), 27062306a36Sopenharmony_ci .mask = BIT(4) | BIT(1), 27162306a36Sopenharmony_ci .val = BIT(4) | BIT(1), 27262306a36Sopenharmony_ci .strict = BIT(4), 27362306a36Sopenharmony_ci .enable = BIT(2), 27462306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 27562306a36Sopenharmony_ci }, 27662306a36Sopenharmony_ci { 27762306a36Sopenharmony_ci .name = "event-flick-y-neg", 27862306a36Sopenharmony_ci .link = BIT(5), 27962306a36Sopenharmony_ci .mask = BIT(5) | BIT(1), 28062306a36Sopenharmony_ci .val = BIT(5) | BIT(1), 28162306a36Sopenharmony_ci .strict = BIT(3), 28262306a36Sopenharmony_ci .enable = BIT(2), 28362306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 28462306a36Sopenharmony_ci }, 28562306a36Sopenharmony_ci}; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistruct iqs7222_reg_grp_desc { 28862306a36Sopenharmony_ci u16 base; 28962306a36Sopenharmony_ci int num_row; 29062306a36Sopenharmony_ci int num_col; 29162306a36Sopenharmony_ci}; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistruct iqs7222_dev_desc { 29462306a36Sopenharmony_ci u16 prod_num; 29562306a36Sopenharmony_ci u16 fw_major; 29662306a36Sopenharmony_ci u16 fw_minor; 29762306a36Sopenharmony_ci u16 sldr_res; 29862306a36Sopenharmony_ci u16 touch_link; 29962306a36Sopenharmony_ci u16 wheel_enable; 30062306a36Sopenharmony_ci int allow_offset; 30162306a36Sopenharmony_ci int event_offset; 30262306a36Sopenharmony_ci int comms_offset; 30362306a36Sopenharmony_ci bool legacy_gesture; 30462306a36Sopenharmony_ci struct iqs7222_reg_grp_desc reg_grps[IQS7222_NUM_REG_GRPS]; 30562306a36Sopenharmony_ci}; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic const struct iqs7222_dev_desc iqs7222_devs[] = { 30862306a36Sopenharmony_ci { 30962306a36Sopenharmony_ci .prod_num = IQS7222_PROD_NUM_A, 31062306a36Sopenharmony_ci .fw_major = 1, 31162306a36Sopenharmony_ci .fw_minor = 13, 31262306a36Sopenharmony_ci .sldr_res = U8_MAX * 16, 31362306a36Sopenharmony_ci .touch_link = 1768, 31462306a36Sopenharmony_ci .allow_offset = 9, 31562306a36Sopenharmony_ci .event_offset = 10, 31662306a36Sopenharmony_ci .comms_offset = 12, 31762306a36Sopenharmony_ci .reg_grps = { 31862306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = { 31962306a36Sopenharmony_ci .base = IQS7222_SYS_STATUS, 32062306a36Sopenharmony_ci .num_row = 1, 32162306a36Sopenharmony_ci .num_col = 8, 32262306a36Sopenharmony_ci }, 32362306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = { 32462306a36Sopenharmony_ci .base = 0x8000, 32562306a36Sopenharmony_ci .num_row = 7, 32662306a36Sopenharmony_ci .num_col = 3, 32762306a36Sopenharmony_ci }, 32862306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = { 32962306a36Sopenharmony_ci .base = 0x8700, 33062306a36Sopenharmony_ci .num_row = 1, 33162306a36Sopenharmony_ci .num_col = 3, 33262306a36Sopenharmony_ci }, 33362306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = { 33462306a36Sopenharmony_ci .base = 0x9000, 33562306a36Sopenharmony_ci .num_row = 12, 33662306a36Sopenharmony_ci .num_col = 3, 33762306a36Sopenharmony_ci }, 33862306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = { 33962306a36Sopenharmony_ci .base = 0xA000, 34062306a36Sopenharmony_ci .num_row = 12, 34162306a36Sopenharmony_ci .num_col = 6, 34262306a36Sopenharmony_ci }, 34362306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = { 34462306a36Sopenharmony_ci .base = 0xAC00, 34562306a36Sopenharmony_ci .num_row = 1, 34662306a36Sopenharmony_ci .num_col = 2, 34762306a36Sopenharmony_ci }, 34862306a36Sopenharmony_ci [IQS7222_REG_GRP_SLDR] = { 34962306a36Sopenharmony_ci .base = 0xB000, 35062306a36Sopenharmony_ci .num_row = 2, 35162306a36Sopenharmony_ci .num_col = 11, 35262306a36Sopenharmony_ci }, 35362306a36Sopenharmony_ci [IQS7222_REG_GRP_GPIO] = { 35462306a36Sopenharmony_ci .base = 0xC000, 35562306a36Sopenharmony_ci .num_row = 1, 35662306a36Sopenharmony_ci .num_col = 3, 35762306a36Sopenharmony_ci }, 35862306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = { 35962306a36Sopenharmony_ci .base = IQS7222_SYS_SETUP, 36062306a36Sopenharmony_ci .num_row = 1, 36162306a36Sopenharmony_ci .num_col = 13, 36262306a36Sopenharmony_ci }, 36362306a36Sopenharmony_ci }, 36462306a36Sopenharmony_ci }, 36562306a36Sopenharmony_ci { 36662306a36Sopenharmony_ci .prod_num = IQS7222_PROD_NUM_A, 36762306a36Sopenharmony_ci .fw_major = 1, 36862306a36Sopenharmony_ci .fw_minor = 12, 36962306a36Sopenharmony_ci .sldr_res = U8_MAX * 16, 37062306a36Sopenharmony_ci .touch_link = 1768, 37162306a36Sopenharmony_ci .allow_offset = 9, 37262306a36Sopenharmony_ci .event_offset = 10, 37362306a36Sopenharmony_ci .comms_offset = 12, 37462306a36Sopenharmony_ci .legacy_gesture = true, 37562306a36Sopenharmony_ci .reg_grps = { 37662306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = { 37762306a36Sopenharmony_ci .base = IQS7222_SYS_STATUS, 37862306a36Sopenharmony_ci .num_row = 1, 37962306a36Sopenharmony_ci .num_col = 8, 38062306a36Sopenharmony_ci }, 38162306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = { 38262306a36Sopenharmony_ci .base = 0x8000, 38362306a36Sopenharmony_ci .num_row = 7, 38462306a36Sopenharmony_ci .num_col = 3, 38562306a36Sopenharmony_ci }, 38662306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = { 38762306a36Sopenharmony_ci .base = 0x8700, 38862306a36Sopenharmony_ci .num_row = 1, 38962306a36Sopenharmony_ci .num_col = 3, 39062306a36Sopenharmony_ci }, 39162306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = { 39262306a36Sopenharmony_ci .base = 0x9000, 39362306a36Sopenharmony_ci .num_row = 12, 39462306a36Sopenharmony_ci .num_col = 3, 39562306a36Sopenharmony_ci }, 39662306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = { 39762306a36Sopenharmony_ci .base = 0xA000, 39862306a36Sopenharmony_ci .num_row = 12, 39962306a36Sopenharmony_ci .num_col = 6, 40062306a36Sopenharmony_ci }, 40162306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = { 40262306a36Sopenharmony_ci .base = 0xAC00, 40362306a36Sopenharmony_ci .num_row = 1, 40462306a36Sopenharmony_ci .num_col = 2, 40562306a36Sopenharmony_ci }, 40662306a36Sopenharmony_ci [IQS7222_REG_GRP_SLDR] = { 40762306a36Sopenharmony_ci .base = 0xB000, 40862306a36Sopenharmony_ci .num_row = 2, 40962306a36Sopenharmony_ci .num_col = 11, 41062306a36Sopenharmony_ci }, 41162306a36Sopenharmony_ci [IQS7222_REG_GRP_GPIO] = { 41262306a36Sopenharmony_ci .base = 0xC000, 41362306a36Sopenharmony_ci .num_row = 1, 41462306a36Sopenharmony_ci .num_col = 3, 41562306a36Sopenharmony_ci }, 41662306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = { 41762306a36Sopenharmony_ci .base = IQS7222_SYS_SETUP, 41862306a36Sopenharmony_ci .num_row = 1, 41962306a36Sopenharmony_ci .num_col = 13, 42062306a36Sopenharmony_ci }, 42162306a36Sopenharmony_ci }, 42262306a36Sopenharmony_ci }, 42362306a36Sopenharmony_ci { 42462306a36Sopenharmony_ci .prod_num = IQS7222_PROD_NUM_B, 42562306a36Sopenharmony_ci .fw_major = 1, 42662306a36Sopenharmony_ci .fw_minor = 43, 42762306a36Sopenharmony_ci .event_offset = 10, 42862306a36Sopenharmony_ci .comms_offset = 11, 42962306a36Sopenharmony_ci .reg_grps = { 43062306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = { 43162306a36Sopenharmony_ci .base = IQS7222_SYS_STATUS, 43262306a36Sopenharmony_ci .num_row = 1, 43362306a36Sopenharmony_ci .num_col = 6, 43462306a36Sopenharmony_ci }, 43562306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = { 43662306a36Sopenharmony_ci .base = 0x8000, 43762306a36Sopenharmony_ci .num_row = 10, 43862306a36Sopenharmony_ci .num_col = 2, 43962306a36Sopenharmony_ci }, 44062306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = { 44162306a36Sopenharmony_ci .base = 0x8A00, 44262306a36Sopenharmony_ci .num_row = 1, 44362306a36Sopenharmony_ci .num_col = 3, 44462306a36Sopenharmony_ci }, 44562306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = { 44662306a36Sopenharmony_ci .base = 0x9000, 44762306a36Sopenharmony_ci .num_row = 20, 44862306a36Sopenharmony_ci .num_col = 2, 44962306a36Sopenharmony_ci }, 45062306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = { 45162306a36Sopenharmony_ci .base = 0xB000, 45262306a36Sopenharmony_ci .num_row = 20, 45362306a36Sopenharmony_ci .num_col = 4, 45462306a36Sopenharmony_ci }, 45562306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = { 45662306a36Sopenharmony_ci .base = 0xC400, 45762306a36Sopenharmony_ci .num_row = 1, 45862306a36Sopenharmony_ci .num_col = 2, 45962306a36Sopenharmony_ci }, 46062306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = { 46162306a36Sopenharmony_ci .base = IQS7222_SYS_SETUP, 46262306a36Sopenharmony_ci .num_row = 1, 46362306a36Sopenharmony_ci .num_col = 13, 46462306a36Sopenharmony_ci }, 46562306a36Sopenharmony_ci }, 46662306a36Sopenharmony_ci }, 46762306a36Sopenharmony_ci { 46862306a36Sopenharmony_ci .prod_num = IQS7222_PROD_NUM_B, 46962306a36Sopenharmony_ci .fw_major = 1, 47062306a36Sopenharmony_ci .fw_minor = 27, 47162306a36Sopenharmony_ci .reg_grps = { 47262306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = { 47362306a36Sopenharmony_ci .base = IQS7222_SYS_STATUS, 47462306a36Sopenharmony_ci .num_row = 1, 47562306a36Sopenharmony_ci .num_col = 6, 47662306a36Sopenharmony_ci }, 47762306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = { 47862306a36Sopenharmony_ci .base = 0x8000, 47962306a36Sopenharmony_ci .num_row = 10, 48062306a36Sopenharmony_ci .num_col = 2, 48162306a36Sopenharmony_ci }, 48262306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = { 48362306a36Sopenharmony_ci .base = 0x8A00, 48462306a36Sopenharmony_ci .num_row = 1, 48562306a36Sopenharmony_ci .num_col = 3, 48662306a36Sopenharmony_ci }, 48762306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = { 48862306a36Sopenharmony_ci .base = 0x9000, 48962306a36Sopenharmony_ci .num_row = 20, 49062306a36Sopenharmony_ci .num_col = 2, 49162306a36Sopenharmony_ci }, 49262306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = { 49362306a36Sopenharmony_ci .base = 0xB000, 49462306a36Sopenharmony_ci .num_row = 20, 49562306a36Sopenharmony_ci .num_col = 4, 49662306a36Sopenharmony_ci }, 49762306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = { 49862306a36Sopenharmony_ci .base = 0xC400, 49962306a36Sopenharmony_ci .num_row = 1, 50062306a36Sopenharmony_ci .num_col = 2, 50162306a36Sopenharmony_ci }, 50262306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = { 50362306a36Sopenharmony_ci .base = IQS7222_SYS_SETUP, 50462306a36Sopenharmony_ci .num_row = 1, 50562306a36Sopenharmony_ci .num_col = 10, 50662306a36Sopenharmony_ci }, 50762306a36Sopenharmony_ci }, 50862306a36Sopenharmony_ci }, 50962306a36Sopenharmony_ci { 51062306a36Sopenharmony_ci .prod_num = IQS7222_PROD_NUM_C, 51162306a36Sopenharmony_ci .fw_major = 2, 51262306a36Sopenharmony_ci .fw_minor = 6, 51362306a36Sopenharmony_ci .sldr_res = U16_MAX, 51462306a36Sopenharmony_ci .touch_link = 1686, 51562306a36Sopenharmony_ci .wheel_enable = BIT(3), 51662306a36Sopenharmony_ci .event_offset = 9, 51762306a36Sopenharmony_ci .comms_offset = 10, 51862306a36Sopenharmony_ci .reg_grps = { 51962306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = { 52062306a36Sopenharmony_ci .base = IQS7222_SYS_STATUS, 52162306a36Sopenharmony_ci .num_row = 1, 52262306a36Sopenharmony_ci .num_col = 6, 52362306a36Sopenharmony_ci }, 52462306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = { 52562306a36Sopenharmony_ci .base = 0x8000, 52662306a36Sopenharmony_ci .num_row = 5, 52762306a36Sopenharmony_ci .num_col = 3, 52862306a36Sopenharmony_ci }, 52962306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = { 53062306a36Sopenharmony_ci .base = 0x8500, 53162306a36Sopenharmony_ci .num_row = 1, 53262306a36Sopenharmony_ci .num_col = 3, 53362306a36Sopenharmony_ci }, 53462306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = { 53562306a36Sopenharmony_ci .base = 0x9000, 53662306a36Sopenharmony_ci .num_row = 10, 53762306a36Sopenharmony_ci .num_col = 3, 53862306a36Sopenharmony_ci }, 53962306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = { 54062306a36Sopenharmony_ci .base = 0xA000, 54162306a36Sopenharmony_ci .num_row = 10, 54262306a36Sopenharmony_ci .num_col = 6, 54362306a36Sopenharmony_ci }, 54462306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = { 54562306a36Sopenharmony_ci .base = 0xAA00, 54662306a36Sopenharmony_ci .num_row = 1, 54762306a36Sopenharmony_ci .num_col = 2, 54862306a36Sopenharmony_ci }, 54962306a36Sopenharmony_ci [IQS7222_REG_GRP_SLDR] = { 55062306a36Sopenharmony_ci .base = 0xB000, 55162306a36Sopenharmony_ci .num_row = 2, 55262306a36Sopenharmony_ci .num_col = 10, 55362306a36Sopenharmony_ci }, 55462306a36Sopenharmony_ci [IQS7222_REG_GRP_GPIO] = { 55562306a36Sopenharmony_ci .base = 0xC000, 55662306a36Sopenharmony_ci .num_row = 3, 55762306a36Sopenharmony_ci .num_col = 3, 55862306a36Sopenharmony_ci }, 55962306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = { 56062306a36Sopenharmony_ci .base = IQS7222_SYS_SETUP, 56162306a36Sopenharmony_ci .num_row = 1, 56262306a36Sopenharmony_ci .num_col = 12, 56362306a36Sopenharmony_ci }, 56462306a36Sopenharmony_ci }, 56562306a36Sopenharmony_ci }, 56662306a36Sopenharmony_ci { 56762306a36Sopenharmony_ci .prod_num = IQS7222_PROD_NUM_C, 56862306a36Sopenharmony_ci .fw_major = 1, 56962306a36Sopenharmony_ci .fw_minor = 13, 57062306a36Sopenharmony_ci .sldr_res = U16_MAX, 57162306a36Sopenharmony_ci .touch_link = 1674, 57262306a36Sopenharmony_ci .wheel_enable = BIT(3), 57362306a36Sopenharmony_ci .event_offset = 9, 57462306a36Sopenharmony_ci .comms_offset = 10, 57562306a36Sopenharmony_ci .reg_grps = { 57662306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = { 57762306a36Sopenharmony_ci .base = IQS7222_SYS_STATUS, 57862306a36Sopenharmony_ci .num_row = 1, 57962306a36Sopenharmony_ci .num_col = 6, 58062306a36Sopenharmony_ci }, 58162306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = { 58262306a36Sopenharmony_ci .base = 0x8000, 58362306a36Sopenharmony_ci .num_row = 5, 58462306a36Sopenharmony_ci .num_col = 3, 58562306a36Sopenharmony_ci }, 58662306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = { 58762306a36Sopenharmony_ci .base = 0x8500, 58862306a36Sopenharmony_ci .num_row = 1, 58962306a36Sopenharmony_ci .num_col = 3, 59062306a36Sopenharmony_ci }, 59162306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = { 59262306a36Sopenharmony_ci .base = 0x9000, 59362306a36Sopenharmony_ci .num_row = 10, 59462306a36Sopenharmony_ci .num_col = 3, 59562306a36Sopenharmony_ci }, 59662306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = { 59762306a36Sopenharmony_ci .base = 0xA000, 59862306a36Sopenharmony_ci .num_row = 10, 59962306a36Sopenharmony_ci .num_col = 6, 60062306a36Sopenharmony_ci }, 60162306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = { 60262306a36Sopenharmony_ci .base = 0xAA00, 60362306a36Sopenharmony_ci .num_row = 1, 60462306a36Sopenharmony_ci .num_col = 2, 60562306a36Sopenharmony_ci }, 60662306a36Sopenharmony_ci [IQS7222_REG_GRP_SLDR] = { 60762306a36Sopenharmony_ci .base = 0xB000, 60862306a36Sopenharmony_ci .num_row = 2, 60962306a36Sopenharmony_ci .num_col = 10, 61062306a36Sopenharmony_ci }, 61162306a36Sopenharmony_ci [IQS7222_REG_GRP_GPIO] = { 61262306a36Sopenharmony_ci .base = 0xC000, 61362306a36Sopenharmony_ci .num_row = 1, 61462306a36Sopenharmony_ci .num_col = 3, 61562306a36Sopenharmony_ci }, 61662306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = { 61762306a36Sopenharmony_ci .base = IQS7222_SYS_SETUP, 61862306a36Sopenharmony_ci .num_row = 1, 61962306a36Sopenharmony_ci .num_col = 11, 62062306a36Sopenharmony_ci }, 62162306a36Sopenharmony_ci }, 62262306a36Sopenharmony_ci }, 62362306a36Sopenharmony_ci { 62462306a36Sopenharmony_ci .prod_num = IQS7222_PROD_NUM_D, 62562306a36Sopenharmony_ci .fw_major = 1, 62662306a36Sopenharmony_ci .fw_minor = 2, 62762306a36Sopenharmony_ci .touch_link = 1770, 62862306a36Sopenharmony_ci .allow_offset = 9, 62962306a36Sopenharmony_ci .event_offset = 10, 63062306a36Sopenharmony_ci .comms_offset = 11, 63162306a36Sopenharmony_ci .reg_grps = { 63262306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = { 63362306a36Sopenharmony_ci .base = IQS7222_SYS_STATUS, 63462306a36Sopenharmony_ci .num_row = 1, 63562306a36Sopenharmony_ci .num_col = 7, 63662306a36Sopenharmony_ci }, 63762306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = { 63862306a36Sopenharmony_ci .base = 0x8000, 63962306a36Sopenharmony_ci .num_row = 7, 64062306a36Sopenharmony_ci .num_col = 2, 64162306a36Sopenharmony_ci }, 64262306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = { 64362306a36Sopenharmony_ci .base = 0x8700, 64462306a36Sopenharmony_ci .num_row = 1, 64562306a36Sopenharmony_ci .num_col = 3, 64662306a36Sopenharmony_ci }, 64762306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = { 64862306a36Sopenharmony_ci .base = 0x9000, 64962306a36Sopenharmony_ci .num_row = 14, 65062306a36Sopenharmony_ci .num_col = 3, 65162306a36Sopenharmony_ci }, 65262306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = { 65362306a36Sopenharmony_ci .base = 0xA000, 65462306a36Sopenharmony_ci .num_row = 14, 65562306a36Sopenharmony_ci .num_col = 4, 65662306a36Sopenharmony_ci }, 65762306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = { 65862306a36Sopenharmony_ci .base = 0xAE00, 65962306a36Sopenharmony_ci .num_row = 1, 66062306a36Sopenharmony_ci .num_col = 2, 66162306a36Sopenharmony_ci }, 66262306a36Sopenharmony_ci [IQS7222_REG_GRP_TPAD] = { 66362306a36Sopenharmony_ci .base = 0xB000, 66462306a36Sopenharmony_ci .num_row = 1, 66562306a36Sopenharmony_ci .num_col = 24, 66662306a36Sopenharmony_ci }, 66762306a36Sopenharmony_ci [IQS7222_REG_GRP_GPIO] = { 66862306a36Sopenharmony_ci .base = 0xC000, 66962306a36Sopenharmony_ci .num_row = 3, 67062306a36Sopenharmony_ci .num_col = 3, 67162306a36Sopenharmony_ci }, 67262306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = { 67362306a36Sopenharmony_ci .base = IQS7222_SYS_SETUP, 67462306a36Sopenharmony_ci .num_row = 1, 67562306a36Sopenharmony_ci .num_col = 12, 67662306a36Sopenharmony_ci }, 67762306a36Sopenharmony_ci }, 67862306a36Sopenharmony_ci }, 67962306a36Sopenharmony_ci { 68062306a36Sopenharmony_ci .prod_num = IQS7222_PROD_NUM_D, 68162306a36Sopenharmony_ci .fw_major = 1, 68262306a36Sopenharmony_ci .fw_minor = 1, 68362306a36Sopenharmony_ci .touch_link = 1774, 68462306a36Sopenharmony_ci .allow_offset = 9, 68562306a36Sopenharmony_ci .event_offset = 10, 68662306a36Sopenharmony_ci .comms_offset = 11, 68762306a36Sopenharmony_ci .reg_grps = { 68862306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = { 68962306a36Sopenharmony_ci .base = IQS7222_SYS_STATUS, 69062306a36Sopenharmony_ci .num_row = 1, 69162306a36Sopenharmony_ci .num_col = 7, 69262306a36Sopenharmony_ci }, 69362306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = { 69462306a36Sopenharmony_ci .base = 0x8000, 69562306a36Sopenharmony_ci .num_row = 7, 69662306a36Sopenharmony_ci .num_col = 2, 69762306a36Sopenharmony_ci }, 69862306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = { 69962306a36Sopenharmony_ci .base = 0x8700, 70062306a36Sopenharmony_ci .num_row = 1, 70162306a36Sopenharmony_ci .num_col = 3, 70262306a36Sopenharmony_ci }, 70362306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = { 70462306a36Sopenharmony_ci .base = 0x9000, 70562306a36Sopenharmony_ci .num_row = 14, 70662306a36Sopenharmony_ci .num_col = 3, 70762306a36Sopenharmony_ci }, 70862306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = { 70962306a36Sopenharmony_ci .base = 0xA000, 71062306a36Sopenharmony_ci .num_row = 14, 71162306a36Sopenharmony_ci .num_col = 4, 71262306a36Sopenharmony_ci }, 71362306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = { 71462306a36Sopenharmony_ci .base = 0xAE00, 71562306a36Sopenharmony_ci .num_row = 1, 71662306a36Sopenharmony_ci .num_col = 2, 71762306a36Sopenharmony_ci }, 71862306a36Sopenharmony_ci [IQS7222_REG_GRP_TPAD] = { 71962306a36Sopenharmony_ci .base = 0xB000, 72062306a36Sopenharmony_ci .num_row = 1, 72162306a36Sopenharmony_ci .num_col = 24, 72262306a36Sopenharmony_ci }, 72362306a36Sopenharmony_ci [IQS7222_REG_GRP_GPIO] = { 72462306a36Sopenharmony_ci .base = 0xC000, 72562306a36Sopenharmony_ci .num_row = 3, 72662306a36Sopenharmony_ci .num_col = 3, 72762306a36Sopenharmony_ci }, 72862306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = { 72962306a36Sopenharmony_ci .base = IQS7222_SYS_SETUP, 73062306a36Sopenharmony_ci .num_row = 1, 73162306a36Sopenharmony_ci .num_col = 12, 73262306a36Sopenharmony_ci }, 73362306a36Sopenharmony_ci }, 73462306a36Sopenharmony_ci }, 73562306a36Sopenharmony_ci { 73662306a36Sopenharmony_ci .prod_num = IQS7222_PROD_NUM_D, 73762306a36Sopenharmony_ci .fw_major = 0, 73862306a36Sopenharmony_ci .fw_minor = 37, 73962306a36Sopenharmony_ci .touch_link = 1770, 74062306a36Sopenharmony_ci .allow_offset = 9, 74162306a36Sopenharmony_ci .event_offset = 10, 74262306a36Sopenharmony_ci .comms_offset = 11, 74362306a36Sopenharmony_ci .reg_grps = { 74462306a36Sopenharmony_ci [IQS7222_REG_GRP_STAT] = { 74562306a36Sopenharmony_ci .base = IQS7222_SYS_STATUS, 74662306a36Sopenharmony_ci .num_row = 1, 74762306a36Sopenharmony_ci .num_col = 7, 74862306a36Sopenharmony_ci }, 74962306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = { 75062306a36Sopenharmony_ci .base = 0x8000, 75162306a36Sopenharmony_ci .num_row = 7, 75262306a36Sopenharmony_ci .num_col = 2, 75362306a36Sopenharmony_ci }, 75462306a36Sopenharmony_ci [IQS7222_REG_GRP_GLBL] = { 75562306a36Sopenharmony_ci .base = 0x8700, 75662306a36Sopenharmony_ci .num_row = 1, 75762306a36Sopenharmony_ci .num_col = 3, 75862306a36Sopenharmony_ci }, 75962306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN] = { 76062306a36Sopenharmony_ci .base = 0x9000, 76162306a36Sopenharmony_ci .num_row = 14, 76262306a36Sopenharmony_ci .num_col = 3, 76362306a36Sopenharmony_ci }, 76462306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = { 76562306a36Sopenharmony_ci .base = 0xA000, 76662306a36Sopenharmony_ci .num_row = 14, 76762306a36Sopenharmony_ci .num_col = 4, 76862306a36Sopenharmony_ci }, 76962306a36Sopenharmony_ci [IQS7222_REG_GRP_FILT] = { 77062306a36Sopenharmony_ci .base = 0xAE00, 77162306a36Sopenharmony_ci .num_row = 1, 77262306a36Sopenharmony_ci .num_col = 2, 77362306a36Sopenharmony_ci }, 77462306a36Sopenharmony_ci [IQS7222_REG_GRP_TPAD] = { 77562306a36Sopenharmony_ci .base = 0xB000, 77662306a36Sopenharmony_ci .num_row = 1, 77762306a36Sopenharmony_ci .num_col = 24, 77862306a36Sopenharmony_ci }, 77962306a36Sopenharmony_ci [IQS7222_REG_GRP_GPIO] = { 78062306a36Sopenharmony_ci .base = 0xC000, 78162306a36Sopenharmony_ci .num_row = 3, 78262306a36Sopenharmony_ci .num_col = 3, 78362306a36Sopenharmony_ci }, 78462306a36Sopenharmony_ci [IQS7222_REG_GRP_SYS] = { 78562306a36Sopenharmony_ci .base = IQS7222_SYS_SETUP, 78662306a36Sopenharmony_ci .num_row = 1, 78762306a36Sopenharmony_ci .num_col = 12, 78862306a36Sopenharmony_ci }, 78962306a36Sopenharmony_ci }, 79062306a36Sopenharmony_ci }, 79162306a36Sopenharmony_ci}; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistruct iqs7222_prop_desc { 79462306a36Sopenharmony_ci const char *name; 79562306a36Sopenharmony_ci enum iqs7222_reg_grp_id reg_grp; 79662306a36Sopenharmony_ci enum iqs7222_reg_key_id reg_key; 79762306a36Sopenharmony_ci int reg_offset; 79862306a36Sopenharmony_ci int reg_shift; 79962306a36Sopenharmony_ci int reg_width; 80062306a36Sopenharmony_ci int val_pitch; 80162306a36Sopenharmony_ci int val_min; 80262306a36Sopenharmony_ci int val_max; 80362306a36Sopenharmony_ci bool invert; 80462306a36Sopenharmony_ci const char *label; 80562306a36Sopenharmony_ci}; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic const struct iqs7222_prop_desc iqs7222_props[] = { 80862306a36Sopenharmony_ci { 80962306a36Sopenharmony_ci .name = "azoteq,conv-period", 81062306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 81162306a36Sopenharmony_ci .reg_offset = 0, 81262306a36Sopenharmony_ci .reg_shift = 8, 81362306a36Sopenharmony_ci .reg_width = 8, 81462306a36Sopenharmony_ci .label = "conversion period", 81562306a36Sopenharmony_ci }, 81662306a36Sopenharmony_ci { 81762306a36Sopenharmony_ci .name = "azoteq,conv-frac", 81862306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 81962306a36Sopenharmony_ci .reg_offset = 0, 82062306a36Sopenharmony_ci .reg_shift = 0, 82162306a36Sopenharmony_ci .reg_width = 8, 82262306a36Sopenharmony_ci .label = "conversion frequency fractional divider", 82362306a36Sopenharmony_ci }, 82462306a36Sopenharmony_ci { 82562306a36Sopenharmony_ci .name = "azoteq,rx-float-inactive", 82662306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 82762306a36Sopenharmony_ci .reg_offset = 1, 82862306a36Sopenharmony_ci .reg_shift = 6, 82962306a36Sopenharmony_ci .reg_width = 1, 83062306a36Sopenharmony_ci .invert = true, 83162306a36Sopenharmony_ci }, 83262306a36Sopenharmony_ci { 83362306a36Sopenharmony_ci .name = "azoteq,dead-time-enable", 83462306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 83562306a36Sopenharmony_ci .reg_offset = 1, 83662306a36Sopenharmony_ci .reg_shift = 5, 83762306a36Sopenharmony_ci .reg_width = 1, 83862306a36Sopenharmony_ci }, 83962306a36Sopenharmony_ci { 84062306a36Sopenharmony_ci .name = "azoteq,tx-freq-fosc", 84162306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 84262306a36Sopenharmony_ci .reg_offset = 1, 84362306a36Sopenharmony_ci .reg_shift = 4, 84462306a36Sopenharmony_ci .reg_width = 1, 84562306a36Sopenharmony_ci }, 84662306a36Sopenharmony_ci { 84762306a36Sopenharmony_ci .name = "azoteq,vbias-enable", 84862306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 84962306a36Sopenharmony_ci .reg_offset = 1, 85062306a36Sopenharmony_ci .reg_shift = 3, 85162306a36Sopenharmony_ci .reg_width = 1, 85262306a36Sopenharmony_ci }, 85362306a36Sopenharmony_ci { 85462306a36Sopenharmony_ci .name = "azoteq,sense-mode", 85562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 85662306a36Sopenharmony_ci .reg_offset = 1, 85762306a36Sopenharmony_ci .reg_shift = 0, 85862306a36Sopenharmony_ci .reg_width = 3, 85962306a36Sopenharmony_ci .val_max = 3, 86062306a36Sopenharmony_ci .label = "sensing mode", 86162306a36Sopenharmony_ci }, 86262306a36Sopenharmony_ci { 86362306a36Sopenharmony_ci .name = "azoteq,iref-enable", 86462306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 86562306a36Sopenharmony_ci .reg_offset = 2, 86662306a36Sopenharmony_ci .reg_shift = 10, 86762306a36Sopenharmony_ci .reg_width = 1, 86862306a36Sopenharmony_ci }, 86962306a36Sopenharmony_ci { 87062306a36Sopenharmony_ci .name = "azoteq,iref-level", 87162306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 87262306a36Sopenharmony_ci .reg_offset = 2, 87362306a36Sopenharmony_ci .reg_shift = 4, 87462306a36Sopenharmony_ci .reg_width = 4, 87562306a36Sopenharmony_ci .label = "current reference level", 87662306a36Sopenharmony_ci }, 87762306a36Sopenharmony_ci { 87862306a36Sopenharmony_ci .name = "azoteq,iref-trim", 87962306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CYCLE, 88062306a36Sopenharmony_ci .reg_offset = 2, 88162306a36Sopenharmony_ci .reg_shift = 0, 88262306a36Sopenharmony_ci .reg_width = 4, 88362306a36Sopenharmony_ci .label = "current reference trim", 88462306a36Sopenharmony_ci }, 88562306a36Sopenharmony_ci { 88662306a36Sopenharmony_ci .name = "azoteq,max-counts", 88762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_GLBL, 88862306a36Sopenharmony_ci .reg_offset = 0, 88962306a36Sopenharmony_ci .reg_shift = 13, 89062306a36Sopenharmony_ci .reg_width = 2, 89162306a36Sopenharmony_ci .label = "maximum counts", 89262306a36Sopenharmony_ci }, 89362306a36Sopenharmony_ci { 89462306a36Sopenharmony_ci .name = "azoteq,auto-mode", 89562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_GLBL, 89662306a36Sopenharmony_ci .reg_offset = 0, 89762306a36Sopenharmony_ci .reg_shift = 2, 89862306a36Sopenharmony_ci .reg_width = 2, 89962306a36Sopenharmony_ci .label = "number of conversions", 90062306a36Sopenharmony_ci }, 90162306a36Sopenharmony_ci { 90262306a36Sopenharmony_ci .name = "azoteq,ati-frac-div-fine", 90362306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_GLBL, 90462306a36Sopenharmony_ci .reg_offset = 1, 90562306a36Sopenharmony_ci .reg_shift = 9, 90662306a36Sopenharmony_ci .reg_width = 5, 90762306a36Sopenharmony_ci .label = "ATI fine fractional divider", 90862306a36Sopenharmony_ci }, 90962306a36Sopenharmony_ci { 91062306a36Sopenharmony_ci .name = "azoteq,ati-frac-div-coarse", 91162306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_GLBL, 91262306a36Sopenharmony_ci .reg_offset = 1, 91362306a36Sopenharmony_ci .reg_shift = 0, 91462306a36Sopenharmony_ci .reg_width = 5, 91562306a36Sopenharmony_ci .label = "ATI coarse fractional divider", 91662306a36Sopenharmony_ci }, 91762306a36Sopenharmony_ci { 91862306a36Sopenharmony_ci .name = "azoteq,ati-comp-select", 91962306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_GLBL, 92062306a36Sopenharmony_ci .reg_offset = 2, 92162306a36Sopenharmony_ci .reg_shift = 0, 92262306a36Sopenharmony_ci .reg_width = 10, 92362306a36Sopenharmony_ci .label = "ATI compensation selection", 92462306a36Sopenharmony_ci }, 92562306a36Sopenharmony_ci { 92662306a36Sopenharmony_ci .name = "azoteq,ati-band", 92762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 92862306a36Sopenharmony_ci .reg_offset = 0, 92962306a36Sopenharmony_ci .reg_shift = 12, 93062306a36Sopenharmony_ci .reg_width = 2, 93162306a36Sopenharmony_ci .label = "ATI band", 93262306a36Sopenharmony_ci }, 93362306a36Sopenharmony_ci { 93462306a36Sopenharmony_ci .name = "azoteq,global-halt", 93562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 93662306a36Sopenharmony_ci .reg_offset = 0, 93762306a36Sopenharmony_ci .reg_shift = 11, 93862306a36Sopenharmony_ci .reg_width = 1, 93962306a36Sopenharmony_ci }, 94062306a36Sopenharmony_ci { 94162306a36Sopenharmony_ci .name = "azoteq,invert-enable", 94262306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 94362306a36Sopenharmony_ci .reg_offset = 0, 94462306a36Sopenharmony_ci .reg_shift = 10, 94562306a36Sopenharmony_ci .reg_width = 1, 94662306a36Sopenharmony_ci }, 94762306a36Sopenharmony_ci { 94862306a36Sopenharmony_ci .name = "azoteq,dual-direction", 94962306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 95062306a36Sopenharmony_ci .reg_offset = 0, 95162306a36Sopenharmony_ci .reg_shift = 9, 95262306a36Sopenharmony_ci .reg_width = 1, 95362306a36Sopenharmony_ci }, 95462306a36Sopenharmony_ci { 95562306a36Sopenharmony_ci .name = "azoteq,samp-cap-double", 95662306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 95762306a36Sopenharmony_ci .reg_offset = 0, 95862306a36Sopenharmony_ci .reg_shift = 3, 95962306a36Sopenharmony_ci .reg_width = 1, 96062306a36Sopenharmony_ci }, 96162306a36Sopenharmony_ci { 96262306a36Sopenharmony_ci .name = "azoteq,vref-half", 96362306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 96462306a36Sopenharmony_ci .reg_offset = 0, 96562306a36Sopenharmony_ci .reg_shift = 2, 96662306a36Sopenharmony_ci .reg_width = 1, 96762306a36Sopenharmony_ci }, 96862306a36Sopenharmony_ci { 96962306a36Sopenharmony_ci .name = "azoteq,proj-bias", 97062306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 97162306a36Sopenharmony_ci .reg_offset = 0, 97262306a36Sopenharmony_ci .reg_shift = 0, 97362306a36Sopenharmony_ci .reg_width = 2, 97462306a36Sopenharmony_ci .label = "projected bias current", 97562306a36Sopenharmony_ci }, 97662306a36Sopenharmony_ci { 97762306a36Sopenharmony_ci .name = "azoteq,ati-target", 97862306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 97962306a36Sopenharmony_ci .reg_offset = 1, 98062306a36Sopenharmony_ci .reg_shift = 8, 98162306a36Sopenharmony_ci .reg_width = 8, 98262306a36Sopenharmony_ci .val_pitch = 8, 98362306a36Sopenharmony_ci .label = "ATI target", 98462306a36Sopenharmony_ci }, 98562306a36Sopenharmony_ci { 98662306a36Sopenharmony_ci .name = "azoteq,ati-base", 98762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 98862306a36Sopenharmony_ci .reg_offset = 1, 98962306a36Sopenharmony_ci .reg_shift = 3, 99062306a36Sopenharmony_ci .reg_width = 5, 99162306a36Sopenharmony_ci .val_pitch = 16, 99262306a36Sopenharmony_ci .label = "ATI base", 99362306a36Sopenharmony_ci }, 99462306a36Sopenharmony_ci { 99562306a36Sopenharmony_ci .name = "azoteq,ati-mode", 99662306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 99762306a36Sopenharmony_ci .reg_offset = 1, 99862306a36Sopenharmony_ci .reg_shift = 0, 99962306a36Sopenharmony_ci .reg_width = 3, 100062306a36Sopenharmony_ci .val_max = 5, 100162306a36Sopenharmony_ci .label = "ATI mode", 100262306a36Sopenharmony_ci }, 100362306a36Sopenharmony_ci { 100462306a36Sopenharmony_ci .name = "azoteq,ati-frac-div-fine", 100562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 100662306a36Sopenharmony_ci .reg_offset = 2, 100762306a36Sopenharmony_ci .reg_shift = 9, 100862306a36Sopenharmony_ci .reg_width = 5, 100962306a36Sopenharmony_ci .label = "ATI fine fractional divider", 101062306a36Sopenharmony_ci }, 101162306a36Sopenharmony_ci { 101262306a36Sopenharmony_ci .name = "azoteq,ati-frac-mult-coarse", 101362306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 101462306a36Sopenharmony_ci .reg_offset = 2, 101562306a36Sopenharmony_ci .reg_shift = 5, 101662306a36Sopenharmony_ci .reg_width = 4, 101762306a36Sopenharmony_ci .label = "ATI coarse fractional multiplier", 101862306a36Sopenharmony_ci }, 101962306a36Sopenharmony_ci { 102062306a36Sopenharmony_ci .name = "azoteq,ati-frac-div-coarse", 102162306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 102262306a36Sopenharmony_ci .reg_offset = 2, 102362306a36Sopenharmony_ci .reg_shift = 0, 102462306a36Sopenharmony_ci .reg_width = 5, 102562306a36Sopenharmony_ci .label = "ATI coarse fractional divider", 102662306a36Sopenharmony_ci }, 102762306a36Sopenharmony_ci { 102862306a36Sopenharmony_ci .name = "azoteq,ati-comp-div", 102962306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 103062306a36Sopenharmony_ci .reg_offset = 3, 103162306a36Sopenharmony_ci .reg_shift = 11, 103262306a36Sopenharmony_ci .reg_width = 5, 103362306a36Sopenharmony_ci .label = "ATI compensation divider", 103462306a36Sopenharmony_ci }, 103562306a36Sopenharmony_ci { 103662306a36Sopenharmony_ci .name = "azoteq,ati-comp-select", 103762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_CHAN, 103862306a36Sopenharmony_ci .reg_offset = 3, 103962306a36Sopenharmony_ci .reg_shift = 0, 104062306a36Sopenharmony_ci .reg_width = 10, 104162306a36Sopenharmony_ci .label = "ATI compensation selection", 104262306a36Sopenharmony_ci }, 104362306a36Sopenharmony_ci { 104462306a36Sopenharmony_ci .name = "azoteq,debounce-exit", 104562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_BTN, 104662306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_DEBOUNCE, 104762306a36Sopenharmony_ci .reg_offset = 0, 104862306a36Sopenharmony_ci .reg_shift = 12, 104962306a36Sopenharmony_ci .reg_width = 4, 105062306a36Sopenharmony_ci .label = "debounce exit factor", 105162306a36Sopenharmony_ci }, 105262306a36Sopenharmony_ci { 105362306a36Sopenharmony_ci .name = "azoteq,debounce-enter", 105462306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_BTN, 105562306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_DEBOUNCE, 105662306a36Sopenharmony_ci .reg_offset = 0, 105762306a36Sopenharmony_ci .reg_shift = 8, 105862306a36Sopenharmony_ci .reg_width = 4, 105962306a36Sopenharmony_ci .label = "debounce entrance factor", 106062306a36Sopenharmony_ci }, 106162306a36Sopenharmony_ci { 106262306a36Sopenharmony_ci .name = "azoteq,thresh", 106362306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_BTN, 106462306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_PROX, 106562306a36Sopenharmony_ci .reg_offset = 0, 106662306a36Sopenharmony_ci .reg_shift = 0, 106762306a36Sopenharmony_ci .reg_width = 8, 106862306a36Sopenharmony_ci .val_max = 127, 106962306a36Sopenharmony_ci .label = "threshold", 107062306a36Sopenharmony_ci }, 107162306a36Sopenharmony_ci { 107262306a36Sopenharmony_ci .name = "azoteq,thresh", 107362306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_BTN, 107462306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TOUCH, 107562306a36Sopenharmony_ci .reg_offset = 1, 107662306a36Sopenharmony_ci .reg_shift = 0, 107762306a36Sopenharmony_ci .reg_width = 8, 107862306a36Sopenharmony_ci .label = "threshold", 107962306a36Sopenharmony_ci }, 108062306a36Sopenharmony_ci { 108162306a36Sopenharmony_ci .name = "azoteq,hyst", 108262306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_BTN, 108362306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TOUCH, 108462306a36Sopenharmony_ci .reg_offset = 1, 108562306a36Sopenharmony_ci .reg_shift = 8, 108662306a36Sopenharmony_ci .reg_width = 8, 108762306a36Sopenharmony_ci .label = "hysteresis", 108862306a36Sopenharmony_ci }, 108962306a36Sopenharmony_ci { 109062306a36Sopenharmony_ci .name = "azoteq,lta-beta-lp", 109162306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_FILT, 109262306a36Sopenharmony_ci .reg_offset = 0, 109362306a36Sopenharmony_ci .reg_shift = 12, 109462306a36Sopenharmony_ci .reg_width = 4, 109562306a36Sopenharmony_ci .label = "low-power mode long-term average beta", 109662306a36Sopenharmony_ci }, 109762306a36Sopenharmony_ci { 109862306a36Sopenharmony_ci .name = "azoteq,lta-beta-np", 109962306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_FILT, 110062306a36Sopenharmony_ci .reg_offset = 0, 110162306a36Sopenharmony_ci .reg_shift = 8, 110262306a36Sopenharmony_ci .reg_width = 4, 110362306a36Sopenharmony_ci .label = "normal-power mode long-term average beta", 110462306a36Sopenharmony_ci }, 110562306a36Sopenharmony_ci { 110662306a36Sopenharmony_ci .name = "azoteq,counts-beta-lp", 110762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_FILT, 110862306a36Sopenharmony_ci .reg_offset = 0, 110962306a36Sopenharmony_ci .reg_shift = 4, 111062306a36Sopenharmony_ci .reg_width = 4, 111162306a36Sopenharmony_ci .label = "low-power mode counts beta", 111262306a36Sopenharmony_ci }, 111362306a36Sopenharmony_ci { 111462306a36Sopenharmony_ci .name = "azoteq,counts-beta-np", 111562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_FILT, 111662306a36Sopenharmony_ci .reg_offset = 0, 111762306a36Sopenharmony_ci .reg_shift = 0, 111862306a36Sopenharmony_ci .reg_width = 4, 111962306a36Sopenharmony_ci .label = "normal-power mode counts beta", 112062306a36Sopenharmony_ci }, 112162306a36Sopenharmony_ci { 112262306a36Sopenharmony_ci .name = "azoteq,lta-fast-beta-lp", 112362306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_FILT, 112462306a36Sopenharmony_ci .reg_offset = 1, 112562306a36Sopenharmony_ci .reg_shift = 4, 112662306a36Sopenharmony_ci .reg_width = 4, 112762306a36Sopenharmony_ci .label = "low-power mode long-term average fast beta", 112862306a36Sopenharmony_ci }, 112962306a36Sopenharmony_ci { 113062306a36Sopenharmony_ci .name = "azoteq,lta-fast-beta-np", 113162306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_FILT, 113262306a36Sopenharmony_ci .reg_offset = 1, 113362306a36Sopenharmony_ci .reg_shift = 0, 113462306a36Sopenharmony_ci .reg_width = 4, 113562306a36Sopenharmony_ci .label = "normal-power mode long-term average fast beta", 113662306a36Sopenharmony_ci }, 113762306a36Sopenharmony_ci { 113862306a36Sopenharmony_ci .name = "azoteq,lower-cal", 113962306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 114062306a36Sopenharmony_ci .reg_offset = 0, 114162306a36Sopenharmony_ci .reg_shift = 8, 114262306a36Sopenharmony_ci .reg_width = 8, 114362306a36Sopenharmony_ci .label = "lower calibration", 114462306a36Sopenharmony_ci }, 114562306a36Sopenharmony_ci { 114662306a36Sopenharmony_ci .name = "azoteq,static-beta", 114762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 114862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_NO_WHEEL, 114962306a36Sopenharmony_ci .reg_offset = 0, 115062306a36Sopenharmony_ci .reg_shift = 6, 115162306a36Sopenharmony_ci .reg_width = 1, 115262306a36Sopenharmony_ci }, 115362306a36Sopenharmony_ci { 115462306a36Sopenharmony_ci .name = "azoteq,bottom-beta", 115562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 115662306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_NO_WHEEL, 115762306a36Sopenharmony_ci .reg_offset = 0, 115862306a36Sopenharmony_ci .reg_shift = 3, 115962306a36Sopenharmony_ci .reg_width = 3, 116062306a36Sopenharmony_ci .label = "bottom beta", 116162306a36Sopenharmony_ci }, 116262306a36Sopenharmony_ci { 116362306a36Sopenharmony_ci .name = "azoteq,static-beta", 116462306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 116562306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_WHEEL, 116662306a36Sopenharmony_ci .reg_offset = 0, 116762306a36Sopenharmony_ci .reg_shift = 7, 116862306a36Sopenharmony_ci .reg_width = 1, 116962306a36Sopenharmony_ci }, 117062306a36Sopenharmony_ci { 117162306a36Sopenharmony_ci .name = "azoteq,bottom-beta", 117262306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 117362306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_WHEEL, 117462306a36Sopenharmony_ci .reg_offset = 0, 117562306a36Sopenharmony_ci .reg_shift = 4, 117662306a36Sopenharmony_ci .reg_width = 3, 117762306a36Sopenharmony_ci .label = "bottom beta", 117862306a36Sopenharmony_ci }, 117962306a36Sopenharmony_ci { 118062306a36Sopenharmony_ci .name = "azoteq,bottom-speed", 118162306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 118262306a36Sopenharmony_ci .reg_offset = 1, 118362306a36Sopenharmony_ci .reg_shift = 8, 118462306a36Sopenharmony_ci .reg_width = 8, 118562306a36Sopenharmony_ci .label = "bottom speed", 118662306a36Sopenharmony_ci }, 118762306a36Sopenharmony_ci { 118862306a36Sopenharmony_ci .name = "azoteq,upper-cal", 118962306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 119062306a36Sopenharmony_ci .reg_offset = 1, 119162306a36Sopenharmony_ci .reg_shift = 0, 119262306a36Sopenharmony_ci .reg_width = 8, 119362306a36Sopenharmony_ci .label = "upper calibration", 119462306a36Sopenharmony_ci }, 119562306a36Sopenharmony_ci { 119662306a36Sopenharmony_ci .name = "azoteq,gesture-max-ms", 119762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 119862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TAP, 119962306a36Sopenharmony_ci .reg_offset = 9, 120062306a36Sopenharmony_ci .reg_shift = 8, 120162306a36Sopenharmony_ci .reg_width = 8, 120262306a36Sopenharmony_ci .val_pitch = 16, 120362306a36Sopenharmony_ci .label = "maximum gesture time", 120462306a36Sopenharmony_ci }, 120562306a36Sopenharmony_ci { 120662306a36Sopenharmony_ci .name = "azoteq,gesture-max-ms", 120762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 120862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TAP_LEGACY, 120962306a36Sopenharmony_ci .reg_offset = 9, 121062306a36Sopenharmony_ci .reg_shift = 8, 121162306a36Sopenharmony_ci .reg_width = 8, 121262306a36Sopenharmony_ci .val_pitch = 4, 121362306a36Sopenharmony_ci .label = "maximum gesture time", 121462306a36Sopenharmony_ci }, 121562306a36Sopenharmony_ci { 121662306a36Sopenharmony_ci .name = "azoteq,gesture-min-ms", 121762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 121862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TAP, 121962306a36Sopenharmony_ci .reg_offset = 9, 122062306a36Sopenharmony_ci .reg_shift = 3, 122162306a36Sopenharmony_ci .reg_width = 5, 122262306a36Sopenharmony_ci .val_pitch = 16, 122362306a36Sopenharmony_ci .label = "minimum gesture time", 122462306a36Sopenharmony_ci }, 122562306a36Sopenharmony_ci { 122662306a36Sopenharmony_ci .name = "azoteq,gesture-min-ms", 122762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 122862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TAP_LEGACY, 122962306a36Sopenharmony_ci .reg_offset = 9, 123062306a36Sopenharmony_ci .reg_shift = 3, 123162306a36Sopenharmony_ci .reg_width = 5, 123262306a36Sopenharmony_ci .val_pitch = 4, 123362306a36Sopenharmony_ci .label = "minimum gesture time", 123462306a36Sopenharmony_ci }, 123562306a36Sopenharmony_ci { 123662306a36Sopenharmony_ci .name = "azoteq,gesture-dist", 123762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 123862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 123962306a36Sopenharmony_ci .reg_offset = 10, 124062306a36Sopenharmony_ci .reg_shift = 8, 124162306a36Sopenharmony_ci .reg_width = 8, 124262306a36Sopenharmony_ci .val_pitch = 16, 124362306a36Sopenharmony_ci .label = "gesture distance", 124462306a36Sopenharmony_ci }, 124562306a36Sopenharmony_ci { 124662306a36Sopenharmony_ci .name = "azoteq,gesture-dist", 124762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 124862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL_LEGACY, 124962306a36Sopenharmony_ci .reg_offset = 10, 125062306a36Sopenharmony_ci .reg_shift = 8, 125162306a36Sopenharmony_ci .reg_width = 8, 125262306a36Sopenharmony_ci .val_pitch = 16, 125362306a36Sopenharmony_ci .label = "gesture distance", 125462306a36Sopenharmony_ci }, 125562306a36Sopenharmony_ci { 125662306a36Sopenharmony_ci .name = "azoteq,gesture-max-ms", 125762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 125862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 125962306a36Sopenharmony_ci .reg_offset = 10, 126062306a36Sopenharmony_ci .reg_shift = 0, 126162306a36Sopenharmony_ci .reg_width = 8, 126262306a36Sopenharmony_ci .val_pitch = 16, 126362306a36Sopenharmony_ci .label = "maximum gesture time", 126462306a36Sopenharmony_ci }, 126562306a36Sopenharmony_ci { 126662306a36Sopenharmony_ci .name = "azoteq,gesture-max-ms", 126762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SLDR, 126862306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL_LEGACY, 126962306a36Sopenharmony_ci .reg_offset = 10, 127062306a36Sopenharmony_ci .reg_shift = 0, 127162306a36Sopenharmony_ci .reg_width = 8, 127262306a36Sopenharmony_ci .val_pitch = 4, 127362306a36Sopenharmony_ci .label = "maximum gesture time", 127462306a36Sopenharmony_ci }, 127562306a36Sopenharmony_ci { 127662306a36Sopenharmony_ci .name = "azoteq,num-rows", 127762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 127862306a36Sopenharmony_ci .reg_offset = 0, 127962306a36Sopenharmony_ci .reg_shift = 4, 128062306a36Sopenharmony_ci .reg_width = 4, 128162306a36Sopenharmony_ci .val_min = 1, 128262306a36Sopenharmony_ci .val_max = 12, 128362306a36Sopenharmony_ci .label = "number of rows", 128462306a36Sopenharmony_ci }, 128562306a36Sopenharmony_ci { 128662306a36Sopenharmony_ci .name = "azoteq,num-cols", 128762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 128862306a36Sopenharmony_ci .reg_offset = 0, 128962306a36Sopenharmony_ci .reg_shift = 0, 129062306a36Sopenharmony_ci .reg_width = 4, 129162306a36Sopenharmony_ci .val_min = 1, 129262306a36Sopenharmony_ci .val_max = 12, 129362306a36Sopenharmony_ci .label = "number of columns", 129462306a36Sopenharmony_ci }, 129562306a36Sopenharmony_ci { 129662306a36Sopenharmony_ci .name = "azoteq,lower-cal-y", 129762306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 129862306a36Sopenharmony_ci .reg_offset = 1, 129962306a36Sopenharmony_ci .reg_shift = 8, 130062306a36Sopenharmony_ci .reg_width = 8, 130162306a36Sopenharmony_ci .label = "lower vertical calibration", 130262306a36Sopenharmony_ci }, 130362306a36Sopenharmony_ci { 130462306a36Sopenharmony_ci .name = "azoteq,lower-cal-x", 130562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 130662306a36Sopenharmony_ci .reg_offset = 1, 130762306a36Sopenharmony_ci .reg_shift = 0, 130862306a36Sopenharmony_ci .reg_width = 8, 130962306a36Sopenharmony_ci .label = "lower horizontal calibration", 131062306a36Sopenharmony_ci }, 131162306a36Sopenharmony_ci { 131262306a36Sopenharmony_ci .name = "azoteq,upper-cal-y", 131362306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 131462306a36Sopenharmony_ci .reg_offset = 2, 131562306a36Sopenharmony_ci .reg_shift = 8, 131662306a36Sopenharmony_ci .reg_width = 8, 131762306a36Sopenharmony_ci .label = "upper vertical calibration", 131862306a36Sopenharmony_ci }, 131962306a36Sopenharmony_ci { 132062306a36Sopenharmony_ci .name = "azoteq,upper-cal-x", 132162306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 132262306a36Sopenharmony_ci .reg_offset = 2, 132362306a36Sopenharmony_ci .reg_shift = 0, 132462306a36Sopenharmony_ci .reg_width = 8, 132562306a36Sopenharmony_ci .label = "upper horizontal calibration", 132662306a36Sopenharmony_ci }, 132762306a36Sopenharmony_ci { 132862306a36Sopenharmony_ci .name = "azoteq,top-speed", 132962306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 133062306a36Sopenharmony_ci .reg_offset = 3, 133162306a36Sopenharmony_ci .reg_shift = 8, 133262306a36Sopenharmony_ci .reg_width = 8, 133362306a36Sopenharmony_ci .val_pitch = 4, 133462306a36Sopenharmony_ci .label = "top speed", 133562306a36Sopenharmony_ci }, 133662306a36Sopenharmony_ci { 133762306a36Sopenharmony_ci .name = "azoteq,bottom-speed", 133862306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 133962306a36Sopenharmony_ci .reg_offset = 3, 134062306a36Sopenharmony_ci .reg_shift = 0, 134162306a36Sopenharmony_ci .reg_width = 8, 134262306a36Sopenharmony_ci .label = "bottom speed", 134362306a36Sopenharmony_ci }, 134462306a36Sopenharmony_ci { 134562306a36Sopenharmony_ci .name = "azoteq,gesture-min-ms", 134662306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 134762306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TAP, 134862306a36Sopenharmony_ci .reg_offset = 20, 134962306a36Sopenharmony_ci .reg_shift = 8, 135062306a36Sopenharmony_ci .reg_width = 8, 135162306a36Sopenharmony_ci .val_pitch = 16, 135262306a36Sopenharmony_ci .label = "minimum gesture time", 135362306a36Sopenharmony_ci }, 135462306a36Sopenharmony_ci { 135562306a36Sopenharmony_ci .name = "azoteq,gesture-max-ms", 135662306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 135762306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 135862306a36Sopenharmony_ci .reg_offset = 21, 135962306a36Sopenharmony_ci .reg_shift = 8, 136062306a36Sopenharmony_ci .reg_width = 8, 136162306a36Sopenharmony_ci .val_pitch = 16, 136262306a36Sopenharmony_ci .label = "maximum gesture time", 136362306a36Sopenharmony_ci }, 136462306a36Sopenharmony_ci { 136562306a36Sopenharmony_ci .name = "azoteq,gesture-max-ms", 136662306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 136762306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TAP, 136862306a36Sopenharmony_ci .reg_offset = 21, 136962306a36Sopenharmony_ci .reg_shift = 0, 137062306a36Sopenharmony_ci .reg_width = 8, 137162306a36Sopenharmony_ci .val_pitch = 16, 137262306a36Sopenharmony_ci .label = "maximum gesture time", 137362306a36Sopenharmony_ci }, 137462306a36Sopenharmony_ci { 137562306a36Sopenharmony_ci .name = "azoteq,gesture-dist", 137662306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 137762306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_TAP, 137862306a36Sopenharmony_ci .reg_offset = 22, 137962306a36Sopenharmony_ci .reg_shift = 0, 138062306a36Sopenharmony_ci .reg_width = 16, 138162306a36Sopenharmony_ci .label = "gesture distance", 138262306a36Sopenharmony_ci }, 138362306a36Sopenharmony_ci { 138462306a36Sopenharmony_ci .name = "azoteq,gesture-dist", 138562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_TPAD, 138662306a36Sopenharmony_ci .reg_key = IQS7222_REG_KEY_AXIAL, 138762306a36Sopenharmony_ci .reg_offset = 23, 138862306a36Sopenharmony_ci .reg_shift = 0, 138962306a36Sopenharmony_ci .reg_width = 16, 139062306a36Sopenharmony_ci .label = "gesture distance", 139162306a36Sopenharmony_ci }, 139262306a36Sopenharmony_ci { 139362306a36Sopenharmony_ci .name = "drive-open-drain", 139462306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_GPIO, 139562306a36Sopenharmony_ci .reg_offset = 0, 139662306a36Sopenharmony_ci .reg_shift = 1, 139762306a36Sopenharmony_ci .reg_width = 1, 139862306a36Sopenharmony_ci }, 139962306a36Sopenharmony_ci { 140062306a36Sopenharmony_ci .name = "azoteq,timeout-ati-ms", 140162306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SYS, 140262306a36Sopenharmony_ci .reg_offset = 1, 140362306a36Sopenharmony_ci .reg_shift = 0, 140462306a36Sopenharmony_ci .reg_width = 16, 140562306a36Sopenharmony_ci .val_pitch = 500, 140662306a36Sopenharmony_ci .label = "ATI error timeout", 140762306a36Sopenharmony_ci }, 140862306a36Sopenharmony_ci { 140962306a36Sopenharmony_ci .name = "azoteq,rate-ati-ms", 141062306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SYS, 141162306a36Sopenharmony_ci .reg_offset = 2, 141262306a36Sopenharmony_ci .reg_shift = 0, 141362306a36Sopenharmony_ci .reg_width = 16, 141462306a36Sopenharmony_ci .label = "ATI report rate", 141562306a36Sopenharmony_ci }, 141662306a36Sopenharmony_ci { 141762306a36Sopenharmony_ci .name = "azoteq,timeout-np-ms", 141862306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SYS, 141962306a36Sopenharmony_ci .reg_offset = 3, 142062306a36Sopenharmony_ci .reg_shift = 0, 142162306a36Sopenharmony_ci .reg_width = 16, 142262306a36Sopenharmony_ci .label = "normal-power mode timeout", 142362306a36Sopenharmony_ci }, 142462306a36Sopenharmony_ci { 142562306a36Sopenharmony_ci .name = "azoteq,rate-np-ms", 142662306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SYS, 142762306a36Sopenharmony_ci .reg_offset = 4, 142862306a36Sopenharmony_ci .reg_shift = 0, 142962306a36Sopenharmony_ci .reg_width = 16, 143062306a36Sopenharmony_ci .val_max = 3000, 143162306a36Sopenharmony_ci .label = "normal-power mode report rate", 143262306a36Sopenharmony_ci }, 143362306a36Sopenharmony_ci { 143462306a36Sopenharmony_ci .name = "azoteq,timeout-lp-ms", 143562306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SYS, 143662306a36Sopenharmony_ci .reg_offset = 5, 143762306a36Sopenharmony_ci .reg_shift = 0, 143862306a36Sopenharmony_ci .reg_width = 16, 143962306a36Sopenharmony_ci .label = "low-power mode timeout", 144062306a36Sopenharmony_ci }, 144162306a36Sopenharmony_ci { 144262306a36Sopenharmony_ci .name = "azoteq,rate-lp-ms", 144362306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SYS, 144462306a36Sopenharmony_ci .reg_offset = 6, 144562306a36Sopenharmony_ci .reg_shift = 0, 144662306a36Sopenharmony_ci .reg_width = 16, 144762306a36Sopenharmony_ci .val_max = 3000, 144862306a36Sopenharmony_ci .label = "low-power mode report rate", 144962306a36Sopenharmony_ci }, 145062306a36Sopenharmony_ci { 145162306a36Sopenharmony_ci .name = "azoteq,timeout-ulp-ms", 145262306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SYS, 145362306a36Sopenharmony_ci .reg_offset = 7, 145462306a36Sopenharmony_ci .reg_shift = 0, 145562306a36Sopenharmony_ci .reg_width = 16, 145662306a36Sopenharmony_ci .label = "ultra-low-power mode timeout", 145762306a36Sopenharmony_ci }, 145862306a36Sopenharmony_ci { 145962306a36Sopenharmony_ci .name = "azoteq,rate-ulp-ms", 146062306a36Sopenharmony_ci .reg_grp = IQS7222_REG_GRP_SYS, 146162306a36Sopenharmony_ci .reg_offset = 8, 146262306a36Sopenharmony_ci .reg_shift = 0, 146362306a36Sopenharmony_ci .reg_width = 16, 146462306a36Sopenharmony_ci .val_max = 3000, 146562306a36Sopenharmony_ci .label = "ultra-low-power mode report rate", 146662306a36Sopenharmony_ci }, 146762306a36Sopenharmony_ci}; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_cistruct iqs7222_private { 147062306a36Sopenharmony_ci const struct iqs7222_dev_desc *dev_desc; 147162306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 147262306a36Sopenharmony_ci struct gpio_desc *irq_gpio; 147362306a36Sopenharmony_ci struct i2c_client *client; 147462306a36Sopenharmony_ci struct input_dev *keypad; 147562306a36Sopenharmony_ci struct touchscreen_properties prop; 147662306a36Sopenharmony_ci unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)]; 147762306a36Sopenharmony_ci unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)]; 147862306a36Sopenharmony_ci unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)]; 147962306a36Sopenharmony_ci unsigned int sl_axis[IQS7222_MAX_SLDR]; 148062306a36Sopenharmony_ci unsigned int tp_code[ARRAY_SIZE(iqs7222_tp_events)]; 148162306a36Sopenharmony_ci u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE]; 148262306a36Sopenharmony_ci u16 glbl_setup[IQS7222_MAX_COLS_GLBL]; 148362306a36Sopenharmony_ci u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN]; 148462306a36Sopenharmony_ci u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN]; 148562306a36Sopenharmony_ci u16 filt_setup[IQS7222_MAX_COLS_FILT]; 148662306a36Sopenharmony_ci u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR]; 148762306a36Sopenharmony_ci u16 tpad_setup[IQS7222_MAX_COLS_TPAD]; 148862306a36Sopenharmony_ci u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO]; 148962306a36Sopenharmony_ci u16 sys_setup[IQS7222_MAX_COLS_SYS]; 149062306a36Sopenharmony_ci}; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_cistatic u16 *iqs7222_setup(struct iqs7222_private *iqs7222, 149362306a36Sopenharmony_ci enum iqs7222_reg_grp_id reg_grp, int row) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci switch (reg_grp) { 149662306a36Sopenharmony_ci case IQS7222_REG_GRP_CYCLE: 149762306a36Sopenharmony_ci return iqs7222->cycle_setup[row]; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci case IQS7222_REG_GRP_GLBL: 150062306a36Sopenharmony_ci return iqs7222->glbl_setup; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci case IQS7222_REG_GRP_BTN: 150362306a36Sopenharmony_ci return iqs7222->btn_setup[row]; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci case IQS7222_REG_GRP_CHAN: 150662306a36Sopenharmony_ci return iqs7222->chan_setup[row]; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci case IQS7222_REG_GRP_FILT: 150962306a36Sopenharmony_ci return iqs7222->filt_setup; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci case IQS7222_REG_GRP_SLDR: 151262306a36Sopenharmony_ci return iqs7222->sldr_setup[row]; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci case IQS7222_REG_GRP_TPAD: 151562306a36Sopenharmony_ci return iqs7222->tpad_setup; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci case IQS7222_REG_GRP_GPIO: 151862306a36Sopenharmony_ci return iqs7222->gpio_setup[row]; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci case IQS7222_REG_GRP_SYS: 152162306a36Sopenharmony_ci return iqs7222->sys_setup; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci default: 152462306a36Sopenharmony_ci return NULL; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_cistatic int iqs7222_irq_poll(struct iqs7222_private *iqs7222, u16 timeout_ms) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci ktime_t irq_timeout = ktime_add_ms(ktime_get(), timeout_ms); 153162306a36Sopenharmony_ci int ret; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci do { 153462306a36Sopenharmony_ci usleep_range(1000, 1100); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci ret = gpiod_get_value_cansleep(iqs7222->irq_gpio); 153762306a36Sopenharmony_ci if (ret < 0) 153862306a36Sopenharmony_ci return ret; 153962306a36Sopenharmony_ci else if (ret > 0) 154062306a36Sopenharmony_ci return 0; 154162306a36Sopenharmony_ci } while (ktime_compare(ktime_get(), irq_timeout) < 0); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci return -EBUSY; 154462306a36Sopenharmony_ci} 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_cistatic int iqs7222_hard_reset(struct iqs7222_private *iqs7222) 154762306a36Sopenharmony_ci{ 154862306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 154962306a36Sopenharmony_ci int error; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (!iqs7222->reset_gpio) 155262306a36Sopenharmony_ci return 0; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci gpiod_set_value_cansleep(iqs7222->reset_gpio, 1); 155562306a36Sopenharmony_ci usleep_range(1000, 1100); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci gpiod_set_value_cansleep(iqs7222->reset_gpio, 0); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci error = iqs7222_irq_poll(iqs7222, IQS7222_RESET_TIMEOUT_MS); 156062306a36Sopenharmony_ci if (error) 156162306a36Sopenharmony_ci dev_err(&client->dev, "Failed to reset device: %d\n", error); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci return error; 156462306a36Sopenharmony_ci} 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_cistatic int iqs7222_force_comms(struct iqs7222_private *iqs7222) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci u8 msg_buf[] = { 0xFF, }; 156962306a36Sopenharmony_ci int ret; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci /* 157262306a36Sopenharmony_ci * The device cannot communicate until it asserts its interrupt (RDY) 157362306a36Sopenharmony_ci * pin. Attempts to do so while RDY is deasserted return an ACK; how- 157462306a36Sopenharmony_ci * ever all write data is ignored, and all read data returns 0xEE. 157562306a36Sopenharmony_ci * 157662306a36Sopenharmony_ci * Unsolicited communication must be preceded by a special force com- 157762306a36Sopenharmony_ci * munication command, after which the device eventually asserts its 157862306a36Sopenharmony_ci * RDY pin and agrees to communicate. 157962306a36Sopenharmony_ci * 158062306a36Sopenharmony_ci * Regardless of whether communication is forced or the result of an 158162306a36Sopenharmony_ci * interrupt, the device automatically deasserts its RDY pin once it 158262306a36Sopenharmony_ci * detects an I2C stop condition, or a timeout expires. 158362306a36Sopenharmony_ci */ 158462306a36Sopenharmony_ci ret = gpiod_get_value_cansleep(iqs7222->irq_gpio); 158562306a36Sopenharmony_ci if (ret < 0) 158662306a36Sopenharmony_ci return ret; 158762306a36Sopenharmony_ci else if (ret > 0) 158862306a36Sopenharmony_ci return 0; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci ret = i2c_master_send(iqs7222->client, msg_buf, sizeof(msg_buf)); 159162306a36Sopenharmony_ci if (ret < (int)sizeof(msg_buf)) { 159262306a36Sopenharmony_ci if (ret >= 0) 159362306a36Sopenharmony_ci ret = -EIO; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci /* 159662306a36Sopenharmony_ci * The datasheet states that the host must wait to retry any 159762306a36Sopenharmony_ci * failed attempt to communicate over I2C. 159862306a36Sopenharmony_ci */ 159962306a36Sopenharmony_ci msleep(IQS7222_COMMS_RETRY_MS); 160062306a36Sopenharmony_ci return ret; 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci return iqs7222_irq_poll(iqs7222, IQS7222_COMMS_TIMEOUT_MS); 160462306a36Sopenharmony_ci} 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_cistatic int iqs7222_read_burst(struct iqs7222_private *iqs7222, 160762306a36Sopenharmony_ci u16 reg, void *val, u16 num_val) 160862306a36Sopenharmony_ci{ 160962306a36Sopenharmony_ci u8 reg_buf[sizeof(__be16)]; 161062306a36Sopenharmony_ci int ret, i; 161162306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 161262306a36Sopenharmony_ci struct i2c_msg msg[] = { 161362306a36Sopenharmony_ci { 161462306a36Sopenharmony_ci .addr = client->addr, 161562306a36Sopenharmony_ci .flags = 0, 161662306a36Sopenharmony_ci .len = reg > U8_MAX ? sizeof(reg) : sizeof(u8), 161762306a36Sopenharmony_ci .buf = reg_buf, 161862306a36Sopenharmony_ci }, 161962306a36Sopenharmony_ci { 162062306a36Sopenharmony_ci .addr = client->addr, 162162306a36Sopenharmony_ci .flags = I2C_M_RD, 162262306a36Sopenharmony_ci .len = num_val * sizeof(__le16), 162362306a36Sopenharmony_ci .buf = (u8 *)val, 162462306a36Sopenharmony_ci }, 162562306a36Sopenharmony_ci }; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (reg > U8_MAX) 162862306a36Sopenharmony_ci put_unaligned_be16(reg, reg_buf); 162962306a36Sopenharmony_ci else 163062306a36Sopenharmony_ci *reg_buf = (u8)reg; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci /* 163362306a36Sopenharmony_ci * The following loop protects against an edge case in which the RDY 163462306a36Sopenharmony_ci * pin is automatically deasserted just as the read is initiated. In 163562306a36Sopenharmony_ci * that case, the read must be retried using forced communication. 163662306a36Sopenharmony_ci */ 163762306a36Sopenharmony_ci for (i = 0; i < IQS7222_NUM_RETRIES; i++) { 163862306a36Sopenharmony_ci ret = iqs7222_force_comms(iqs7222); 163962306a36Sopenharmony_ci if (ret < 0) 164062306a36Sopenharmony_ci continue; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); 164362306a36Sopenharmony_ci if (ret < (int)ARRAY_SIZE(msg)) { 164462306a36Sopenharmony_ci if (ret >= 0) 164562306a36Sopenharmony_ci ret = -EIO; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci msleep(IQS7222_COMMS_RETRY_MS); 164862306a36Sopenharmony_ci continue; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci if (get_unaligned_le16(msg[1].buf) == IQS7222_COMMS_ERROR) { 165262306a36Sopenharmony_ci ret = -ENODATA; 165362306a36Sopenharmony_ci continue; 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci ret = 0; 165762306a36Sopenharmony_ci break; 165862306a36Sopenharmony_ci } 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci /* 166162306a36Sopenharmony_ci * The following delay ensures the device has deasserted the RDY pin 166262306a36Sopenharmony_ci * following the I2C stop condition. 166362306a36Sopenharmony_ci */ 166462306a36Sopenharmony_ci usleep_range(50, 100); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci if (ret < 0) 166762306a36Sopenharmony_ci dev_err(&client->dev, 166862306a36Sopenharmony_ci "Failed to read from address 0x%04X: %d\n", reg, ret); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci return ret; 167162306a36Sopenharmony_ci} 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_cistatic int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci __le16 val_buf; 167662306a36Sopenharmony_ci int error; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci error = iqs7222_read_burst(iqs7222, reg, &val_buf, 1); 167962306a36Sopenharmony_ci if (error) 168062306a36Sopenharmony_ci return error; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci *val = le16_to_cpu(val_buf); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci return 0; 168562306a36Sopenharmony_ci} 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_cistatic int iqs7222_write_burst(struct iqs7222_private *iqs7222, 168862306a36Sopenharmony_ci u16 reg, const void *val, u16 num_val) 168962306a36Sopenharmony_ci{ 169062306a36Sopenharmony_ci int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8); 169162306a36Sopenharmony_ci int val_len = num_val * sizeof(__le16); 169262306a36Sopenharmony_ci int msg_len = reg_len + val_len; 169362306a36Sopenharmony_ci int ret, i; 169462306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 169562306a36Sopenharmony_ci u8 *msg_buf; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci msg_buf = kzalloc(msg_len, GFP_KERNEL); 169862306a36Sopenharmony_ci if (!msg_buf) 169962306a36Sopenharmony_ci return -ENOMEM; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci if (reg > U8_MAX) 170262306a36Sopenharmony_ci put_unaligned_be16(reg, msg_buf); 170362306a36Sopenharmony_ci else 170462306a36Sopenharmony_ci *msg_buf = (u8)reg; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci memcpy(msg_buf + reg_len, val, val_len); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci /* 170962306a36Sopenharmony_ci * The following loop protects against an edge case in which the RDY 171062306a36Sopenharmony_ci * pin is automatically asserted just before the force communication 171162306a36Sopenharmony_ci * command is sent. 171262306a36Sopenharmony_ci * 171362306a36Sopenharmony_ci * In that case, the subsequent I2C stop condition tricks the device 171462306a36Sopenharmony_ci * into preemptively deasserting the RDY pin and the command must be 171562306a36Sopenharmony_ci * sent again. 171662306a36Sopenharmony_ci */ 171762306a36Sopenharmony_ci for (i = 0; i < IQS7222_NUM_RETRIES; i++) { 171862306a36Sopenharmony_ci ret = iqs7222_force_comms(iqs7222); 171962306a36Sopenharmony_ci if (ret < 0) 172062306a36Sopenharmony_ci continue; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci ret = i2c_master_send(client, msg_buf, msg_len); 172362306a36Sopenharmony_ci if (ret < msg_len) { 172462306a36Sopenharmony_ci if (ret >= 0) 172562306a36Sopenharmony_ci ret = -EIO; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci msleep(IQS7222_COMMS_RETRY_MS); 172862306a36Sopenharmony_ci continue; 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci ret = 0; 173262306a36Sopenharmony_ci break; 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci kfree(msg_buf); 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci usleep_range(50, 100); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci if (ret < 0) 174062306a36Sopenharmony_ci dev_err(&client->dev, 174162306a36Sopenharmony_ci "Failed to write to address 0x%04X: %d\n", reg, ret); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci return ret; 174462306a36Sopenharmony_ci} 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_cistatic int iqs7222_write_word(struct iqs7222_private *iqs7222, u16 reg, u16 val) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci __le16 val_buf = cpu_to_le16(val); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci return iqs7222_write_burst(iqs7222, reg, &val_buf, 1); 175162306a36Sopenharmony_ci} 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_cistatic int iqs7222_ati_trigger(struct iqs7222_private *iqs7222) 175462306a36Sopenharmony_ci{ 175562306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 175662306a36Sopenharmony_ci ktime_t ati_timeout; 175762306a36Sopenharmony_ci u16 sys_status = 0; 175862306a36Sopenharmony_ci u16 sys_setup; 175962306a36Sopenharmony_ci int error, i; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci /* 176262306a36Sopenharmony_ci * The reserved fields of the system setup register may have changed 176362306a36Sopenharmony_ci * as a result of other registers having been written. As such, read 176462306a36Sopenharmony_ci * the register's latest value to avoid unexpected behavior when the 176562306a36Sopenharmony_ci * register is written in the loop that follows. 176662306a36Sopenharmony_ci */ 176762306a36Sopenharmony_ci error = iqs7222_read_word(iqs7222, IQS7222_SYS_SETUP, &sys_setup); 176862306a36Sopenharmony_ci if (error) 176962306a36Sopenharmony_ci return error; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci for (i = 0; i < IQS7222_NUM_RETRIES; i++) { 177262306a36Sopenharmony_ci /* 177362306a36Sopenharmony_ci * Trigger ATI from streaming and normal-power modes so that 177462306a36Sopenharmony_ci * the RDY pin continues to be asserted during ATI. 177562306a36Sopenharmony_ci */ 177662306a36Sopenharmony_ci error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP, 177762306a36Sopenharmony_ci sys_setup | 177862306a36Sopenharmony_ci IQS7222_SYS_SETUP_REDO_ATI); 177962306a36Sopenharmony_ci if (error) 178062306a36Sopenharmony_ci return error; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci ati_timeout = ktime_add_ms(ktime_get(), IQS7222_ATI_TIMEOUT_MS); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci do { 178562306a36Sopenharmony_ci error = iqs7222_irq_poll(iqs7222, 178662306a36Sopenharmony_ci IQS7222_COMMS_TIMEOUT_MS); 178762306a36Sopenharmony_ci if (error) 178862306a36Sopenharmony_ci continue; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci error = iqs7222_read_word(iqs7222, IQS7222_SYS_STATUS, 179162306a36Sopenharmony_ci &sys_status); 179262306a36Sopenharmony_ci if (error) 179362306a36Sopenharmony_ci return error; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci if (sys_status & IQS7222_SYS_STATUS_RESET) 179662306a36Sopenharmony_ci return 0; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR) 179962306a36Sopenharmony_ci break; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE) 180262306a36Sopenharmony_ci continue; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci /* 180562306a36Sopenharmony_ci * Use stream-in-touch mode if either slider reports 180662306a36Sopenharmony_ci * absolute position. 180762306a36Sopenharmony_ci */ 180862306a36Sopenharmony_ci sys_setup |= test_bit(EV_ABS, iqs7222->keypad->evbit) 180962306a36Sopenharmony_ci ? IQS7222_SYS_SETUP_INTF_MODE_TOUCH 181062306a36Sopenharmony_ci : IQS7222_SYS_SETUP_INTF_MODE_EVENT; 181162306a36Sopenharmony_ci sys_setup |= IQS7222_SYS_SETUP_PWR_MODE_AUTO; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci return iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP, 181462306a36Sopenharmony_ci sys_setup); 181562306a36Sopenharmony_ci } while (ktime_compare(ktime_get(), ati_timeout) < 0); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci dev_err(&client->dev, 181862306a36Sopenharmony_ci "ATI attempt %d of %d failed with status 0x%02X, %s\n", 181962306a36Sopenharmony_ci i + 1, IQS7222_NUM_RETRIES, (u8)sys_status, 182062306a36Sopenharmony_ci i + 1 < IQS7222_NUM_RETRIES ? "retrying" : "stopping"); 182162306a36Sopenharmony_ci } 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci return -ETIMEDOUT; 182462306a36Sopenharmony_ci} 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_cistatic int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir) 182762306a36Sopenharmony_ci{ 182862306a36Sopenharmony_ci const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 182962306a36Sopenharmony_ci int comms_offset = dev_desc->comms_offset; 183062306a36Sopenharmony_ci int error, i, j, k; 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci /* 183362306a36Sopenharmony_ci * Acknowledge reset before writing any registers in case the device 183462306a36Sopenharmony_ci * suffers a spurious reset during initialization. Because this step 183562306a36Sopenharmony_ci * may change the reserved fields of the second filter beta register, 183662306a36Sopenharmony_ci * its cache must be updated. 183762306a36Sopenharmony_ci * 183862306a36Sopenharmony_ci * Writing the second filter beta register, in turn, may clobber the 183962306a36Sopenharmony_ci * system status register. As such, the filter beta register pair is 184062306a36Sopenharmony_ci * written first to protect against this hazard. 184162306a36Sopenharmony_ci */ 184262306a36Sopenharmony_ci if (dir == WRITE) { 184362306a36Sopenharmony_ci u16 reg = dev_desc->reg_grps[IQS7222_REG_GRP_FILT].base + 1; 184462306a36Sopenharmony_ci u16 filt_setup; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP, 184762306a36Sopenharmony_ci iqs7222->sys_setup[0] | 184862306a36Sopenharmony_ci IQS7222_SYS_SETUP_ACK_RESET); 184962306a36Sopenharmony_ci if (error) 185062306a36Sopenharmony_ci return error; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci error = iqs7222_read_word(iqs7222, reg, &filt_setup); 185362306a36Sopenharmony_ci if (error) 185462306a36Sopenharmony_ci return error; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci iqs7222->filt_setup[1] &= GENMASK(7, 0); 185762306a36Sopenharmony_ci iqs7222->filt_setup[1] |= (filt_setup & ~GENMASK(7, 0)); 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci /* 186162306a36Sopenharmony_ci * Take advantage of the stop-bit disable function, if available, to 186262306a36Sopenharmony_ci * save the trouble of having to reopen a communication window after 186362306a36Sopenharmony_ci * each burst read or write. 186462306a36Sopenharmony_ci */ 186562306a36Sopenharmony_ci if (comms_offset) { 186662306a36Sopenharmony_ci u16 comms_setup; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci error = iqs7222_read_word(iqs7222, 186962306a36Sopenharmony_ci IQS7222_SYS_SETUP + comms_offset, 187062306a36Sopenharmony_ci &comms_setup); 187162306a36Sopenharmony_ci if (error) 187262306a36Sopenharmony_ci return error; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci error = iqs7222_write_word(iqs7222, 187562306a36Sopenharmony_ci IQS7222_SYS_SETUP + comms_offset, 187662306a36Sopenharmony_ci comms_setup | IQS7222_COMMS_HOLD); 187762306a36Sopenharmony_ci if (error) 187862306a36Sopenharmony_ci return error; 187962306a36Sopenharmony_ci } 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) { 188262306a36Sopenharmony_ci int num_row = dev_desc->reg_grps[i].num_row; 188362306a36Sopenharmony_ci int num_col = dev_desc->reg_grps[i].num_col; 188462306a36Sopenharmony_ci u16 reg = dev_desc->reg_grps[i].base; 188562306a36Sopenharmony_ci __le16 *val_buf; 188662306a36Sopenharmony_ci u16 *val; 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci if (!num_col) 188962306a36Sopenharmony_ci continue; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci val = iqs7222_setup(iqs7222, i, 0); 189262306a36Sopenharmony_ci if (!val) 189362306a36Sopenharmony_ci continue; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci val_buf = kcalloc(num_col, sizeof(__le16), GFP_KERNEL); 189662306a36Sopenharmony_ci if (!val_buf) 189762306a36Sopenharmony_ci return -ENOMEM; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci for (j = 0; j < num_row; j++) { 190062306a36Sopenharmony_ci switch (dir) { 190162306a36Sopenharmony_ci case READ: 190262306a36Sopenharmony_ci error = iqs7222_read_burst(iqs7222, reg, 190362306a36Sopenharmony_ci val_buf, num_col); 190462306a36Sopenharmony_ci for (k = 0; k < num_col; k++) 190562306a36Sopenharmony_ci val[k] = le16_to_cpu(val_buf[k]); 190662306a36Sopenharmony_ci break; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci case WRITE: 190962306a36Sopenharmony_ci for (k = 0; k < num_col; k++) 191062306a36Sopenharmony_ci val_buf[k] = cpu_to_le16(val[k]); 191162306a36Sopenharmony_ci error = iqs7222_write_burst(iqs7222, reg, 191262306a36Sopenharmony_ci val_buf, num_col); 191362306a36Sopenharmony_ci break; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci default: 191662306a36Sopenharmony_ci error = -EINVAL; 191762306a36Sopenharmony_ci } 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci if (error) 192062306a36Sopenharmony_ci break; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci reg += IQS7222_REG_OFFSET; 192362306a36Sopenharmony_ci val += iqs7222_max_cols[i]; 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci kfree(val_buf); 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci if (error) 192962306a36Sopenharmony_ci return error; 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci if (comms_offset) { 193362306a36Sopenharmony_ci u16 comms_setup; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci error = iqs7222_read_word(iqs7222, 193662306a36Sopenharmony_ci IQS7222_SYS_SETUP + comms_offset, 193762306a36Sopenharmony_ci &comms_setup); 193862306a36Sopenharmony_ci if (error) 193962306a36Sopenharmony_ci return error; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci error = iqs7222_write_word(iqs7222, 194262306a36Sopenharmony_ci IQS7222_SYS_SETUP + comms_offset, 194362306a36Sopenharmony_ci comms_setup & ~IQS7222_COMMS_HOLD); 194462306a36Sopenharmony_ci if (error) 194562306a36Sopenharmony_ci return error; 194662306a36Sopenharmony_ci } 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci if (dir == READ) { 194962306a36Sopenharmony_ci iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK; 195062306a36Sopenharmony_ci iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK; 195162306a36Sopenharmony_ci return 0; 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci return iqs7222_ati_trigger(iqs7222); 195562306a36Sopenharmony_ci} 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_cistatic int iqs7222_dev_info(struct iqs7222_private *iqs7222) 195862306a36Sopenharmony_ci{ 195962306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 196062306a36Sopenharmony_ci bool prod_num_valid = false; 196162306a36Sopenharmony_ci __le16 dev_id[3]; 196262306a36Sopenharmony_ci int error, i; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id, 196562306a36Sopenharmony_ci ARRAY_SIZE(dev_id)); 196662306a36Sopenharmony_ci if (error) 196762306a36Sopenharmony_ci return error; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs7222_devs); i++) { 197062306a36Sopenharmony_ci if (le16_to_cpu(dev_id[0]) != iqs7222_devs[i].prod_num) 197162306a36Sopenharmony_ci continue; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci prod_num_valid = true; 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci if (le16_to_cpu(dev_id[1]) < iqs7222_devs[i].fw_major) 197662306a36Sopenharmony_ci continue; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci if (le16_to_cpu(dev_id[2]) < iqs7222_devs[i].fw_minor) 197962306a36Sopenharmony_ci continue; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci iqs7222->dev_desc = &iqs7222_devs[i]; 198262306a36Sopenharmony_ci return 0; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci if (prod_num_valid) 198662306a36Sopenharmony_ci dev_err(&client->dev, "Unsupported firmware revision: %u.%u\n", 198762306a36Sopenharmony_ci le16_to_cpu(dev_id[1]), le16_to_cpu(dev_id[2])); 198862306a36Sopenharmony_ci else 198962306a36Sopenharmony_ci dev_err(&client->dev, "Unrecognized product number: %u\n", 199062306a36Sopenharmony_ci le16_to_cpu(dev_id[0])); 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci return -EINVAL; 199362306a36Sopenharmony_ci} 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_cistatic int iqs7222_gpio_select(struct iqs7222_private *iqs7222, 199662306a36Sopenharmony_ci struct fwnode_handle *child_node, 199762306a36Sopenharmony_ci int child_enable, u16 child_link) 199862306a36Sopenharmony_ci{ 199962306a36Sopenharmony_ci const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 200062306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 200162306a36Sopenharmony_ci int num_gpio = dev_desc->reg_grps[IQS7222_REG_GRP_GPIO].num_row; 200262306a36Sopenharmony_ci int error, count, i; 200362306a36Sopenharmony_ci unsigned int gpio_sel[ARRAY_SIZE(iqs7222_gpio_links)]; 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci if (!num_gpio) 200662306a36Sopenharmony_ci return 0; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci if (!fwnode_property_present(child_node, "azoteq,gpio-select")) 200962306a36Sopenharmony_ci return 0; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci count = fwnode_property_count_u32(child_node, "azoteq,gpio-select"); 201262306a36Sopenharmony_ci if (count > num_gpio) { 201362306a36Sopenharmony_ci dev_err(&client->dev, "Invalid number of %s GPIOs\n", 201462306a36Sopenharmony_ci fwnode_get_name(child_node)); 201562306a36Sopenharmony_ci return -EINVAL; 201662306a36Sopenharmony_ci } else if (count < 0) { 201762306a36Sopenharmony_ci dev_err(&client->dev, "Failed to count %s GPIOs: %d\n", 201862306a36Sopenharmony_ci fwnode_get_name(child_node), count); 201962306a36Sopenharmony_ci return count; 202062306a36Sopenharmony_ci } 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci error = fwnode_property_read_u32_array(child_node, 202362306a36Sopenharmony_ci "azoteq,gpio-select", 202462306a36Sopenharmony_ci gpio_sel, count); 202562306a36Sopenharmony_ci if (error) { 202662306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s GPIOs: %d\n", 202762306a36Sopenharmony_ci fwnode_get_name(child_node), error); 202862306a36Sopenharmony_ci return error; 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci for (i = 0; i < count; i++) { 203262306a36Sopenharmony_ci u16 *gpio_setup; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if (gpio_sel[i] >= num_gpio) { 203562306a36Sopenharmony_ci dev_err(&client->dev, "Invalid %s GPIO: %u\n", 203662306a36Sopenharmony_ci fwnode_get_name(child_node), gpio_sel[i]); 203762306a36Sopenharmony_ci return -EINVAL; 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci gpio_setup = iqs7222->gpio_setup[gpio_sel[i]]; 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci if (gpio_setup[2] && child_link != gpio_setup[2]) { 204362306a36Sopenharmony_ci dev_err(&client->dev, 204462306a36Sopenharmony_ci "Conflicting GPIO %u event types\n", 204562306a36Sopenharmony_ci gpio_sel[i]); 204662306a36Sopenharmony_ci return -EINVAL; 204762306a36Sopenharmony_ci } 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci gpio_setup[0] |= IQS7222_GPIO_SETUP_0_GPIO_EN; 205062306a36Sopenharmony_ci gpio_setup[1] |= child_enable; 205162306a36Sopenharmony_ci gpio_setup[2] = child_link; 205262306a36Sopenharmony_ci } 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci return 0; 205562306a36Sopenharmony_ci} 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_cistatic int iqs7222_parse_props(struct iqs7222_private *iqs7222, 205862306a36Sopenharmony_ci struct fwnode_handle *reg_grp_node, 205962306a36Sopenharmony_ci int reg_grp_index, 206062306a36Sopenharmony_ci enum iqs7222_reg_grp_id reg_grp, 206162306a36Sopenharmony_ci enum iqs7222_reg_key_id reg_key) 206262306a36Sopenharmony_ci{ 206362306a36Sopenharmony_ci u16 *setup = iqs7222_setup(iqs7222, reg_grp, reg_grp_index); 206462306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 206562306a36Sopenharmony_ci int i; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci if (!setup) 206862306a36Sopenharmony_ci return 0; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs7222_props); i++) { 207162306a36Sopenharmony_ci const char *name = iqs7222_props[i].name; 207262306a36Sopenharmony_ci int reg_offset = iqs7222_props[i].reg_offset; 207362306a36Sopenharmony_ci int reg_shift = iqs7222_props[i].reg_shift; 207462306a36Sopenharmony_ci int reg_width = iqs7222_props[i].reg_width; 207562306a36Sopenharmony_ci int val_pitch = iqs7222_props[i].val_pitch ? : 1; 207662306a36Sopenharmony_ci int val_min = iqs7222_props[i].val_min; 207762306a36Sopenharmony_ci int val_max = iqs7222_props[i].val_max; 207862306a36Sopenharmony_ci bool invert = iqs7222_props[i].invert; 207962306a36Sopenharmony_ci const char *label = iqs7222_props[i].label ? : name; 208062306a36Sopenharmony_ci unsigned int val; 208162306a36Sopenharmony_ci int error; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci if (iqs7222_props[i].reg_grp != reg_grp || 208462306a36Sopenharmony_ci iqs7222_props[i].reg_key != reg_key) 208562306a36Sopenharmony_ci continue; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci /* 208862306a36Sopenharmony_ci * Boolean register fields are one bit wide; they are forcibly 208962306a36Sopenharmony_ci * reset to provide a means to undo changes by a bootloader if 209062306a36Sopenharmony_ci * necessary. 209162306a36Sopenharmony_ci * 209262306a36Sopenharmony_ci * Scalar fields, on the other hand, are left untouched unless 209362306a36Sopenharmony_ci * their corresponding properties are present. 209462306a36Sopenharmony_ci */ 209562306a36Sopenharmony_ci if (reg_width == 1) { 209662306a36Sopenharmony_ci if (invert) 209762306a36Sopenharmony_ci setup[reg_offset] |= BIT(reg_shift); 209862306a36Sopenharmony_ci else 209962306a36Sopenharmony_ci setup[reg_offset] &= ~BIT(reg_shift); 210062306a36Sopenharmony_ci } 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci if (!fwnode_property_present(reg_grp_node, name)) 210362306a36Sopenharmony_ci continue; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if (reg_width == 1) { 210662306a36Sopenharmony_ci if (invert) 210762306a36Sopenharmony_ci setup[reg_offset] &= ~BIT(reg_shift); 210862306a36Sopenharmony_ci else 210962306a36Sopenharmony_ci setup[reg_offset] |= BIT(reg_shift); 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci continue; 211262306a36Sopenharmony_ci } 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci error = fwnode_property_read_u32(reg_grp_node, name, &val); 211562306a36Sopenharmony_ci if (error) { 211662306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s %s: %d\n", 211762306a36Sopenharmony_ci fwnode_get_name(reg_grp_node), label, error); 211862306a36Sopenharmony_ci return error; 211962306a36Sopenharmony_ci } 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci if (!val_max) 212262306a36Sopenharmony_ci val_max = GENMASK(reg_width - 1, 0) * val_pitch; 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci if (val < val_min || val > val_max) { 212562306a36Sopenharmony_ci dev_err(&client->dev, "Invalid %s %s: %u\n", 212662306a36Sopenharmony_ci fwnode_get_name(reg_grp_node), label, val); 212762306a36Sopenharmony_ci return -EINVAL; 212862306a36Sopenharmony_ci } 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci setup[reg_offset] &= ~GENMASK(reg_shift + reg_width - 1, 213162306a36Sopenharmony_ci reg_shift); 213262306a36Sopenharmony_ci setup[reg_offset] |= (val / val_pitch << reg_shift); 213362306a36Sopenharmony_ci } 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci return 0; 213662306a36Sopenharmony_ci} 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_cistatic int iqs7222_parse_event(struct iqs7222_private *iqs7222, 213962306a36Sopenharmony_ci struct fwnode_handle *event_node, 214062306a36Sopenharmony_ci int reg_grp_index, 214162306a36Sopenharmony_ci enum iqs7222_reg_grp_id reg_grp, 214262306a36Sopenharmony_ci enum iqs7222_reg_key_id reg_key, 214362306a36Sopenharmony_ci u16 event_enable, u16 event_link, 214462306a36Sopenharmony_ci unsigned int *event_type, 214562306a36Sopenharmony_ci unsigned int *event_code) 214662306a36Sopenharmony_ci{ 214762306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 214862306a36Sopenharmony_ci int error; 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci error = iqs7222_parse_props(iqs7222, event_node, reg_grp_index, 215162306a36Sopenharmony_ci reg_grp, reg_key); 215262306a36Sopenharmony_ci if (error) 215362306a36Sopenharmony_ci return error; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci error = iqs7222_gpio_select(iqs7222, event_node, event_enable, 215662306a36Sopenharmony_ci event_link); 215762306a36Sopenharmony_ci if (error) 215862306a36Sopenharmony_ci return error; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci error = fwnode_property_read_u32(event_node, "linux,code", event_code); 216162306a36Sopenharmony_ci if (error == -EINVAL) { 216262306a36Sopenharmony_ci return 0; 216362306a36Sopenharmony_ci } else if (error) { 216462306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s code: %d\n", 216562306a36Sopenharmony_ci fwnode_get_name(event_node), error); 216662306a36Sopenharmony_ci return error; 216762306a36Sopenharmony_ci } 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci if (!event_type) { 217062306a36Sopenharmony_ci input_set_capability(iqs7222->keypad, EV_KEY, *event_code); 217162306a36Sopenharmony_ci return 0; 217262306a36Sopenharmony_ci } 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci error = fwnode_property_read_u32(event_node, "linux,input-type", 217562306a36Sopenharmony_ci event_type); 217662306a36Sopenharmony_ci if (error == -EINVAL) { 217762306a36Sopenharmony_ci *event_type = EV_KEY; 217862306a36Sopenharmony_ci } else if (error) { 217962306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s input type: %d\n", 218062306a36Sopenharmony_ci fwnode_get_name(event_node), error); 218162306a36Sopenharmony_ci return error; 218262306a36Sopenharmony_ci } else if (*event_type != EV_KEY && *event_type != EV_SW) { 218362306a36Sopenharmony_ci dev_err(&client->dev, "Invalid %s input type: %d\n", 218462306a36Sopenharmony_ci fwnode_get_name(event_node), *event_type); 218562306a36Sopenharmony_ci return -EINVAL; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci input_set_capability(iqs7222->keypad, *event_type, *event_code); 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci return 0; 219162306a36Sopenharmony_ci} 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_cistatic int iqs7222_parse_cycle(struct iqs7222_private *iqs7222, 219462306a36Sopenharmony_ci struct fwnode_handle *cycle_node, int cycle_index) 219562306a36Sopenharmony_ci{ 219662306a36Sopenharmony_ci u16 *cycle_setup = iqs7222->cycle_setup[cycle_index]; 219762306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 219862306a36Sopenharmony_ci unsigned int pins[9]; 219962306a36Sopenharmony_ci int error, count, i; 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci /* 220262306a36Sopenharmony_ci * Each channel shares a cycle with one other channel; the mapping of 220362306a36Sopenharmony_ci * channels to cycles is fixed. Properties defined for a cycle impact 220462306a36Sopenharmony_ci * both channels tied to the cycle. 220562306a36Sopenharmony_ci * 220662306a36Sopenharmony_ci * Unlike channels which are restricted to a select range of CRx pins 220762306a36Sopenharmony_ci * based on channel number, any cycle can claim any of the device's 9 220862306a36Sopenharmony_ci * CTx pins (CTx0-8). 220962306a36Sopenharmony_ci */ 221062306a36Sopenharmony_ci if (!fwnode_property_present(cycle_node, "azoteq,tx-enable")) 221162306a36Sopenharmony_ci return 0; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci count = fwnode_property_count_u32(cycle_node, "azoteq,tx-enable"); 221462306a36Sopenharmony_ci if (count < 0) { 221562306a36Sopenharmony_ci dev_err(&client->dev, "Failed to count %s CTx pins: %d\n", 221662306a36Sopenharmony_ci fwnode_get_name(cycle_node), count); 221762306a36Sopenharmony_ci return count; 221862306a36Sopenharmony_ci } else if (count > ARRAY_SIZE(pins)) { 221962306a36Sopenharmony_ci dev_err(&client->dev, "Invalid number of %s CTx pins\n", 222062306a36Sopenharmony_ci fwnode_get_name(cycle_node)); 222162306a36Sopenharmony_ci return -EINVAL; 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci error = fwnode_property_read_u32_array(cycle_node, "azoteq,tx-enable", 222562306a36Sopenharmony_ci pins, count); 222662306a36Sopenharmony_ci if (error) { 222762306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s CTx pins: %d\n", 222862306a36Sopenharmony_ci fwnode_get_name(cycle_node), error); 222962306a36Sopenharmony_ci return error; 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci cycle_setup[1] &= ~GENMASK(7 + ARRAY_SIZE(pins) - 1, 7); 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci for (i = 0; i < count; i++) { 223562306a36Sopenharmony_ci if (pins[i] > 8) { 223662306a36Sopenharmony_ci dev_err(&client->dev, "Invalid %s CTx pin: %u\n", 223762306a36Sopenharmony_ci fwnode_get_name(cycle_node), pins[i]); 223862306a36Sopenharmony_ci return -EINVAL; 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci cycle_setup[1] |= BIT(pins[i] + 7); 224262306a36Sopenharmony_ci } 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci return 0; 224562306a36Sopenharmony_ci} 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_cistatic int iqs7222_parse_chan(struct iqs7222_private *iqs7222, 224862306a36Sopenharmony_ci struct fwnode_handle *chan_node, int chan_index) 224962306a36Sopenharmony_ci{ 225062306a36Sopenharmony_ci const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 225162306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 225262306a36Sopenharmony_ci int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; 225362306a36Sopenharmony_ci int ext_chan = rounddown(num_chan, 10); 225462306a36Sopenharmony_ci int error, i; 225562306a36Sopenharmony_ci u16 *chan_setup = iqs7222->chan_setup[chan_index]; 225662306a36Sopenharmony_ci u16 *sys_setup = iqs7222->sys_setup; 225762306a36Sopenharmony_ci unsigned int val; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci if (dev_desc->allow_offset && 226062306a36Sopenharmony_ci fwnode_property_present(chan_node, "azoteq,ulp-allow")) 226162306a36Sopenharmony_ci sys_setup[dev_desc->allow_offset] &= ~BIT(chan_index); 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci chan_setup[0] |= IQS7222_CHAN_SETUP_0_CHAN_EN; 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci /* 226662306a36Sopenharmony_ci * The reference channel function allows for differential measurements 226762306a36Sopenharmony_ci * and is only available in the case of IQS7222A or IQS7222C. 226862306a36Sopenharmony_ci */ 226962306a36Sopenharmony_ci if (dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_col > 4 && 227062306a36Sopenharmony_ci fwnode_property_present(chan_node, "azoteq,ref-select")) { 227162306a36Sopenharmony_ci u16 *ref_setup; 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci error = fwnode_property_read_u32(chan_node, "azoteq,ref-select", 227462306a36Sopenharmony_ci &val); 227562306a36Sopenharmony_ci if (error) { 227662306a36Sopenharmony_ci dev_err(&client->dev, 227762306a36Sopenharmony_ci "Failed to read %s reference channel: %d\n", 227862306a36Sopenharmony_ci fwnode_get_name(chan_node), error); 227962306a36Sopenharmony_ci return error; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci if (val >= ext_chan) { 228362306a36Sopenharmony_ci dev_err(&client->dev, 228462306a36Sopenharmony_ci "Invalid %s reference channel: %u\n", 228562306a36Sopenharmony_ci fwnode_get_name(chan_node), val); 228662306a36Sopenharmony_ci return -EINVAL; 228762306a36Sopenharmony_ci } 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci ref_setup = iqs7222->chan_setup[val]; 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci /* 229262306a36Sopenharmony_ci * Configure the current channel as a follower of the selected 229362306a36Sopenharmony_ci * reference channel. 229462306a36Sopenharmony_ci */ 229562306a36Sopenharmony_ci chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW; 229662306a36Sopenharmony_ci chan_setup[4] = val * 42 + 1048; 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci error = fwnode_property_read_u32(chan_node, "azoteq,ref-weight", 229962306a36Sopenharmony_ci &val); 230062306a36Sopenharmony_ci if (!error) { 230162306a36Sopenharmony_ci if (val > U16_MAX) { 230262306a36Sopenharmony_ci dev_err(&client->dev, 230362306a36Sopenharmony_ci "Invalid %s reference weight: %u\n", 230462306a36Sopenharmony_ci fwnode_get_name(chan_node), val); 230562306a36Sopenharmony_ci return -EINVAL; 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci chan_setup[5] = val; 230962306a36Sopenharmony_ci } else if (error != -EINVAL) { 231062306a36Sopenharmony_ci dev_err(&client->dev, 231162306a36Sopenharmony_ci "Failed to read %s reference weight: %d\n", 231262306a36Sopenharmony_ci fwnode_get_name(chan_node), error); 231362306a36Sopenharmony_ci return error; 231462306a36Sopenharmony_ci } 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci /* 231762306a36Sopenharmony_ci * Configure the selected channel as a reference channel which 231862306a36Sopenharmony_ci * serves the current channel. 231962306a36Sopenharmony_ci */ 232062306a36Sopenharmony_ci ref_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF; 232162306a36Sopenharmony_ci ref_setup[5] |= BIT(chan_index); 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci ref_setup[4] = dev_desc->touch_link; 232462306a36Sopenharmony_ci if (fwnode_property_present(chan_node, "azoteq,use-prox")) 232562306a36Sopenharmony_ci ref_setup[4] -= 2; 232662306a36Sopenharmony_ci } else if (dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row && 232762306a36Sopenharmony_ci fwnode_property_present(chan_node, 232862306a36Sopenharmony_ci "azoteq,counts-filt-enable")) { 232962306a36Sopenharmony_ci /* 233062306a36Sopenharmony_ci * In the case of IQS7222D, however, the reference mode field 233162306a36Sopenharmony_ci * is partially repurposed as a counts filter enable control. 233262306a36Sopenharmony_ci */ 233362306a36Sopenharmony_ci chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF; 233462306a36Sopenharmony_ci } 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci if (fwnode_property_present(chan_node, "azoteq,rx-enable")) { 233762306a36Sopenharmony_ci /* 233862306a36Sopenharmony_ci * Each channel can claim up to 4 CRx pins. The first half of 233962306a36Sopenharmony_ci * the channels can use CRx0-3, while the second half can use 234062306a36Sopenharmony_ci * CRx4-7. 234162306a36Sopenharmony_ci */ 234262306a36Sopenharmony_ci unsigned int pins[4]; 234362306a36Sopenharmony_ci int count; 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci count = fwnode_property_count_u32(chan_node, 234662306a36Sopenharmony_ci "azoteq,rx-enable"); 234762306a36Sopenharmony_ci if (count < 0) { 234862306a36Sopenharmony_ci dev_err(&client->dev, 234962306a36Sopenharmony_ci "Failed to count %s CRx pins: %d\n", 235062306a36Sopenharmony_ci fwnode_get_name(chan_node), count); 235162306a36Sopenharmony_ci return count; 235262306a36Sopenharmony_ci } else if (count > ARRAY_SIZE(pins)) { 235362306a36Sopenharmony_ci dev_err(&client->dev, 235462306a36Sopenharmony_ci "Invalid number of %s CRx pins\n", 235562306a36Sopenharmony_ci fwnode_get_name(chan_node)); 235662306a36Sopenharmony_ci return -EINVAL; 235762306a36Sopenharmony_ci } 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci error = fwnode_property_read_u32_array(chan_node, 236062306a36Sopenharmony_ci "azoteq,rx-enable", 236162306a36Sopenharmony_ci pins, count); 236262306a36Sopenharmony_ci if (error) { 236362306a36Sopenharmony_ci dev_err(&client->dev, 236462306a36Sopenharmony_ci "Failed to read %s CRx pins: %d\n", 236562306a36Sopenharmony_ci fwnode_get_name(chan_node), error); 236662306a36Sopenharmony_ci return error; 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci chan_setup[0] &= ~GENMASK(4 + ARRAY_SIZE(pins) - 1, 4); 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci for (i = 0; i < count; i++) { 237262306a36Sopenharmony_ci int min_crx = chan_index < ext_chan / 2 ? 0 : 4; 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci if (pins[i] < min_crx || pins[i] > min_crx + 3) { 237562306a36Sopenharmony_ci dev_err(&client->dev, 237662306a36Sopenharmony_ci "Invalid %s CRx pin: %u\n", 237762306a36Sopenharmony_ci fwnode_get_name(chan_node), pins[i]); 237862306a36Sopenharmony_ci return -EINVAL; 237962306a36Sopenharmony_ci } 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci chan_setup[0] |= BIT(pins[i] + 4 - min_crx); 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci } 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs7222_kp_events); i++) { 238662306a36Sopenharmony_ci const char *event_name = iqs7222_kp_events[i].name; 238762306a36Sopenharmony_ci u16 event_enable = iqs7222_kp_events[i].enable; 238862306a36Sopenharmony_ci struct fwnode_handle *event_node; 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci event_node = fwnode_get_named_child_node(chan_node, event_name); 239162306a36Sopenharmony_ci if (!event_node) 239262306a36Sopenharmony_ci continue; 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci error = fwnode_property_read_u32(event_node, 239562306a36Sopenharmony_ci "azoteq,timeout-press-ms", 239662306a36Sopenharmony_ci &val); 239762306a36Sopenharmony_ci if (!error) { 239862306a36Sopenharmony_ci /* 239962306a36Sopenharmony_ci * The IQS7222B employs a global pair of press timeout 240062306a36Sopenharmony_ci * registers as opposed to channel-specific registers. 240162306a36Sopenharmony_ci */ 240262306a36Sopenharmony_ci u16 *setup = dev_desc->reg_grps 240362306a36Sopenharmony_ci [IQS7222_REG_GRP_BTN].num_col > 2 ? 240462306a36Sopenharmony_ci &iqs7222->btn_setup[chan_index][2] : 240562306a36Sopenharmony_ci &sys_setup[9]; 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci if (val > U8_MAX * 500) { 240862306a36Sopenharmony_ci dev_err(&client->dev, 240962306a36Sopenharmony_ci "Invalid %s press timeout: %u\n", 241062306a36Sopenharmony_ci fwnode_get_name(event_node), val); 241162306a36Sopenharmony_ci fwnode_handle_put(event_node); 241262306a36Sopenharmony_ci return -EINVAL; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci *setup &= ~(U8_MAX << i * 8); 241662306a36Sopenharmony_ci *setup |= (val / 500 << i * 8); 241762306a36Sopenharmony_ci } else if (error != -EINVAL) { 241862306a36Sopenharmony_ci dev_err(&client->dev, 241962306a36Sopenharmony_ci "Failed to read %s press timeout: %d\n", 242062306a36Sopenharmony_ci fwnode_get_name(event_node), error); 242162306a36Sopenharmony_ci fwnode_handle_put(event_node); 242262306a36Sopenharmony_ci return error; 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci error = iqs7222_parse_event(iqs7222, event_node, chan_index, 242662306a36Sopenharmony_ci IQS7222_REG_GRP_BTN, 242762306a36Sopenharmony_ci iqs7222_kp_events[i].reg_key, 242862306a36Sopenharmony_ci BIT(chan_index), 242962306a36Sopenharmony_ci dev_desc->touch_link - (i ? 0 : 2), 243062306a36Sopenharmony_ci &iqs7222->kp_type[chan_index][i], 243162306a36Sopenharmony_ci &iqs7222->kp_code[chan_index][i]); 243262306a36Sopenharmony_ci fwnode_handle_put(event_node); 243362306a36Sopenharmony_ci if (error) 243462306a36Sopenharmony_ci return error; 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci if (!dev_desc->event_offset) 243762306a36Sopenharmony_ci continue; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci sys_setup[dev_desc->event_offset] |= event_enable; 244062306a36Sopenharmony_ci } 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci /* 244362306a36Sopenharmony_ci * The following call handles a special pair of properties that apply 244462306a36Sopenharmony_ci * to a channel node, but reside within the button (event) group. 244562306a36Sopenharmony_ci */ 244662306a36Sopenharmony_ci return iqs7222_parse_props(iqs7222, chan_node, chan_index, 244762306a36Sopenharmony_ci IQS7222_REG_GRP_BTN, 244862306a36Sopenharmony_ci IQS7222_REG_KEY_DEBOUNCE); 244962306a36Sopenharmony_ci} 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_cistatic int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, 245262306a36Sopenharmony_ci struct fwnode_handle *sldr_node, int sldr_index) 245362306a36Sopenharmony_ci{ 245462306a36Sopenharmony_ci const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 245562306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 245662306a36Sopenharmony_ci int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; 245762306a36Sopenharmony_ci int ext_chan = rounddown(num_chan, 10); 245862306a36Sopenharmony_ci int count, error, reg_offset, i; 245962306a36Sopenharmony_ci u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset]; 246062306a36Sopenharmony_ci u16 *sldr_setup = iqs7222->sldr_setup[sldr_index]; 246162306a36Sopenharmony_ci unsigned int chan_sel[4], val; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci /* 246462306a36Sopenharmony_ci * Each slider can be spread across 3 to 4 channels. It is possible to 246562306a36Sopenharmony_ci * select only 2 channels, but doing so prevents the slider from using 246662306a36Sopenharmony_ci * the specified resolution. 246762306a36Sopenharmony_ci */ 246862306a36Sopenharmony_ci count = fwnode_property_count_u32(sldr_node, "azoteq,channel-select"); 246962306a36Sopenharmony_ci if (count < 0) { 247062306a36Sopenharmony_ci dev_err(&client->dev, "Failed to count %s channels: %d\n", 247162306a36Sopenharmony_ci fwnode_get_name(sldr_node), count); 247262306a36Sopenharmony_ci return count; 247362306a36Sopenharmony_ci } else if (count < 3 || count > ARRAY_SIZE(chan_sel)) { 247462306a36Sopenharmony_ci dev_err(&client->dev, "Invalid number of %s channels\n", 247562306a36Sopenharmony_ci fwnode_get_name(sldr_node)); 247662306a36Sopenharmony_ci return -EINVAL; 247762306a36Sopenharmony_ci } 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci error = fwnode_property_read_u32_array(sldr_node, 248062306a36Sopenharmony_ci "azoteq,channel-select", 248162306a36Sopenharmony_ci chan_sel, count); 248262306a36Sopenharmony_ci if (error) { 248362306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s channels: %d\n", 248462306a36Sopenharmony_ci fwnode_get_name(sldr_node), error); 248562306a36Sopenharmony_ci return error; 248662306a36Sopenharmony_ci } 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci /* 248962306a36Sopenharmony_ci * Resolution and top speed, if small enough, are packed into a single 249062306a36Sopenharmony_ci * register. Otherwise, each occupies its own register and the rest of 249162306a36Sopenharmony_ci * the slider-related register addresses are offset by one. 249262306a36Sopenharmony_ci */ 249362306a36Sopenharmony_ci reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1; 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci sldr_setup[0] |= count; 249662306a36Sopenharmony_ci sldr_setup[3 + reg_offset] &= ~GENMASK(ext_chan - 1, 0); 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(chan_sel); i++) { 249962306a36Sopenharmony_ci sldr_setup[5 + reg_offset + i] = 0; 250062306a36Sopenharmony_ci if (i >= count) 250162306a36Sopenharmony_ci continue; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci if (chan_sel[i] >= ext_chan) { 250462306a36Sopenharmony_ci dev_err(&client->dev, "Invalid %s channel: %u\n", 250562306a36Sopenharmony_ci fwnode_get_name(sldr_node), chan_sel[i]); 250662306a36Sopenharmony_ci return -EINVAL; 250762306a36Sopenharmony_ci } 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci /* 251062306a36Sopenharmony_ci * The following fields indicate which channels participate in 251162306a36Sopenharmony_ci * the slider, as well as each channel's relative placement. 251262306a36Sopenharmony_ci */ 251362306a36Sopenharmony_ci sldr_setup[3 + reg_offset] |= BIT(chan_sel[i]); 251462306a36Sopenharmony_ci sldr_setup[5 + reg_offset + i] = chan_sel[i] * 42 + 1080; 251562306a36Sopenharmony_ci } 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci sldr_setup[4 + reg_offset] = dev_desc->touch_link; 251862306a36Sopenharmony_ci if (fwnode_property_present(sldr_node, "azoteq,use-prox")) 251962306a36Sopenharmony_ci sldr_setup[4 + reg_offset] -= 2; 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci error = fwnode_property_read_u32(sldr_node, "azoteq,slider-size", &val); 252262306a36Sopenharmony_ci if (!error) { 252362306a36Sopenharmony_ci if (val > dev_desc->sldr_res) { 252462306a36Sopenharmony_ci dev_err(&client->dev, "Invalid %s size: %u\n", 252562306a36Sopenharmony_ci fwnode_get_name(sldr_node), val); 252662306a36Sopenharmony_ci return -EINVAL; 252762306a36Sopenharmony_ci } 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci if (reg_offset) { 253062306a36Sopenharmony_ci sldr_setup[3] = val; 253162306a36Sopenharmony_ci } else { 253262306a36Sopenharmony_ci sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_RES_MASK; 253362306a36Sopenharmony_ci sldr_setup[2] |= (val / 16 << 253462306a36Sopenharmony_ci IQS7222_SLDR_SETUP_2_RES_SHIFT); 253562306a36Sopenharmony_ci } 253662306a36Sopenharmony_ci } else if (error != -EINVAL) { 253762306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s size: %d\n", 253862306a36Sopenharmony_ci fwnode_get_name(sldr_node), error); 253962306a36Sopenharmony_ci return error; 254062306a36Sopenharmony_ci } 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci if (!(reg_offset ? sldr_setup[3] 254362306a36Sopenharmony_ci : sldr_setup[2] & IQS7222_SLDR_SETUP_2_RES_MASK)) { 254462306a36Sopenharmony_ci dev_err(&client->dev, "Undefined %s size\n", 254562306a36Sopenharmony_ci fwnode_get_name(sldr_node)); 254662306a36Sopenharmony_ci return -EINVAL; 254762306a36Sopenharmony_ci } 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ci error = fwnode_property_read_u32(sldr_node, "azoteq,top-speed", &val); 255062306a36Sopenharmony_ci if (!error) { 255162306a36Sopenharmony_ci if (val > (reg_offset ? U16_MAX : U8_MAX * 4)) { 255262306a36Sopenharmony_ci dev_err(&client->dev, "Invalid %s top speed: %u\n", 255362306a36Sopenharmony_ci fwnode_get_name(sldr_node), val); 255462306a36Sopenharmony_ci return -EINVAL; 255562306a36Sopenharmony_ci } 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci if (reg_offset) { 255862306a36Sopenharmony_ci sldr_setup[2] = val; 255962306a36Sopenharmony_ci } else { 256062306a36Sopenharmony_ci sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK; 256162306a36Sopenharmony_ci sldr_setup[2] |= (val / 4); 256262306a36Sopenharmony_ci } 256362306a36Sopenharmony_ci } else if (error != -EINVAL) { 256462306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s top speed: %d\n", 256562306a36Sopenharmony_ci fwnode_get_name(sldr_node), error); 256662306a36Sopenharmony_ci return error; 256762306a36Sopenharmony_ci } 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci error = fwnode_property_read_u32(sldr_node, "linux,axis", &val); 257062306a36Sopenharmony_ci if (!error) { 257162306a36Sopenharmony_ci u16 sldr_max = sldr_setup[3] - 1; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci if (!reg_offset) { 257462306a36Sopenharmony_ci sldr_max = sldr_setup[2]; 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci sldr_max &= IQS7222_SLDR_SETUP_2_RES_MASK; 257762306a36Sopenharmony_ci sldr_max >>= IQS7222_SLDR_SETUP_2_RES_SHIFT; 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci sldr_max = sldr_max * 16 - 1; 258062306a36Sopenharmony_ci } 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci input_set_abs_params(iqs7222->keypad, val, 0, sldr_max, 0, 0); 258362306a36Sopenharmony_ci iqs7222->sl_axis[sldr_index] = val; 258462306a36Sopenharmony_ci } else if (error != -EINVAL) { 258562306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s axis: %d\n", 258662306a36Sopenharmony_ci fwnode_get_name(sldr_node), error); 258762306a36Sopenharmony_ci return error; 258862306a36Sopenharmony_ci } 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci if (dev_desc->wheel_enable) { 259162306a36Sopenharmony_ci sldr_setup[0] &= ~dev_desc->wheel_enable; 259262306a36Sopenharmony_ci if (iqs7222->sl_axis[sldr_index] == ABS_WHEEL) 259362306a36Sopenharmony_ci sldr_setup[0] |= dev_desc->wheel_enable; 259462306a36Sopenharmony_ci } 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci /* 259762306a36Sopenharmony_ci * The absence of a register offset makes it safe to assume the device 259862306a36Sopenharmony_ci * supports gestures, each of which is first disabled until explicitly 259962306a36Sopenharmony_ci * enabled. 260062306a36Sopenharmony_ci */ 260162306a36Sopenharmony_ci if (!reg_offset) 260262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) 260362306a36Sopenharmony_ci sldr_setup[9] &= ~iqs7222_sl_events[i].enable; 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) { 260662306a36Sopenharmony_ci const char *event_name = iqs7222_sl_events[i].name; 260762306a36Sopenharmony_ci struct fwnode_handle *event_node; 260862306a36Sopenharmony_ci enum iqs7222_reg_key_id reg_key; 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci event_node = fwnode_get_named_child_node(sldr_node, event_name); 261162306a36Sopenharmony_ci if (!event_node) 261262306a36Sopenharmony_ci continue; 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci /* 261562306a36Sopenharmony_ci * Depending on the device, gestures are either offered using 261662306a36Sopenharmony_ci * one of two timing resolutions, or are not supported at all. 261762306a36Sopenharmony_ci */ 261862306a36Sopenharmony_ci if (reg_offset) 261962306a36Sopenharmony_ci reg_key = IQS7222_REG_KEY_RESERVED; 262062306a36Sopenharmony_ci else if (dev_desc->legacy_gesture && 262162306a36Sopenharmony_ci iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_TAP) 262262306a36Sopenharmony_ci reg_key = IQS7222_REG_KEY_TAP_LEGACY; 262362306a36Sopenharmony_ci else if (dev_desc->legacy_gesture && 262462306a36Sopenharmony_ci iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_AXIAL) 262562306a36Sopenharmony_ci reg_key = IQS7222_REG_KEY_AXIAL_LEGACY; 262662306a36Sopenharmony_ci else 262762306a36Sopenharmony_ci reg_key = iqs7222_sl_events[i].reg_key; 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci /* 263062306a36Sopenharmony_ci * The press/release event does not expose a direct GPIO link, 263162306a36Sopenharmony_ci * but one can be emulated by tying each of the participating 263262306a36Sopenharmony_ci * channels to the same GPIO. 263362306a36Sopenharmony_ci */ 263462306a36Sopenharmony_ci error = iqs7222_parse_event(iqs7222, event_node, sldr_index, 263562306a36Sopenharmony_ci IQS7222_REG_GRP_SLDR, reg_key, 263662306a36Sopenharmony_ci i ? iqs7222_sl_events[i].enable 263762306a36Sopenharmony_ci : sldr_setup[3 + reg_offset], 263862306a36Sopenharmony_ci i ? 1568 + sldr_index * 30 263962306a36Sopenharmony_ci : sldr_setup[4 + reg_offset], 264062306a36Sopenharmony_ci NULL, 264162306a36Sopenharmony_ci &iqs7222->sl_code[sldr_index][i]); 264262306a36Sopenharmony_ci fwnode_handle_put(event_node); 264362306a36Sopenharmony_ci if (error) 264462306a36Sopenharmony_ci return error; 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci if (!reg_offset) 264762306a36Sopenharmony_ci sldr_setup[9] |= iqs7222_sl_events[i].enable; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci if (!dev_desc->event_offset) 265062306a36Sopenharmony_ci continue; 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci /* 265362306a36Sopenharmony_ci * The press/release event is determined based on whether the 265462306a36Sopenharmony_ci * coordinate field reports 0xFFFF and solely relies on touch 265562306a36Sopenharmony_ci * or proximity interrupts to be unmasked. 265662306a36Sopenharmony_ci */ 265762306a36Sopenharmony_ci if (i && !reg_offset) 265862306a36Sopenharmony_ci *event_mask |= (IQS7222_EVENT_MASK_SLDR << sldr_index); 265962306a36Sopenharmony_ci else if (sldr_setup[4 + reg_offset] == dev_desc->touch_link) 266062306a36Sopenharmony_ci *event_mask |= IQS7222_EVENT_MASK_TOUCH; 266162306a36Sopenharmony_ci else 266262306a36Sopenharmony_ci *event_mask |= IQS7222_EVENT_MASK_PROX; 266362306a36Sopenharmony_ci } 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci /* 266662306a36Sopenharmony_ci * The following call handles a special pair of properties that shift 266762306a36Sopenharmony_ci * to make room for a wheel enable control in the case of IQS7222C. 266862306a36Sopenharmony_ci */ 266962306a36Sopenharmony_ci return iqs7222_parse_props(iqs7222, sldr_node, sldr_index, 267062306a36Sopenharmony_ci IQS7222_REG_GRP_SLDR, 267162306a36Sopenharmony_ci dev_desc->wheel_enable ? 267262306a36Sopenharmony_ci IQS7222_REG_KEY_WHEEL : 267362306a36Sopenharmony_ci IQS7222_REG_KEY_NO_WHEEL); 267462306a36Sopenharmony_ci} 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_cistatic int iqs7222_parse_tpad(struct iqs7222_private *iqs7222, 267762306a36Sopenharmony_ci struct fwnode_handle *tpad_node, int tpad_index) 267862306a36Sopenharmony_ci{ 267962306a36Sopenharmony_ci const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 268062306a36Sopenharmony_ci struct touchscreen_properties *prop = &iqs7222->prop; 268162306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 268262306a36Sopenharmony_ci int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; 268362306a36Sopenharmony_ci int count, error, i; 268462306a36Sopenharmony_ci u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset]; 268562306a36Sopenharmony_ci u16 *tpad_setup = iqs7222->tpad_setup; 268662306a36Sopenharmony_ci unsigned int chan_sel[12]; 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_ci error = iqs7222_parse_props(iqs7222, tpad_node, tpad_index, 268962306a36Sopenharmony_ci IQS7222_REG_GRP_TPAD, 269062306a36Sopenharmony_ci IQS7222_REG_KEY_NONE); 269162306a36Sopenharmony_ci if (error) 269262306a36Sopenharmony_ci return error; 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_ci count = fwnode_property_count_u32(tpad_node, "azoteq,channel-select"); 269562306a36Sopenharmony_ci if (count < 0) { 269662306a36Sopenharmony_ci dev_err(&client->dev, "Failed to count %s channels: %d\n", 269762306a36Sopenharmony_ci fwnode_get_name(tpad_node), count); 269862306a36Sopenharmony_ci return count; 269962306a36Sopenharmony_ci } else if (!count || count > ARRAY_SIZE(chan_sel)) { 270062306a36Sopenharmony_ci dev_err(&client->dev, "Invalid number of %s channels\n", 270162306a36Sopenharmony_ci fwnode_get_name(tpad_node)); 270262306a36Sopenharmony_ci return -EINVAL; 270362306a36Sopenharmony_ci } 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci error = fwnode_property_read_u32_array(tpad_node, 270662306a36Sopenharmony_ci "azoteq,channel-select", 270762306a36Sopenharmony_ci chan_sel, count); 270862306a36Sopenharmony_ci if (error) { 270962306a36Sopenharmony_ci dev_err(&client->dev, "Failed to read %s channels: %d\n", 271062306a36Sopenharmony_ci fwnode_get_name(tpad_node), error); 271162306a36Sopenharmony_ci return error; 271262306a36Sopenharmony_ci } 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci tpad_setup[6] &= ~GENMASK(num_chan - 1, 0); 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(chan_sel); i++) { 271762306a36Sopenharmony_ci tpad_setup[8 + i] = 0; 271862306a36Sopenharmony_ci if (i >= count || chan_sel[i] == U8_MAX) 271962306a36Sopenharmony_ci continue; 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci if (chan_sel[i] >= num_chan) { 272262306a36Sopenharmony_ci dev_err(&client->dev, "Invalid %s channel: %u\n", 272362306a36Sopenharmony_ci fwnode_get_name(tpad_node), chan_sel[i]); 272462306a36Sopenharmony_ci return -EINVAL; 272562306a36Sopenharmony_ci } 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci /* 272862306a36Sopenharmony_ci * The following fields indicate which channels participate in 272962306a36Sopenharmony_ci * the trackpad, as well as each channel's relative placement. 273062306a36Sopenharmony_ci */ 273162306a36Sopenharmony_ci tpad_setup[6] |= BIT(chan_sel[i]); 273262306a36Sopenharmony_ci tpad_setup[8 + i] = chan_sel[i] * 34 + 1072; 273362306a36Sopenharmony_ci } 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci tpad_setup[7] = dev_desc->touch_link; 273662306a36Sopenharmony_ci if (fwnode_property_present(tpad_node, "azoteq,use-prox")) 273762306a36Sopenharmony_ci tpad_setup[7] -= 2; 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) 274062306a36Sopenharmony_ci tpad_setup[20] &= ~(iqs7222_tp_events[i].strict | 274162306a36Sopenharmony_ci iqs7222_tp_events[i].enable); 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) { 274462306a36Sopenharmony_ci const char *event_name = iqs7222_tp_events[i].name; 274562306a36Sopenharmony_ci struct fwnode_handle *event_node; 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci event_node = fwnode_get_named_child_node(tpad_node, event_name); 274862306a36Sopenharmony_ci if (!event_node) 274962306a36Sopenharmony_ci continue; 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci if (fwnode_property_present(event_node, 275262306a36Sopenharmony_ci "azoteq,gesture-angle-tighten")) 275362306a36Sopenharmony_ci tpad_setup[20] |= iqs7222_tp_events[i].strict; 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci tpad_setup[20] |= iqs7222_tp_events[i].enable; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci error = iqs7222_parse_event(iqs7222, event_node, tpad_index, 275862306a36Sopenharmony_ci IQS7222_REG_GRP_TPAD, 275962306a36Sopenharmony_ci iqs7222_tp_events[i].reg_key, 276062306a36Sopenharmony_ci iqs7222_tp_events[i].link, 1566, 276162306a36Sopenharmony_ci NULL, 276262306a36Sopenharmony_ci &iqs7222->tp_code[i]); 276362306a36Sopenharmony_ci fwnode_handle_put(event_node); 276462306a36Sopenharmony_ci if (error) 276562306a36Sopenharmony_ci return error; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci if (!dev_desc->event_offset) 276862306a36Sopenharmony_ci continue; 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci /* 277162306a36Sopenharmony_ci * The press/release event is determined based on whether the 277262306a36Sopenharmony_ci * coordinate fields report 0xFFFF and solely relies on touch 277362306a36Sopenharmony_ci * or proximity interrupts to be unmasked. 277462306a36Sopenharmony_ci */ 277562306a36Sopenharmony_ci if (i) 277662306a36Sopenharmony_ci *event_mask |= IQS7222_EVENT_MASK_TPAD; 277762306a36Sopenharmony_ci else if (tpad_setup[7] == dev_desc->touch_link) 277862306a36Sopenharmony_ci *event_mask |= IQS7222_EVENT_MASK_TOUCH; 277962306a36Sopenharmony_ci else 278062306a36Sopenharmony_ci *event_mask |= IQS7222_EVENT_MASK_PROX; 278162306a36Sopenharmony_ci } 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci if (!iqs7222->tp_code[0]) 278462306a36Sopenharmony_ci return 0; 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci input_set_abs_params(iqs7222->keypad, ABS_X, 278762306a36Sopenharmony_ci 0, (tpad_setup[4] ? : 1) - 1, 0, 0); 278862306a36Sopenharmony_ci 278962306a36Sopenharmony_ci input_set_abs_params(iqs7222->keypad, ABS_Y, 279062306a36Sopenharmony_ci 0, (tpad_setup[5] ? : 1) - 1, 0, 0); 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci touchscreen_parse_properties(iqs7222->keypad, false, prop); 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_ci if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) { 279562306a36Sopenharmony_ci dev_err(&client->dev, "Invalid trackpad size: %u*%u\n", 279662306a36Sopenharmony_ci prop->max_x, prop->max_y); 279762306a36Sopenharmony_ci return -EINVAL; 279862306a36Sopenharmony_ci } 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci tpad_setup[4] = prop->max_x + 1; 280162306a36Sopenharmony_ci tpad_setup[5] = prop->max_y + 1; 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci return 0; 280462306a36Sopenharmony_ci} 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_cistatic int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS]) 280762306a36Sopenharmony_ci (struct iqs7222_private *iqs7222, 280862306a36Sopenharmony_ci struct fwnode_handle *reg_grp_node, 280962306a36Sopenharmony_ci int reg_grp_index) = { 281062306a36Sopenharmony_ci [IQS7222_REG_GRP_CYCLE] = iqs7222_parse_cycle, 281162306a36Sopenharmony_ci [IQS7222_REG_GRP_CHAN] = iqs7222_parse_chan, 281262306a36Sopenharmony_ci [IQS7222_REG_GRP_SLDR] = iqs7222_parse_sldr, 281362306a36Sopenharmony_ci [IQS7222_REG_GRP_TPAD] = iqs7222_parse_tpad, 281462306a36Sopenharmony_ci}; 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_cistatic int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222, 281762306a36Sopenharmony_ci enum iqs7222_reg_grp_id reg_grp, 281862306a36Sopenharmony_ci int reg_grp_index) 281962306a36Sopenharmony_ci{ 282062306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 282162306a36Sopenharmony_ci struct fwnode_handle *reg_grp_node; 282262306a36Sopenharmony_ci int error; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci if (iqs7222_reg_grp_names[reg_grp]) { 282562306a36Sopenharmony_ci char reg_grp_name[16]; 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci snprintf(reg_grp_name, sizeof(reg_grp_name), 282862306a36Sopenharmony_ci iqs7222_reg_grp_names[reg_grp], reg_grp_index); 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci reg_grp_node = device_get_named_child_node(&client->dev, 283162306a36Sopenharmony_ci reg_grp_name); 283262306a36Sopenharmony_ci } else { 283362306a36Sopenharmony_ci reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev)); 283462306a36Sopenharmony_ci } 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci if (!reg_grp_node) 283762306a36Sopenharmony_ci return 0; 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci error = iqs7222_parse_props(iqs7222, reg_grp_node, reg_grp_index, 284062306a36Sopenharmony_ci reg_grp, IQS7222_REG_KEY_NONE); 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_ci if (!error && iqs7222_parse_extra[reg_grp]) 284362306a36Sopenharmony_ci error = iqs7222_parse_extra[reg_grp](iqs7222, reg_grp_node, 284462306a36Sopenharmony_ci reg_grp_index); 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci fwnode_handle_put(reg_grp_node); 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci return error; 284962306a36Sopenharmony_ci} 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_cistatic int iqs7222_parse_all(struct iqs7222_private *iqs7222) 285262306a36Sopenharmony_ci{ 285362306a36Sopenharmony_ci const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 285462306a36Sopenharmony_ci const struct iqs7222_reg_grp_desc *reg_grps = dev_desc->reg_grps; 285562306a36Sopenharmony_ci u16 *sys_setup = iqs7222->sys_setup; 285662306a36Sopenharmony_ci int error, i, j; 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_ci if (dev_desc->allow_offset) 285962306a36Sopenharmony_ci sys_setup[dev_desc->allow_offset] = U16_MAX; 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci if (dev_desc->event_offset) 286262306a36Sopenharmony_ci sys_setup[dev_desc->event_offset] = IQS7222_EVENT_MASK_ATI; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci for (i = 0; i < reg_grps[IQS7222_REG_GRP_GPIO].num_row; i++) { 286562306a36Sopenharmony_ci u16 *gpio_setup = iqs7222->gpio_setup[i]; 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci gpio_setup[0] &= ~IQS7222_GPIO_SETUP_0_GPIO_EN; 286862306a36Sopenharmony_ci gpio_setup[1] = 0; 286962306a36Sopenharmony_ci gpio_setup[2] = 0; 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci if (reg_grps[IQS7222_REG_GRP_GPIO].num_row == 1) 287262306a36Sopenharmony_ci continue; 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci /* 287562306a36Sopenharmony_ci * The IQS7222C and IQS7222D expose multiple GPIO and must be 287662306a36Sopenharmony_ci * informed as to which GPIO this group represents. 287762306a36Sopenharmony_ci */ 287862306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++) 287962306a36Sopenharmony_ci gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]); 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci gpio_setup[0] |= BIT(iqs7222_gpio_links[i]); 288262306a36Sopenharmony_ci } 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) { 288562306a36Sopenharmony_ci u16 *chan_setup = iqs7222->chan_setup[i]; 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_REF_MODE_MASK; 288862306a36Sopenharmony_ci chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_CHAN_EN; 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci chan_setup[5] = 0; 289162306a36Sopenharmony_ci } 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci for (i = 0; i < reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) { 289462306a36Sopenharmony_ci u16 *sldr_setup = iqs7222->sldr_setup[i]; 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci sldr_setup[0] &= ~IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK; 289762306a36Sopenharmony_ci } 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) { 290062306a36Sopenharmony_ci for (j = 0; j < reg_grps[i].num_row; j++) { 290162306a36Sopenharmony_ci error = iqs7222_parse_reg_grp(iqs7222, i, j); 290262306a36Sopenharmony_ci if (error) 290362306a36Sopenharmony_ci return error; 290462306a36Sopenharmony_ci } 290562306a36Sopenharmony_ci } 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_ci return 0; 290862306a36Sopenharmony_ci} 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_cistatic int iqs7222_report(struct iqs7222_private *iqs7222) 291162306a36Sopenharmony_ci{ 291262306a36Sopenharmony_ci const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; 291362306a36Sopenharmony_ci struct i2c_client *client = iqs7222->client; 291462306a36Sopenharmony_ci int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; 291562306a36Sopenharmony_ci int num_stat = dev_desc->reg_grps[IQS7222_REG_GRP_STAT].num_col; 291662306a36Sopenharmony_ci int error, i, j; 291762306a36Sopenharmony_ci __le16 status[IQS7222_MAX_COLS_STAT]; 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status, 292062306a36Sopenharmony_ci num_stat); 292162306a36Sopenharmony_ci if (error) 292262306a36Sopenharmony_ci return error; 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_RESET) { 292562306a36Sopenharmony_ci dev_err(&client->dev, "Unexpected device reset\n"); 292662306a36Sopenharmony_ci return iqs7222_dev_init(iqs7222, WRITE); 292762306a36Sopenharmony_ci } 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ERROR) { 293062306a36Sopenharmony_ci dev_err(&client->dev, "Unexpected ATI error\n"); 293162306a36Sopenharmony_ci return iqs7222_ati_trigger(iqs7222); 293262306a36Sopenharmony_ci } 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ACTIVE) 293562306a36Sopenharmony_ci return 0; 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_ci for (i = 0; i < num_chan; i++) { 293862306a36Sopenharmony_ci u16 *chan_setup = iqs7222->chan_setup[i]; 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci if (!(chan_setup[0] & IQS7222_CHAN_SETUP_0_CHAN_EN)) 294162306a36Sopenharmony_ci continue; 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(iqs7222_kp_events); j++) { 294462306a36Sopenharmony_ci /* 294562306a36Sopenharmony_ci * Proximity state begins at offset 2 and spills into 294662306a36Sopenharmony_ci * offset 3 for devices with more than 16 channels. 294762306a36Sopenharmony_ci * 294862306a36Sopenharmony_ci * Touch state begins at the first offset immediately 294962306a36Sopenharmony_ci * following proximity state. 295062306a36Sopenharmony_ci */ 295162306a36Sopenharmony_ci int k = 2 + j * (num_chan > 16 ? 2 : 1); 295262306a36Sopenharmony_ci u16 state = le16_to_cpu(status[k + i / 16]); 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci if (!iqs7222->kp_type[i][j]) 295562306a36Sopenharmony_ci continue; 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci input_event(iqs7222->keypad, 295862306a36Sopenharmony_ci iqs7222->kp_type[i][j], 295962306a36Sopenharmony_ci iqs7222->kp_code[i][j], 296062306a36Sopenharmony_ci !!(state & BIT(i % 16))); 296162306a36Sopenharmony_ci } 296262306a36Sopenharmony_ci } 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) { 296562306a36Sopenharmony_ci u16 *sldr_setup = iqs7222->sldr_setup[i]; 296662306a36Sopenharmony_ci u16 sldr_pos = le16_to_cpu(status[4 + i]); 296762306a36Sopenharmony_ci u16 state = le16_to_cpu(status[6 + i]); 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci if (!(sldr_setup[0] & IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK)) 297062306a36Sopenharmony_ci continue; 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci if (sldr_pos < dev_desc->sldr_res) 297362306a36Sopenharmony_ci input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i], 297462306a36Sopenharmony_ci sldr_pos); 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci input_report_key(iqs7222->keypad, iqs7222->sl_code[i][0], 297762306a36Sopenharmony_ci sldr_pos < dev_desc->sldr_res); 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci /* 298062306a36Sopenharmony_ci * A maximum resolution indicates the device does not support 298162306a36Sopenharmony_ci * gestures, in which case the remaining fields are ignored. 298262306a36Sopenharmony_ci */ 298362306a36Sopenharmony_ci if (dev_desc->sldr_res == U16_MAX) 298462306a36Sopenharmony_ci continue; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_SLDR << i)) 298762306a36Sopenharmony_ci continue; 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci /* 299062306a36Sopenharmony_ci * Skip the press/release event, as it does not have separate 299162306a36Sopenharmony_ci * status fields and is handled separately. 299262306a36Sopenharmony_ci */ 299362306a36Sopenharmony_ci for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++) { 299462306a36Sopenharmony_ci u16 mask = iqs7222_sl_events[j].mask; 299562306a36Sopenharmony_ci u16 val = iqs7222_sl_events[j].val; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci input_report_key(iqs7222->keypad, 299862306a36Sopenharmony_ci iqs7222->sl_code[i][j], 299962306a36Sopenharmony_ci (state & mask) == val); 300062306a36Sopenharmony_ci } 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci input_sync(iqs7222->keypad); 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_ci for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++) 300562306a36Sopenharmony_ci input_report_key(iqs7222->keypad, 300662306a36Sopenharmony_ci iqs7222->sl_code[i][j], 0); 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row; i++) { 301062306a36Sopenharmony_ci u16 tpad_pos_x = le16_to_cpu(status[4]); 301162306a36Sopenharmony_ci u16 tpad_pos_y = le16_to_cpu(status[5]); 301262306a36Sopenharmony_ci u16 state = le16_to_cpu(status[6]); 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci input_report_key(iqs7222->keypad, iqs7222->tp_code[0], 301562306a36Sopenharmony_ci tpad_pos_x < U16_MAX); 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_ci if (tpad_pos_x < U16_MAX) 301862306a36Sopenharmony_ci touchscreen_report_pos(iqs7222->keypad, &iqs7222->prop, 301962306a36Sopenharmony_ci tpad_pos_x, tpad_pos_y, false); 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_TPAD)) 302262306a36Sopenharmony_ci continue; 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci /* 302562306a36Sopenharmony_ci * Skip the press/release event, as it does not have separate 302662306a36Sopenharmony_ci * status fields and is handled separately. 302762306a36Sopenharmony_ci */ 302862306a36Sopenharmony_ci for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) { 302962306a36Sopenharmony_ci u16 mask = iqs7222_tp_events[j].mask; 303062306a36Sopenharmony_ci u16 val = iqs7222_tp_events[j].val; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci input_report_key(iqs7222->keypad, 303362306a36Sopenharmony_ci iqs7222->tp_code[j], 303462306a36Sopenharmony_ci (state & mask) == val); 303562306a36Sopenharmony_ci } 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci input_sync(iqs7222->keypad); 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) 304062306a36Sopenharmony_ci input_report_key(iqs7222->keypad, 304162306a36Sopenharmony_ci iqs7222->tp_code[j], 0); 304262306a36Sopenharmony_ci } 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ci input_sync(iqs7222->keypad); 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci return 0; 304762306a36Sopenharmony_ci} 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_cistatic irqreturn_t iqs7222_irq(int irq, void *context) 305062306a36Sopenharmony_ci{ 305162306a36Sopenharmony_ci struct iqs7222_private *iqs7222 = context; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci return iqs7222_report(iqs7222) ? IRQ_NONE : IRQ_HANDLED; 305462306a36Sopenharmony_ci} 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_cistatic int iqs7222_probe(struct i2c_client *client) 305762306a36Sopenharmony_ci{ 305862306a36Sopenharmony_ci struct iqs7222_private *iqs7222; 305962306a36Sopenharmony_ci unsigned long irq_flags; 306062306a36Sopenharmony_ci int error, irq; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci iqs7222 = devm_kzalloc(&client->dev, sizeof(*iqs7222), GFP_KERNEL); 306362306a36Sopenharmony_ci if (!iqs7222) 306462306a36Sopenharmony_ci return -ENOMEM; 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci i2c_set_clientdata(client, iqs7222); 306762306a36Sopenharmony_ci iqs7222->client = client; 306862306a36Sopenharmony_ci 306962306a36Sopenharmony_ci iqs7222->keypad = devm_input_allocate_device(&client->dev); 307062306a36Sopenharmony_ci if (!iqs7222->keypad) 307162306a36Sopenharmony_ci return -ENOMEM; 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci iqs7222->keypad->name = client->name; 307462306a36Sopenharmony_ci iqs7222->keypad->id.bustype = BUS_I2C; 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci /* 307762306a36Sopenharmony_ci * The RDY pin behaves as an interrupt, but must also be polled ahead 307862306a36Sopenharmony_ci * of unsolicited I2C communication. As such, it is first opened as a 307962306a36Sopenharmony_ci * GPIO and then passed to gpiod_to_irq() to register the interrupt. 308062306a36Sopenharmony_ci */ 308162306a36Sopenharmony_ci iqs7222->irq_gpio = devm_gpiod_get(&client->dev, "irq", GPIOD_IN); 308262306a36Sopenharmony_ci if (IS_ERR(iqs7222->irq_gpio)) { 308362306a36Sopenharmony_ci error = PTR_ERR(iqs7222->irq_gpio); 308462306a36Sopenharmony_ci dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n", 308562306a36Sopenharmony_ci error); 308662306a36Sopenharmony_ci return error; 308762306a36Sopenharmony_ci } 308862306a36Sopenharmony_ci 308962306a36Sopenharmony_ci iqs7222->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", 309062306a36Sopenharmony_ci GPIOD_OUT_HIGH); 309162306a36Sopenharmony_ci if (IS_ERR(iqs7222->reset_gpio)) { 309262306a36Sopenharmony_ci error = PTR_ERR(iqs7222->reset_gpio); 309362306a36Sopenharmony_ci dev_err(&client->dev, "Failed to request reset GPIO: %d\n", 309462306a36Sopenharmony_ci error); 309562306a36Sopenharmony_ci return error; 309662306a36Sopenharmony_ci } 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci error = iqs7222_hard_reset(iqs7222); 309962306a36Sopenharmony_ci if (error) 310062306a36Sopenharmony_ci return error; 310162306a36Sopenharmony_ci 310262306a36Sopenharmony_ci error = iqs7222_dev_info(iqs7222); 310362306a36Sopenharmony_ci if (error) 310462306a36Sopenharmony_ci return error; 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci error = iqs7222_dev_init(iqs7222, READ); 310762306a36Sopenharmony_ci if (error) 310862306a36Sopenharmony_ci return error; 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci error = iqs7222_parse_all(iqs7222); 311162306a36Sopenharmony_ci if (error) 311262306a36Sopenharmony_ci return error; 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci error = iqs7222_dev_init(iqs7222, WRITE); 311562306a36Sopenharmony_ci if (error) 311662306a36Sopenharmony_ci return error; 311762306a36Sopenharmony_ci 311862306a36Sopenharmony_ci error = iqs7222_report(iqs7222); 311962306a36Sopenharmony_ci if (error) 312062306a36Sopenharmony_ci return error; 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci error = input_register_device(iqs7222->keypad); 312362306a36Sopenharmony_ci if (error) { 312462306a36Sopenharmony_ci dev_err(&client->dev, "Failed to register device: %d\n", error); 312562306a36Sopenharmony_ci return error; 312662306a36Sopenharmony_ci } 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_ci irq = gpiod_to_irq(iqs7222->irq_gpio); 312962306a36Sopenharmony_ci if (irq < 0) 313062306a36Sopenharmony_ci return irq; 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci irq_flags = gpiod_is_active_low(iqs7222->irq_gpio) ? IRQF_TRIGGER_LOW 313362306a36Sopenharmony_ci : IRQF_TRIGGER_HIGH; 313462306a36Sopenharmony_ci irq_flags |= IRQF_ONESHOT; 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7222_irq, 313762306a36Sopenharmony_ci irq_flags, client->name, iqs7222); 313862306a36Sopenharmony_ci if (error) 313962306a36Sopenharmony_ci dev_err(&client->dev, "Failed to request IRQ: %d\n", error); 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci return error; 314262306a36Sopenharmony_ci} 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_cistatic const struct of_device_id iqs7222_of_match[] = { 314562306a36Sopenharmony_ci { .compatible = "azoteq,iqs7222a" }, 314662306a36Sopenharmony_ci { .compatible = "azoteq,iqs7222b" }, 314762306a36Sopenharmony_ci { .compatible = "azoteq,iqs7222c" }, 314862306a36Sopenharmony_ci { .compatible = "azoteq,iqs7222d" }, 314962306a36Sopenharmony_ci { } 315062306a36Sopenharmony_ci}; 315162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, iqs7222_of_match); 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_cistatic struct i2c_driver iqs7222_i2c_driver = { 315462306a36Sopenharmony_ci .driver = { 315562306a36Sopenharmony_ci .name = "iqs7222", 315662306a36Sopenharmony_ci .of_match_table = iqs7222_of_match, 315762306a36Sopenharmony_ci }, 315862306a36Sopenharmony_ci .probe = iqs7222_probe, 315962306a36Sopenharmony_ci}; 316062306a36Sopenharmony_cimodule_i2c_driver(iqs7222_i2c_driver); 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ciMODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); 316362306a36Sopenharmony_ciMODULE_DESCRIPTION("Azoteq IQS7222A/B/C/D Capacitive Touch Controller"); 316462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3165