104e49867SJeff LaBundy // SPDX-License-Identifier: GPL-2.0+ 204e49867SJeff LaBundy /* 304e49867SJeff LaBundy * Azoteq IQS269A Capacitive Touch Controller 404e49867SJeff LaBundy * 504e49867SJeff LaBundy * Copyright (C) 2020 Jeff LaBundy <jeff@labundy.com> 604e49867SJeff LaBundy * 704e49867SJeff LaBundy * This driver registers up to 3 input devices: one representing capacitive or 804e49867SJeff LaBundy * inductive keys as well as Hall-effect switches, and one for each of the two 904e49867SJeff LaBundy * axial sliders presented by the device. 1004e49867SJeff LaBundy */ 1104e49867SJeff LaBundy 1204e49867SJeff LaBundy #include <linux/delay.h> 1304e49867SJeff LaBundy #include <linux/device.h> 1404e49867SJeff LaBundy #include <linux/err.h> 1504e49867SJeff LaBundy #include <linux/i2c.h> 1604e49867SJeff LaBundy #include <linux/input.h> 1704e49867SJeff LaBundy #include <linux/interrupt.h> 1804e49867SJeff LaBundy #include <linux/kernel.h> 1904e49867SJeff LaBundy #include <linux/module.h> 2004e49867SJeff LaBundy #include <linux/mutex.h> 2104e49867SJeff LaBundy #include <linux/of_device.h> 2204e49867SJeff LaBundy #include <linux/property.h> 2304e49867SJeff LaBundy #include <linux/regmap.h> 2404e49867SJeff LaBundy #include <linux/slab.h> 2504e49867SJeff LaBundy 2604e49867SJeff LaBundy #define IQS269_VER_INFO 0x00 2704e49867SJeff LaBundy #define IQS269_VER_INFO_PROD_NUM 0x4F 2804e49867SJeff LaBundy 2904e49867SJeff LaBundy #define IQS269_SYS_FLAGS 0x02 3004e49867SJeff LaBundy #define IQS269_SYS_FLAGS_SHOW_RESET BIT(15) 3104e49867SJeff LaBundy #define IQS269_SYS_FLAGS_PWR_MODE_MASK GENMASK(12, 11) 3204e49867SJeff LaBundy #define IQS269_SYS_FLAGS_PWR_MODE_SHIFT 11 3304e49867SJeff LaBundy #define IQS269_SYS_FLAGS_IN_ATI BIT(10) 3404e49867SJeff LaBundy 3504e49867SJeff LaBundy #define IQS269_CHx_COUNTS 0x08 3604e49867SJeff LaBundy 3704e49867SJeff LaBundy #define IQS269_SLIDER_X 0x30 3804e49867SJeff LaBundy 3904e49867SJeff LaBundy #define IQS269_CAL_DATA_A 0x35 4004e49867SJeff LaBundy #define IQS269_CAL_DATA_A_HALL_BIN_L_MASK GENMASK(15, 12) 4104e49867SJeff LaBundy #define IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT 12 4204e49867SJeff LaBundy #define IQS269_CAL_DATA_A_HALL_BIN_R_MASK GENMASK(11, 8) 4304e49867SJeff LaBundy #define IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT 8 4404e49867SJeff LaBundy 4504e49867SJeff LaBundy #define IQS269_SYS_SETTINGS 0x80 4604e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_CLK_DIV BIT(15) 4704e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ULP_AUTO BIT(14) 4804e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_DIS_AUTO BIT(13) 4904e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_PWR_MODE_MASK GENMASK(12, 11) 5004e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_PWR_MODE_SHIFT 11 5104e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_PWR_MODE_MAX 3 5204e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ULP_UPDATE_MASK GENMASK(10, 8) 5304e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT 8 5404e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ULP_UPDATE_MAX 7 5504e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_RESEED_OFFSET BIT(6) 5604e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_EVENT_MODE BIT(5) 5704e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_EVENT_MODE_LP BIT(4) 5804e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_REDO_ATI BIT(2) 5904e49867SJeff LaBundy #define IQS269_SYS_SETTINGS_ACK_RESET BIT(0) 6004e49867SJeff LaBundy 6104e49867SJeff LaBundy #define IQS269_FILT_STR_LP_LTA_MASK GENMASK(7, 6) 6204e49867SJeff LaBundy #define IQS269_FILT_STR_LP_LTA_SHIFT 6 6304e49867SJeff LaBundy #define IQS269_FILT_STR_LP_CNT_MASK GENMASK(5, 4) 6404e49867SJeff LaBundy #define IQS269_FILT_STR_LP_CNT_SHIFT 4 6504e49867SJeff LaBundy #define IQS269_FILT_STR_NP_LTA_MASK GENMASK(3, 2) 6604e49867SJeff LaBundy #define IQS269_FILT_STR_NP_LTA_SHIFT 2 6704e49867SJeff LaBundy #define IQS269_FILT_STR_NP_CNT_MASK GENMASK(1, 0) 6804e49867SJeff LaBundy #define IQS269_FILT_STR_MAX 3 6904e49867SJeff LaBundy 7004e49867SJeff LaBundy #define IQS269_EVENT_MASK_SYS BIT(6) 7104e49867SJeff LaBundy #define IQS269_EVENT_MASK_DEEP BIT(2) 7204e49867SJeff LaBundy #define IQS269_EVENT_MASK_TOUCH BIT(1) 7304e49867SJeff LaBundy #define IQS269_EVENT_MASK_PROX BIT(0) 7404e49867SJeff LaBundy 7504e49867SJeff LaBundy #define IQS269_RATE_NP_MS_MAX 255 7604e49867SJeff LaBundy #define IQS269_RATE_LP_MS_MAX 255 7704e49867SJeff LaBundy #define IQS269_RATE_ULP_MS_MAX 4080 7804e49867SJeff LaBundy #define IQS269_TIMEOUT_PWR_MS_MAX 130560 7904e49867SJeff LaBundy #define IQS269_TIMEOUT_LTA_MS_MAX 130560 8004e49867SJeff LaBundy 8104e49867SJeff LaBundy #define IQS269_MISC_A_ATI_BAND_DISABLE BIT(15) 8204e49867SJeff LaBundy #define IQS269_MISC_A_ATI_LP_ONLY BIT(14) 8304e49867SJeff LaBundy #define IQS269_MISC_A_ATI_BAND_TIGHTEN BIT(13) 8404e49867SJeff LaBundy #define IQS269_MISC_A_FILT_DISABLE BIT(12) 8504e49867SJeff LaBundy #define IQS269_MISC_A_GPIO3_SELECT_MASK GENMASK(10, 8) 8604e49867SJeff LaBundy #define IQS269_MISC_A_GPIO3_SELECT_SHIFT 8 8704e49867SJeff LaBundy #define IQS269_MISC_A_DUAL_DIR BIT(6) 8804e49867SJeff LaBundy #define IQS269_MISC_A_TX_FREQ_MASK GENMASK(5, 4) 8904e49867SJeff LaBundy #define IQS269_MISC_A_TX_FREQ_SHIFT 4 9004e49867SJeff LaBundy #define IQS269_MISC_A_TX_FREQ_MAX 3 9104e49867SJeff LaBundy #define IQS269_MISC_A_GLOBAL_CAP_SIZE BIT(0) 9204e49867SJeff LaBundy 9304e49867SJeff LaBundy #define IQS269_MISC_B_RESEED_UI_SEL_MASK GENMASK(7, 6) 9404e49867SJeff LaBundy #define IQS269_MISC_B_RESEED_UI_SEL_SHIFT 6 9504e49867SJeff LaBundy #define IQS269_MISC_B_RESEED_UI_SEL_MAX 3 9604e49867SJeff LaBundy #define IQS269_MISC_B_TRACKING_UI_ENABLE BIT(4) 9704e49867SJeff LaBundy #define IQS269_MISC_B_FILT_STR_SLIDER GENMASK(1, 0) 9804e49867SJeff LaBundy 9904e49867SJeff LaBundy #define IQS269_CHx_ENG_A_MEAS_CAP_SIZE BIT(15) 10004e49867SJeff LaBundy #define IQS269_CHx_ENG_A_RX_GND_INACTIVE BIT(13) 10104e49867SJeff LaBundy #define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE BIT(12) 10204e49867SJeff LaBundy #define IQS269_CHx_ENG_A_ATI_MODE_MASK GENMASK(9, 8) 10304e49867SJeff LaBundy #define IQS269_CHx_ENG_A_ATI_MODE_SHIFT 8 10404e49867SJeff LaBundy #define IQS269_CHx_ENG_A_ATI_MODE_MAX 3 10504e49867SJeff LaBundy #define IQS269_CHx_ENG_A_INV_LOGIC BIT(7) 10604e49867SJeff LaBundy #define IQS269_CHx_ENG_A_PROJ_BIAS_MASK GENMASK(6, 5) 10704e49867SJeff LaBundy #define IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT 5 10804e49867SJeff LaBundy #define IQS269_CHx_ENG_A_PROJ_BIAS_MAX 3 10904e49867SJeff LaBundy #define IQS269_CHx_ENG_A_SENSE_MODE_MASK GENMASK(3, 0) 11004e49867SJeff LaBundy #define IQS269_CHx_ENG_A_SENSE_MODE_MAX 15 11104e49867SJeff LaBundy 11204e49867SJeff LaBundy #define IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE BIT(13) 11304e49867SJeff LaBundy #define IQS269_CHx_ENG_B_SENSE_FREQ_MASK GENMASK(10, 9) 11404e49867SJeff LaBundy #define IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT 9 11504e49867SJeff LaBundy #define IQS269_CHx_ENG_B_SENSE_FREQ_MAX 3 11604e49867SJeff LaBundy #define IQS269_CHx_ENG_B_STATIC_ENABLE BIT(8) 11704e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_MASK GENMASK(7, 6) 11804e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_75 0x00 11904e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_100 0x40 12004e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_150 0x80 12104e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_200 0xC0 12204e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_TARGET_MASK GENMASK(5, 0) 12304e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_TARGET_MAX 2016 12404e49867SJeff LaBundy 12504e49867SJeff LaBundy #define IQS269_CHx_WEIGHT_MAX 255 12604e49867SJeff LaBundy #define IQS269_CHx_THRESH_MAX 255 12704e49867SJeff LaBundy #define IQS269_CHx_HYST_DEEP_MASK GENMASK(7, 4) 12804e49867SJeff LaBundy #define IQS269_CHx_HYST_DEEP_SHIFT 4 12904e49867SJeff LaBundy #define IQS269_CHx_HYST_TOUCH_MASK GENMASK(3, 0) 13004e49867SJeff LaBundy #define IQS269_CHx_HYST_MAX 15 13104e49867SJeff LaBundy 13204e49867SJeff LaBundy #define IQS269_CHx_HALL_INACTIVE 6 13304e49867SJeff LaBundy #define IQS269_CHx_HALL_ACTIVE 7 13404e49867SJeff LaBundy 13504e49867SJeff LaBundy #define IQS269_HALL_PAD_R BIT(0) 13604e49867SJeff LaBundy #define IQS269_HALL_PAD_L BIT(1) 13704e49867SJeff LaBundy #define IQS269_HALL_PAD_INV BIT(6) 13804e49867SJeff LaBundy 13904e49867SJeff LaBundy #define IQS269_HALL_UI 0xF5 14004e49867SJeff LaBundy #define IQS269_HALL_UI_ENABLE BIT(15) 14104e49867SJeff LaBundy 14204e49867SJeff LaBundy #define IQS269_MAX_REG 0xFF 14304e49867SJeff LaBundy 14404e49867SJeff LaBundy #define IQS269_NUM_CH 8 14504e49867SJeff LaBundy #define IQS269_NUM_SL 2 14604e49867SJeff LaBundy 14704e49867SJeff LaBundy #define IQS269_ATI_POLL_SLEEP_US (iqs269->delay_mult * 10000) 14804e49867SJeff LaBundy #define IQS269_ATI_POLL_TIMEOUT_US (iqs269->delay_mult * 500000) 14904e49867SJeff LaBundy #define IQS269_ATI_STABLE_DELAY_MS (iqs269->delay_mult * 150) 15004e49867SJeff LaBundy 151e023cc4aSJeff LaBundy #define iqs269_irq_wait() usleep_range(200, 250) 15204e49867SJeff LaBundy 15304e49867SJeff LaBundy enum iqs269_local_cap_size { 15404e49867SJeff LaBundy IQS269_LOCAL_CAP_SIZE_0, 15504e49867SJeff LaBundy IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY, 15604e49867SJeff LaBundy IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5, 15704e49867SJeff LaBundy }; 15804e49867SJeff LaBundy 15904e49867SJeff LaBundy enum iqs269_st_offs { 16004e49867SJeff LaBundy IQS269_ST_OFFS_PROX, 16104e49867SJeff LaBundy IQS269_ST_OFFS_DIR, 16204e49867SJeff LaBundy IQS269_ST_OFFS_TOUCH, 16304e49867SJeff LaBundy IQS269_ST_OFFS_DEEP, 16404e49867SJeff LaBundy }; 16504e49867SJeff LaBundy 16604e49867SJeff LaBundy enum iqs269_th_offs { 16704e49867SJeff LaBundy IQS269_TH_OFFS_PROX, 16804e49867SJeff LaBundy IQS269_TH_OFFS_TOUCH, 16904e49867SJeff LaBundy IQS269_TH_OFFS_DEEP, 17004e49867SJeff LaBundy }; 17104e49867SJeff LaBundy 17204e49867SJeff LaBundy enum iqs269_event_id { 17304e49867SJeff LaBundy IQS269_EVENT_PROX_DN, 17404e49867SJeff LaBundy IQS269_EVENT_PROX_UP, 17504e49867SJeff LaBundy IQS269_EVENT_TOUCH_DN, 17604e49867SJeff LaBundy IQS269_EVENT_TOUCH_UP, 17704e49867SJeff LaBundy IQS269_EVENT_DEEP_DN, 17804e49867SJeff LaBundy IQS269_EVENT_DEEP_UP, 17904e49867SJeff LaBundy }; 18004e49867SJeff LaBundy 18104e49867SJeff LaBundy struct iqs269_switch_desc { 18204e49867SJeff LaBundy unsigned int code; 18304e49867SJeff LaBundy bool enabled; 18404e49867SJeff LaBundy }; 18504e49867SJeff LaBundy 18604e49867SJeff LaBundy struct iqs269_event_desc { 18704e49867SJeff LaBundy const char *name; 18804e49867SJeff LaBundy enum iqs269_st_offs st_offs; 18904e49867SJeff LaBundy enum iqs269_th_offs th_offs; 19004e49867SJeff LaBundy bool dir_up; 19104e49867SJeff LaBundy u8 mask; 19204e49867SJeff LaBundy }; 19304e49867SJeff LaBundy 19404e49867SJeff LaBundy static const struct iqs269_event_desc iqs269_events[] = { 19504e49867SJeff LaBundy [IQS269_EVENT_PROX_DN] = { 19604e49867SJeff LaBundy .name = "event-prox", 19704e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_PROX, 19804e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_PROX, 19904e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_PROX, 20004e49867SJeff LaBundy }, 20104e49867SJeff LaBundy [IQS269_EVENT_PROX_UP] = { 20204e49867SJeff LaBundy .name = "event-prox-alt", 20304e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_PROX, 20404e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_PROX, 20504e49867SJeff LaBundy .dir_up = true, 20604e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_PROX, 20704e49867SJeff LaBundy }, 20804e49867SJeff LaBundy [IQS269_EVENT_TOUCH_DN] = { 20904e49867SJeff LaBundy .name = "event-touch", 21004e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_TOUCH, 21104e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_TOUCH, 21204e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_TOUCH, 21304e49867SJeff LaBundy }, 21404e49867SJeff LaBundy [IQS269_EVENT_TOUCH_UP] = { 21504e49867SJeff LaBundy .name = "event-touch-alt", 21604e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_TOUCH, 21704e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_TOUCH, 21804e49867SJeff LaBundy .dir_up = true, 21904e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_TOUCH, 22004e49867SJeff LaBundy }, 22104e49867SJeff LaBundy [IQS269_EVENT_DEEP_DN] = { 22204e49867SJeff LaBundy .name = "event-deep", 22304e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_DEEP, 22404e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_DEEP, 22504e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_DEEP, 22604e49867SJeff LaBundy }, 22704e49867SJeff LaBundy [IQS269_EVENT_DEEP_UP] = { 22804e49867SJeff LaBundy .name = "event-deep-alt", 22904e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_DEEP, 23004e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_DEEP, 23104e49867SJeff LaBundy .dir_up = true, 23204e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_DEEP, 23304e49867SJeff LaBundy }, 23404e49867SJeff LaBundy }; 23504e49867SJeff LaBundy 23604e49867SJeff LaBundy struct iqs269_ver_info { 23704e49867SJeff LaBundy u8 prod_num; 23804e49867SJeff LaBundy u8 sw_num; 23904e49867SJeff LaBundy u8 hw_num; 24004e49867SJeff LaBundy u8 padding; 24104e49867SJeff LaBundy } __packed; 24204e49867SJeff LaBundy 2433689abfcSJeff LaBundy struct iqs269_ch_reg { 2443689abfcSJeff LaBundy u8 rx_enable; 2453689abfcSJeff LaBundy u8 tx_enable; 2463689abfcSJeff LaBundy __be16 engine_a; 2473689abfcSJeff LaBundy __be16 engine_b; 2483689abfcSJeff LaBundy __be16 ati_comp; 2493689abfcSJeff LaBundy u8 thresh[3]; 2503689abfcSJeff LaBundy u8 hyst; 2513689abfcSJeff LaBundy u8 assoc_select; 2523689abfcSJeff LaBundy u8 assoc_weight; 2533689abfcSJeff LaBundy } __packed; 2543689abfcSJeff LaBundy 25504e49867SJeff LaBundy struct iqs269_sys_reg { 25604e49867SJeff LaBundy __be16 general; 25704e49867SJeff LaBundy u8 active; 25804e49867SJeff LaBundy u8 filter; 25904e49867SJeff LaBundy u8 reseed; 26004e49867SJeff LaBundy u8 event_mask; 26104e49867SJeff LaBundy u8 rate_np; 26204e49867SJeff LaBundy u8 rate_lp; 26304e49867SJeff LaBundy u8 rate_ulp; 26404e49867SJeff LaBundy u8 timeout_pwr; 26504e49867SJeff LaBundy u8 timeout_rdy; 26604e49867SJeff LaBundy u8 timeout_lta; 26704e49867SJeff LaBundy __be16 misc_a; 26804e49867SJeff LaBundy __be16 misc_b; 26904e49867SJeff LaBundy u8 blocking; 27004e49867SJeff LaBundy u8 padding; 27104e49867SJeff LaBundy u8 slider_select[IQS269_NUM_SL]; 27204e49867SJeff LaBundy u8 timeout_tap; 27304e49867SJeff LaBundy u8 timeout_swipe; 27404e49867SJeff LaBundy u8 thresh_swipe; 27504e49867SJeff LaBundy u8 redo_ati; 2763689abfcSJeff LaBundy struct iqs269_ch_reg ch_reg[IQS269_NUM_CH]; 27704e49867SJeff LaBundy } __packed; 27804e49867SJeff LaBundy 27904e49867SJeff LaBundy struct iqs269_flags { 28004e49867SJeff LaBundy __be16 system; 28104e49867SJeff LaBundy u8 gesture; 28204e49867SJeff LaBundy u8 padding; 28304e49867SJeff LaBundy u8 states[4]; 28404e49867SJeff LaBundy } __packed; 28504e49867SJeff LaBundy 28604e49867SJeff LaBundy struct iqs269_private { 28704e49867SJeff LaBundy struct i2c_client *client; 28804e49867SJeff LaBundy struct regmap *regmap; 28904e49867SJeff LaBundy struct mutex lock; 29004e49867SJeff LaBundy struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)]; 29104e49867SJeff LaBundy struct iqs269_sys_reg sys_reg; 29204e49867SJeff LaBundy struct input_dev *keypad; 29304e49867SJeff LaBundy struct input_dev *slider[IQS269_NUM_SL]; 29404e49867SJeff LaBundy unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH]; 29504e49867SJeff LaBundy unsigned int delay_mult; 29604e49867SJeff LaBundy unsigned int ch_num; 29704e49867SJeff LaBundy bool hall_enable; 29804e49867SJeff LaBundy bool ati_current; 29904e49867SJeff LaBundy }; 30004e49867SJeff LaBundy 30104e49867SJeff LaBundy static int iqs269_ati_mode_set(struct iqs269_private *iqs269, 30204e49867SJeff LaBundy unsigned int ch_num, unsigned int mode) 30304e49867SJeff LaBundy { 3043689abfcSJeff LaBundy struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 30504e49867SJeff LaBundy u16 engine_a; 30604e49867SJeff LaBundy 30704e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 30804e49867SJeff LaBundy return -EINVAL; 30904e49867SJeff LaBundy 31004e49867SJeff LaBundy if (mode > IQS269_CHx_ENG_A_ATI_MODE_MAX) 31104e49867SJeff LaBundy return -EINVAL; 31204e49867SJeff LaBundy 31304e49867SJeff LaBundy mutex_lock(&iqs269->lock); 31404e49867SJeff LaBundy 3153689abfcSJeff LaBundy engine_a = be16_to_cpu(ch_reg[ch_num].engine_a); 31604e49867SJeff LaBundy 31704e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_ATI_MODE_MASK; 31804e49867SJeff LaBundy engine_a |= (mode << IQS269_CHx_ENG_A_ATI_MODE_SHIFT); 31904e49867SJeff LaBundy 3203689abfcSJeff LaBundy ch_reg[ch_num].engine_a = cpu_to_be16(engine_a); 32104e49867SJeff LaBundy iqs269->ati_current = false; 32204e49867SJeff LaBundy 32304e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 32404e49867SJeff LaBundy 32504e49867SJeff LaBundy return 0; 32604e49867SJeff LaBundy } 32704e49867SJeff LaBundy 32804e49867SJeff LaBundy static int iqs269_ati_mode_get(struct iqs269_private *iqs269, 32904e49867SJeff LaBundy unsigned int ch_num, unsigned int *mode) 33004e49867SJeff LaBundy { 3313689abfcSJeff LaBundy struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 33204e49867SJeff LaBundy u16 engine_a; 33304e49867SJeff LaBundy 33404e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 33504e49867SJeff LaBundy return -EINVAL; 33604e49867SJeff LaBundy 33704e49867SJeff LaBundy mutex_lock(&iqs269->lock); 3383689abfcSJeff LaBundy engine_a = be16_to_cpu(ch_reg[ch_num].engine_a); 33904e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 34004e49867SJeff LaBundy 34104e49867SJeff LaBundy engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK; 34204e49867SJeff LaBundy *mode = (engine_a >> IQS269_CHx_ENG_A_ATI_MODE_SHIFT); 34304e49867SJeff LaBundy 34404e49867SJeff LaBundy return 0; 34504e49867SJeff LaBundy } 34604e49867SJeff LaBundy 34704e49867SJeff LaBundy static int iqs269_ati_base_set(struct iqs269_private *iqs269, 34804e49867SJeff LaBundy unsigned int ch_num, unsigned int base) 34904e49867SJeff LaBundy { 3503689abfcSJeff LaBundy struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 35104e49867SJeff LaBundy u16 engine_b; 35204e49867SJeff LaBundy 35304e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 35404e49867SJeff LaBundy return -EINVAL; 35504e49867SJeff LaBundy 35604e49867SJeff LaBundy switch (base) { 35704e49867SJeff LaBundy case 75: 35804e49867SJeff LaBundy base = IQS269_CHx_ENG_B_ATI_BASE_75; 35904e49867SJeff LaBundy break; 36004e49867SJeff LaBundy 36104e49867SJeff LaBundy case 100: 36204e49867SJeff LaBundy base = IQS269_CHx_ENG_B_ATI_BASE_100; 36304e49867SJeff LaBundy break; 36404e49867SJeff LaBundy 36504e49867SJeff LaBundy case 150: 36604e49867SJeff LaBundy base = IQS269_CHx_ENG_B_ATI_BASE_150; 36704e49867SJeff LaBundy break; 36804e49867SJeff LaBundy 36904e49867SJeff LaBundy case 200: 37004e49867SJeff LaBundy base = IQS269_CHx_ENG_B_ATI_BASE_200; 37104e49867SJeff LaBundy break; 37204e49867SJeff LaBundy 37304e49867SJeff LaBundy default: 37404e49867SJeff LaBundy return -EINVAL; 37504e49867SJeff LaBundy } 37604e49867SJeff LaBundy 37704e49867SJeff LaBundy mutex_lock(&iqs269->lock); 37804e49867SJeff LaBundy 3793689abfcSJeff LaBundy engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); 38004e49867SJeff LaBundy 38104e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_ATI_BASE_MASK; 38204e49867SJeff LaBundy engine_b |= base; 38304e49867SJeff LaBundy 3843689abfcSJeff LaBundy ch_reg[ch_num].engine_b = cpu_to_be16(engine_b); 38504e49867SJeff LaBundy iqs269->ati_current = false; 38604e49867SJeff LaBundy 38704e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 38804e49867SJeff LaBundy 38904e49867SJeff LaBundy return 0; 39004e49867SJeff LaBundy } 39104e49867SJeff LaBundy 39204e49867SJeff LaBundy static int iqs269_ati_base_get(struct iqs269_private *iqs269, 39304e49867SJeff LaBundy unsigned int ch_num, unsigned int *base) 39404e49867SJeff LaBundy { 3953689abfcSJeff LaBundy struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 39604e49867SJeff LaBundy u16 engine_b; 39704e49867SJeff LaBundy 39804e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 39904e49867SJeff LaBundy return -EINVAL; 40004e49867SJeff LaBundy 40104e49867SJeff LaBundy mutex_lock(&iqs269->lock); 4023689abfcSJeff LaBundy engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); 40304e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 40404e49867SJeff LaBundy 40504e49867SJeff LaBundy switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) { 40604e49867SJeff LaBundy case IQS269_CHx_ENG_B_ATI_BASE_75: 40704e49867SJeff LaBundy *base = 75; 40804e49867SJeff LaBundy return 0; 40904e49867SJeff LaBundy 41004e49867SJeff LaBundy case IQS269_CHx_ENG_B_ATI_BASE_100: 41104e49867SJeff LaBundy *base = 100; 41204e49867SJeff LaBundy return 0; 41304e49867SJeff LaBundy 41404e49867SJeff LaBundy case IQS269_CHx_ENG_B_ATI_BASE_150: 41504e49867SJeff LaBundy *base = 150; 41604e49867SJeff LaBundy return 0; 41704e49867SJeff LaBundy 41804e49867SJeff LaBundy case IQS269_CHx_ENG_B_ATI_BASE_200: 41904e49867SJeff LaBundy *base = 200; 42004e49867SJeff LaBundy return 0; 42104e49867SJeff LaBundy 42204e49867SJeff LaBundy default: 42304e49867SJeff LaBundy return -EINVAL; 42404e49867SJeff LaBundy } 42504e49867SJeff LaBundy } 42604e49867SJeff LaBundy 42704e49867SJeff LaBundy static int iqs269_ati_target_set(struct iqs269_private *iqs269, 42804e49867SJeff LaBundy unsigned int ch_num, unsigned int target) 42904e49867SJeff LaBundy { 4303689abfcSJeff LaBundy struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 43104e49867SJeff LaBundy u16 engine_b; 43204e49867SJeff LaBundy 43304e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 43404e49867SJeff LaBundy return -EINVAL; 43504e49867SJeff LaBundy 43604e49867SJeff LaBundy if (target > IQS269_CHx_ENG_B_ATI_TARGET_MAX) 43704e49867SJeff LaBundy return -EINVAL; 43804e49867SJeff LaBundy 43904e49867SJeff LaBundy mutex_lock(&iqs269->lock); 44004e49867SJeff LaBundy 4413689abfcSJeff LaBundy engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); 44204e49867SJeff LaBundy 44304e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_ATI_TARGET_MASK; 44404e49867SJeff LaBundy engine_b |= target / 32; 44504e49867SJeff LaBundy 4463689abfcSJeff LaBundy ch_reg[ch_num].engine_b = cpu_to_be16(engine_b); 44704e49867SJeff LaBundy iqs269->ati_current = false; 44804e49867SJeff LaBundy 44904e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 45004e49867SJeff LaBundy 45104e49867SJeff LaBundy return 0; 45204e49867SJeff LaBundy } 45304e49867SJeff LaBundy 45404e49867SJeff LaBundy static int iqs269_ati_target_get(struct iqs269_private *iqs269, 45504e49867SJeff LaBundy unsigned int ch_num, unsigned int *target) 45604e49867SJeff LaBundy { 4573689abfcSJeff LaBundy struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 45804e49867SJeff LaBundy u16 engine_b; 45904e49867SJeff LaBundy 46004e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 46104e49867SJeff LaBundy return -EINVAL; 46204e49867SJeff LaBundy 46304e49867SJeff LaBundy mutex_lock(&iqs269->lock); 4643689abfcSJeff LaBundy engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); 46504e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 46604e49867SJeff LaBundy 46704e49867SJeff LaBundy *target = (engine_b & IQS269_CHx_ENG_B_ATI_TARGET_MASK) * 32; 46804e49867SJeff LaBundy 46904e49867SJeff LaBundy return 0; 47004e49867SJeff LaBundy } 47104e49867SJeff LaBundy 47204e49867SJeff LaBundy static int iqs269_parse_mask(const struct fwnode_handle *fwnode, 47304e49867SJeff LaBundy const char *propname, u8 *mask) 47404e49867SJeff LaBundy { 47504e49867SJeff LaBundy unsigned int val[IQS269_NUM_CH]; 47604e49867SJeff LaBundy int count, error, i; 47704e49867SJeff LaBundy 47804e49867SJeff LaBundy count = fwnode_property_count_u32(fwnode, propname); 47904e49867SJeff LaBundy if (count < 0) 48004e49867SJeff LaBundy return 0; 48104e49867SJeff LaBundy 48204e49867SJeff LaBundy if (count > IQS269_NUM_CH) 48304e49867SJeff LaBundy return -EINVAL; 48404e49867SJeff LaBundy 48504e49867SJeff LaBundy error = fwnode_property_read_u32_array(fwnode, propname, val, count); 48604e49867SJeff LaBundy if (error) 48704e49867SJeff LaBundy return error; 48804e49867SJeff LaBundy 48904e49867SJeff LaBundy *mask = 0; 49004e49867SJeff LaBundy 49104e49867SJeff LaBundy for (i = 0; i < count; i++) { 49204e49867SJeff LaBundy if (val[i] >= IQS269_NUM_CH) 49304e49867SJeff LaBundy return -EINVAL; 49404e49867SJeff LaBundy 49504e49867SJeff LaBundy *mask |= BIT(val[i]); 49604e49867SJeff LaBundy } 49704e49867SJeff LaBundy 49804e49867SJeff LaBundy return 0; 49904e49867SJeff LaBundy } 50004e49867SJeff LaBundy 50104e49867SJeff LaBundy static int iqs269_parse_chan(struct iqs269_private *iqs269, 50204e49867SJeff LaBundy const struct fwnode_handle *ch_node) 50304e49867SJeff LaBundy { 50404e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 50504e49867SJeff LaBundy struct fwnode_handle *ev_node; 50604e49867SJeff LaBundy struct iqs269_ch_reg *ch_reg; 50704e49867SJeff LaBundy u16 engine_a, engine_b; 50804e49867SJeff LaBundy unsigned int reg, val; 50904e49867SJeff LaBundy int error, i; 51004e49867SJeff LaBundy 51104e49867SJeff LaBundy error = fwnode_property_read_u32(ch_node, "reg", ®); 51204e49867SJeff LaBundy if (error) { 51304e49867SJeff LaBundy dev_err(&client->dev, "Failed to read channel number: %d\n", 51404e49867SJeff LaBundy error); 51504e49867SJeff LaBundy return error; 51604e49867SJeff LaBundy } else if (reg >= IQS269_NUM_CH) { 51704e49867SJeff LaBundy dev_err(&client->dev, "Invalid channel number: %u\n", reg); 51804e49867SJeff LaBundy return -EINVAL; 51904e49867SJeff LaBundy } 52004e49867SJeff LaBundy 52104e49867SJeff LaBundy iqs269->sys_reg.active |= BIT(reg); 52204e49867SJeff LaBundy if (!fwnode_property_present(ch_node, "azoteq,reseed-disable")) 52304e49867SJeff LaBundy iqs269->sys_reg.reseed |= BIT(reg); 52404e49867SJeff LaBundy 52504e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,blocking-enable")) 52604e49867SJeff LaBundy iqs269->sys_reg.blocking |= BIT(reg); 52704e49867SJeff LaBundy 52804e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,slider0-select")) 52904e49867SJeff LaBundy iqs269->sys_reg.slider_select[0] |= BIT(reg); 53004e49867SJeff LaBundy 53104e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,slider1-select")) 53204e49867SJeff LaBundy iqs269->sys_reg.slider_select[1] |= BIT(reg); 53304e49867SJeff LaBundy 5343689abfcSJeff LaBundy ch_reg = &iqs269->sys_reg.ch_reg[reg]; 53504e49867SJeff LaBundy 53604e49867SJeff LaBundy error = iqs269_parse_mask(ch_node, "azoteq,rx-enable", 53704e49867SJeff LaBundy &ch_reg->rx_enable); 53804e49867SJeff LaBundy if (error) { 53904e49867SJeff LaBundy dev_err(&client->dev, "Invalid channel %u RX enable mask: %d\n", 54004e49867SJeff LaBundy reg, error); 54104e49867SJeff LaBundy return error; 54204e49867SJeff LaBundy } 54304e49867SJeff LaBundy 54404e49867SJeff LaBundy error = iqs269_parse_mask(ch_node, "azoteq,tx-enable", 54504e49867SJeff LaBundy &ch_reg->tx_enable); 54604e49867SJeff LaBundy if (error) { 54704e49867SJeff LaBundy dev_err(&client->dev, "Invalid channel %u TX enable mask: %d\n", 54804e49867SJeff LaBundy reg, error); 54904e49867SJeff LaBundy return error; 55004e49867SJeff LaBundy } 55104e49867SJeff LaBundy 55204e49867SJeff LaBundy engine_a = be16_to_cpu(ch_reg->engine_a); 55304e49867SJeff LaBundy engine_b = be16_to_cpu(ch_reg->engine_b); 55404e49867SJeff LaBundy 55504e49867SJeff LaBundy engine_a |= IQS269_CHx_ENG_A_MEAS_CAP_SIZE; 55604e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,meas-cap-decrease")) 55704e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_MEAS_CAP_SIZE; 55804e49867SJeff LaBundy 55904e49867SJeff LaBundy engine_a |= IQS269_CHx_ENG_A_RX_GND_INACTIVE; 56004e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,rx-float-inactive")) 56104e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_RX_GND_INACTIVE; 56204e49867SJeff LaBundy 56304e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_LOCAL_CAP_SIZE; 56404e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE; 56504e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,local-cap-size", &val)) { 56604e49867SJeff LaBundy switch (val) { 56704e49867SJeff LaBundy case IQS269_LOCAL_CAP_SIZE_0: 56804e49867SJeff LaBundy break; 56904e49867SJeff LaBundy 57004e49867SJeff LaBundy case IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5: 57104e49867SJeff LaBundy engine_a |= IQS269_CHx_ENG_A_LOCAL_CAP_SIZE; 5726f49c4f5SGustavo A. R. Silva fallthrough; 57304e49867SJeff LaBundy 57404e49867SJeff LaBundy case IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY: 57504e49867SJeff LaBundy engine_b |= IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE; 57604e49867SJeff LaBundy break; 57704e49867SJeff LaBundy 57804e49867SJeff LaBundy default: 57904e49867SJeff LaBundy dev_err(&client->dev, 58004e49867SJeff LaBundy "Invalid channel %u local cap. size: %u\n", reg, 58104e49867SJeff LaBundy val); 58204e49867SJeff LaBundy return -EINVAL; 58304e49867SJeff LaBundy } 58404e49867SJeff LaBundy } 58504e49867SJeff LaBundy 58604e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_INV_LOGIC; 58704e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,invert-enable")) 58804e49867SJeff LaBundy engine_a |= IQS269_CHx_ENG_A_INV_LOGIC; 58904e49867SJeff LaBundy 59004e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,proj-bias", &val)) { 59104e49867SJeff LaBundy if (val > IQS269_CHx_ENG_A_PROJ_BIAS_MAX) { 59204e49867SJeff LaBundy dev_err(&client->dev, 59304e49867SJeff LaBundy "Invalid channel %u bias current: %u\n", reg, 59404e49867SJeff LaBundy val); 59504e49867SJeff LaBundy return -EINVAL; 59604e49867SJeff LaBundy } 59704e49867SJeff LaBundy 59804e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_PROJ_BIAS_MASK; 59904e49867SJeff LaBundy engine_a |= (val << IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT); 60004e49867SJeff LaBundy } 60104e49867SJeff LaBundy 60204e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,sense-mode", &val)) { 60304e49867SJeff LaBundy if (val > IQS269_CHx_ENG_A_SENSE_MODE_MAX) { 60404e49867SJeff LaBundy dev_err(&client->dev, 60504e49867SJeff LaBundy "Invalid channel %u sensing mode: %u\n", reg, 60604e49867SJeff LaBundy val); 60704e49867SJeff LaBundy return -EINVAL; 60804e49867SJeff LaBundy } 60904e49867SJeff LaBundy 61004e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_SENSE_MODE_MASK; 61104e49867SJeff LaBundy engine_a |= val; 61204e49867SJeff LaBundy } 61304e49867SJeff LaBundy 61404e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,sense-freq", &val)) { 61504e49867SJeff LaBundy if (val > IQS269_CHx_ENG_B_SENSE_FREQ_MAX) { 61604e49867SJeff LaBundy dev_err(&client->dev, 61704e49867SJeff LaBundy "Invalid channel %u sensing frequency: %u\n", 61804e49867SJeff LaBundy reg, val); 61904e49867SJeff LaBundy return -EINVAL; 62004e49867SJeff LaBundy } 62104e49867SJeff LaBundy 62204e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_SENSE_FREQ_MASK; 62304e49867SJeff LaBundy engine_b |= (val << IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT); 62404e49867SJeff LaBundy } 62504e49867SJeff LaBundy 62604e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_STATIC_ENABLE; 62704e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,static-enable")) 62804e49867SJeff LaBundy engine_b |= IQS269_CHx_ENG_B_STATIC_ENABLE; 62904e49867SJeff LaBundy 63004e49867SJeff LaBundy ch_reg->engine_a = cpu_to_be16(engine_a); 63104e49867SJeff LaBundy ch_reg->engine_b = cpu_to_be16(engine_b); 63204e49867SJeff LaBundy 63304e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,ati-mode", &val)) { 63404e49867SJeff LaBundy error = iqs269_ati_mode_set(iqs269, reg, val); 63504e49867SJeff LaBundy if (error) { 63604e49867SJeff LaBundy dev_err(&client->dev, 63704e49867SJeff LaBundy "Invalid channel %u ATI mode: %u\n", reg, val); 63804e49867SJeff LaBundy return error; 63904e49867SJeff LaBundy } 64004e49867SJeff LaBundy } 64104e49867SJeff LaBundy 64204e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,ati-base", &val)) { 64304e49867SJeff LaBundy error = iqs269_ati_base_set(iqs269, reg, val); 64404e49867SJeff LaBundy if (error) { 64504e49867SJeff LaBundy dev_err(&client->dev, 64604e49867SJeff LaBundy "Invalid channel %u ATI base: %u\n", reg, val); 64704e49867SJeff LaBundy return error; 64804e49867SJeff LaBundy } 64904e49867SJeff LaBundy } 65004e49867SJeff LaBundy 65104e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,ati-target", &val)) { 65204e49867SJeff LaBundy error = iqs269_ati_target_set(iqs269, reg, val); 65304e49867SJeff LaBundy if (error) { 65404e49867SJeff LaBundy dev_err(&client->dev, 65504e49867SJeff LaBundy "Invalid channel %u ATI target: %u\n", reg, 65604e49867SJeff LaBundy val); 65704e49867SJeff LaBundy return error; 65804e49867SJeff LaBundy } 65904e49867SJeff LaBundy } 66004e49867SJeff LaBundy 66104e49867SJeff LaBundy error = iqs269_parse_mask(ch_node, "azoteq,assoc-select", 66204e49867SJeff LaBundy &ch_reg->assoc_select); 66304e49867SJeff LaBundy if (error) { 66404e49867SJeff LaBundy dev_err(&client->dev, "Invalid channel %u association: %d\n", 66504e49867SJeff LaBundy reg, error); 66604e49867SJeff LaBundy return error; 66704e49867SJeff LaBundy } 66804e49867SJeff LaBundy 66904e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,assoc-weight", &val)) { 67004e49867SJeff LaBundy if (val > IQS269_CHx_WEIGHT_MAX) { 67104e49867SJeff LaBundy dev_err(&client->dev, 67204e49867SJeff LaBundy "Invalid channel %u associated weight: %u\n", 67304e49867SJeff LaBundy reg, val); 67404e49867SJeff LaBundy return -EINVAL; 67504e49867SJeff LaBundy } 67604e49867SJeff LaBundy 67704e49867SJeff LaBundy ch_reg->assoc_weight = val; 67804e49867SJeff LaBundy } 67904e49867SJeff LaBundy 68004e49867SJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { 68104e49867SJeff LaBundy ev_node = fwnode_get_named_child_node(ch_node, 68204e49867SJeff LaBundy iqs269_events[i].name); 68304e49867SJeff LaBundy if (!ev_node) 68404e49867SJeff LaBundy continue; 68504e49867SJeff LaBundy 68604e49867SJeff LaBundy if (!fwnode_property_read_u32(ev_node, "azoteq,thresh", &val)) { 68704e49867SJeff LaBundy if (val > IQS269_CHx_THRESH_MAX) { 68804e49867SJeff LaBundy dev_err(&client->dev, 68904e49867SJeff LaBundy "Invalid channel %u threshold: %u\n", 69004e49867SJeff LaBundy reg, val); 69159bc9cb3SJeff LaBundy fwnode_handle_put(ev_node); 69204e49867SJeff LaBundy return -EINVAL; 69304e49867SJeff LaBundy } 69404e49867SJeff LaBundy 69504e49867SJeff LaBundy ch_reg->thresh[iqs269_events[i].th_offs] = val; 69604e49867SJeff LaBundy } 69704e49867SJeff LaBundy 69804e49867SJeff LaBundy if (!fwnode_property_read_u32(ev_node, "azoteq,hyst", &val)) { 69904e49867SJeff LaBundy u8 *hyst = &ch_reg->hyst; 70004e49867SJeff LaBundy 70104e49867SJeff LaBundy if (val > IQS269_CHx_HYST_MAX) { 70204e49867SJeff LaBundy dev_err(&client->dev, 70304e49867SJeff LaBundy "Invalid channel %u hysteresis: %u\n", 70404e49867SJeff LaBundy reg, val); 70559bc9cb3SJeff LaBundy fwnode_handle_put(ev_node); 70604e49867SJeff LaBundy return -EINVAL; 70704e49867SJeff LaBundy } 70804e49867SJeff LaBundy 70904e49867SJeff LaBundy if (i == IQS269_EVENT_DEEP_DN || 71004e49867SJeff LaBundy i == IQS269_EVENT_DEEP_UP) { 71104e49867SJeff LaBundy *hyst &= ~IQS269_CHx_HYST_DEEP_MASK; 71204e49867SJeff LaBundy *hyst |= (val << IQS269_CHx_HYST_DEEP_SHIFT); 71304e49867SJeff LaBundy } else if (i == IQS269_EVENT_TOUCH_DN || 71404e49867SJeff LaBundy i == IQS269_EVENT_TOUCH_UP) { 71504e49867SJeff LaBundy *hyst &= ~IQS269_CHx_HYST_TOUCH_MASK; 71604e49867SJeff LaBundy *hyst |= val; 71704e49867SJeff LaBundy } 71804e49867SJeff LaBundy } 71904e49867SJeff LaBundy 72059bc9cb3SJeff LaBundy error = fwnode_property_read_u32(ev_node, "linux,code", &val); 72159bc9cb3SJeff LaBundy fwnode_handle_put(ev_node); 72259bc9cb3SJeff LaBundy if (error == -EINVAL) { 72304e49867SJeff LaBundy continue; 72459bc9cb3SJeff LaBundy } else if (error) { 72559bc9cb3SJeff LaBundy dev_err(&client->dev, 72659bc9cb3SJeff LaBundy "Failed to read channel %u code: %d\n", reg, 72759bc9cb3SJeff LaBundy error); 72859bc9cb3SJeff LaBundy return error; 72959bc9cb3SJeff LaBundy } 73004e49867SJeff LaBundy 73104e49867SJeff LaBundy switch (reg) { 73204e49867SJeff LaBundy case IQS269_CHx_HALL_ACTIVE: 73304e49867SJeff LaBundy if (iqs269->hall_enable) { 73404e49867SJeff LaBundy iqs269->switches[i].code = val; 73504e49867SJeff LaBundy iqs269->switches[i].enabled = true; 73604e49867SJeff LaBundy } 7376f49c4f5SGustavo A. R. Silva fallthrough; 73804e49867SJeff LaBundy 73904e49867SJeff LaBundy case IQS269_CHx_HALL_INACTIVE: 74004e49867SJeff LaBundy if (iqs269->hall_enable) 74104e49867SJeff LaBundy break; 7426f49c4f5SGustavo A. R. Silva fallthrough; 74304e49867SJeff LaBundy 74404e49867SJeff LaBundy default: 74504e49867SJeff LaBundy iqs269->keycode[i * IQS269_NUM_CH + reg] = val; 74604e49867SJeff LaBundy } 74704e49867SJeff LaBundy 74804e49867SJeff LaBundy iqs269->sys_reg.event_mask &= ~iqs269_events[i].mask; 74904e49867SJeff LaBundy } 75004e49867SJeff LaBundy 75104e49867SJeff LaBundy return 0; 75204e49867SJeff LaBundy } 75304e49867SJeff LaBundy 75404e49867SJeff LaBundy static int iqs269_parse_prop(struct iqs269_private *iqs269) 75504e49867SJeff LaBundy { 75604e49867SJeff LaBundy struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg; 75704e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 75804e49867SJeff LaBundy struct fwnode_handle *ch_node; 75904e49867SJeff LaBundy u16 general, misc_a, misc_b; 76004e49867SJeff LaBundy unsigned int val; 76104e49867SJeff LaBundy int error; 76204e49867SJeff LaBundy 76304e49867SJeff LaBundy iqs269->hall_enable = device_property_present(&client->dev, 76404e49867SJeff LaBundy "azoteq,hall-enable"); 76504e49867SJeff LaBundy 76604e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg, 76704e49867SJeff LaBundy sizeof(*sys_reg)); 76804e49867SJeff LaBundy if (error) 76904e49867SJeff LaBundy return error; 77004e49867SJeff LaBundy 77104e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-lta", 77204e49867SJeff LaBundy &val)) { 77304e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 77404e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 77504e49867SJeff LaBundy val); 77604e49867SJeff LaBundy return -EINVAL; 77704e49867SJeff LaBundy } 77804e49867SJeff LaBundy 77904e49867SJeff LaBundy sys_reg->filter &= ~IQS269_FILT_STR_LP_LTA_MASK; 78004e49867SJeff LaBundy sys_reg->filter |= (val << IQS269_FILT_STR_LP_LTA_SHIFT); 78104e49867SJeff LaBundy } 78204e49867SJeff LaBundy 78304e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-cnt", 78404e49867SJeff LaBundy &val)) { 78504e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 78604e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 78704e49867SJeff LaBundy val); 78804e49867SJeff LaBundy return -EINVAL; 78904e49867SJeff LaBundy } 79004e49867SJeff LaBundy 79104e49867SJeff LaBundy sys_reg->filter &= ~IQS269_FILT_STR_LP_CNT_MASK; 79204e49867SJeff LaBundy sys_reg->filter |= (val << IQS269_FILT_STR_LP_CNT_SHIFT); 79304e49867SJeff LaBundy } 79404e49867SJeff LaBundy 79504e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-lta", 79604e49867SJeff LaBundy &val)) { 79704e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 79804e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 79904e49867SJeff LaBundy val); 80004e49867SJeff LaBundy return -EINVAL; 80104e49867SJeff LaBundy } 80204e49867SJeff LaBundy 80304e49867SJeff LaBundy sys_reg->filter &= ~IQS269_FILT_STR_NP_LTA_MASK; 80404e49867SJeff LaBundy sys_reg->filter |= (val << IQS269_FILT_STR_NP_LTA_SHIFT); 80504e49867SJeff LaBundy } 80604e49867SJeff LaBundy 80704e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-cnt", 80804e49867SJeff LaBundy &val)) { 80904e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 81004e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 81104e49867SJeff LaBundy val); 81204e49867SJeff LaBundy return -EINVAL; 81304e49867SJeff LaBundy } 81404e49867SJeff LaBundy 81504e49867SJeff LaBundy sys_reg->filter &= ~IQS269_FILT_STR_NP_CNT_MASK; 81604e49867SJeff LaBundy sys_reg->filter |= val; 81704e49867SJeff LaBundy } 81804e49867SJeff LaBundy 81904e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,rate-np-ms", 82004e49867SJeff LaBundy &val)) { 82104e49867SJeff LaBundy if (val > IQS269_RATE_NP_MS_MAX) { 82204e49867SJeff LaBundy dev_err(&client->dev, "Invalid report rate: %u\n", val); 82304e49867SJeff LaBundy return -EINVAL; 82404e49867SJeff LaBundy } 82504e49867SJeff LaBundy 82604e49867SJeff LaBundy sys_reg->rate_np = val; 82704e49867SJeff LaBundy } 82804e49867SJeff LaBundy 82904e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,rate-lp-ms", 83004e49867SJeff LaBundy &val)) { 83104e49867SJeff LaBundy if (val > IQS269_RATE_LP_MS_MAX) { 83204e49867SJeff LaBundy dev_err(&client->dev, "Invalid report rate: %u\n", val); 83304e49867SJeff LaBundy return -EINVAL; 83404e49867SJeff LaBundy } 83504e49867SJeff LaBundy 83604e49867SJeff LaBundy sys_reg->rate_lp = val; 83704e49867SJeff LaBundy } 83804e49867SJeff LaBundy 83904e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,rate-ulp-ms", 84004e49867SJeff LaBundy &val)) { 84104e49867SJeff LaBundy if (val > IQS269_RATE_ULP_MS_MAX) { 84204e49867SJeff LaBundy dev_err(&client->dev, "Invalid report rate: %u\n", val); 84304e49867SJeff LaBundy return -EINVAL; 84404e49867SJeff LaBundy } 84504e49867SJeff LaBundy 84604e49867SJeff LaBundy sys_reg->rate_ulp = val / 16; 84704e49867SJeff LaBundy } 84804e49867SJeff LaBundy 84904e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,timeout-pwr-ms", 85004e49867SJeff LaBundy &val)) { 85104e49867SJeff LaBundy if (val > IQS269_TIMEOUT_PWR_MS_MAX) { 85204e49867SJeff LaBundy dev_err(&client->dev, "Invalid timeout: %u\n", val); 85304e49867SJeff LaBundy return -EINVAL; 85404e49867SJeff LaBundy } 85504e49867SJeff LaBundy 85604e49867SJeff LaBundy sys_reg->timeout_pwr = val / 512; 85704e49867SJeff LaBundy } 85804e49867SJeff LaBundy 85904e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,timeout-lta-ms", 86004e49867SJeff LaBundy &val)) { 86104e49867SJeff LaBundy if (val > IQS269_TIMEOUT_LTA_MS_MAX) { 86204e49867SJeff LaBundy dev_err(&client->dev, "Invalid timeout: %u\n", val); 86304e49867SJeff LaBundy return -EINVAL; 86404e49867SJeff LaBundy } 86504e49867SJeff LaBundy 86604e49867SJeff LaBundy sys_reg->timeout_lta = val / 512; 86704e49867SJeff LaBundy } 86804e49867SJeff LaBundy 86904e49867SJeff LaBundy misc_a = be16_to_cpu(sys_reg->misc_a); 87004e49867SJeff LaBundy misc_b = be16_to_cpu(sys_reg->misc_b); 87104e49867SJeff LaBundy 87204e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_ATI_BAND_DISABLE; 87304e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,ati-band-disable")) 87404e49867SJeff LaBundy misc_a |= IQS269_MISC_A_ATI_BAND_DISABLE; 87504e49867SJeff LaBundy 87604e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_ATI_LP_ONLY; 87704e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,ati-lp-only")) 87804e49867SJeff LaBundy misc_a |= IQS269_MISC_A_ATI_LP_ONLY; 87904e49867SJeff LaBundy 88004e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_ATI_BAND_TIGHTEN; 88104e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,ati-band-tighten")) 88204e49867SJeff LaBundy misc_a |= IQS269_MISC_A_ATI_BAND_TIGHTEN; 88304e49867SJeff LaBundy 88404e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_FILT_DISABLE; 88504e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,filt-disable")) 88604e49867SJeff LaBundy misc_a |= IQS269_MISC_A_FILT_DISABLE; 88704e49867SJeff LaBundy 88804e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,gpio3-select", 88904e49867SJeff LaBundy &val)) { 89004e49867SJeff LaBundy if (val >= IQS269_NUM_CH) { 89104e49867SJeff LaBundy dev_err(&client->dev, "Invalid GPIO3 selection: %u\n", 89204e49867SJeff LaBundy val); 89304e49867SJeff LaBundy return -EINVAL; 89404e49867SJeff LaBundy } 89504e49867SJeff LaBundy 89604e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_GPIO3_SELECT_MASK; 89704e49867SJeff LaBundy misc_a |= (val << IQS269_MISC_A_GPIO3_SELECT_SHIFT); 89804e49867SJeff LaBundy } 89904e49867SJeff LaBundy 90004e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_DUAL_DIR; 90104e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,dual-direction")) 90204e49867SJeff LaBundy misc_a |= IQS269_MISC_A_DUAL_DIR; 90304e49867SJeff LaBundy 90404e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,tx-freq", &val)) { 90504e49867SJeff LaBundy if (val > IQS269_MISC_A_TX_FREQ_MAX) { 90604e49867SJeff LaBundy dev_err(&client->dev, 90704e49867SJeff LaBundy "Invalid excitation frequency: %u\n", val); 90804e49867SJeff LaBundy return -EINVAL; 90904e49867SJeff LaBundy } 91004e49867SJeff LaBundy 91104e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_TX_FREQ_MASK; 91204e49867SJeff LaBundy misc_a |= (val << IQS269_MISC_A_TX_FREQ_SHIFT); 91304e49867SJeff LaBundy } 91404e49867SJeff LaBundy 91504e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_GLOBAL_CAP_SIZE; 91604e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,global-cap-increase")) 91704e49867SJeff LaBundy misc_a |= IQS269_MISC_A_GLOBAL_CAP_SIZE; 91804e49867SJeff LaBundy 91904e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,reseed-select", 92004e49867SJeff LaBundy &val)) { 92104e49867SJeff LaBundy if (val > IQS269_MISC_B_RESEED_UI_SEL_MAX) { 92204e49867SJeff LaBundy dev_err(&client->dev, "Invalid reseed selection: %u\n", 92304e49867SJeff LaBundy val); 92404e49867SJeff LaBundy return -EINVAL; 92504e49867SJeff LaBundy } 92604e49867SJeff LaBundy 92704e49867SJeff LaBundy misc_b &= ~IQS269_MISC_B_RESEED_UI_SEL_MASK; 92804e49867SJeff LaBundy misc_b |= (val << IQS269_MISC_B_RESEED_UI_SEL_SHIFT); 92904e49867SJeff LaBundy } 93004e49867SJeff LaBundy 93104e49867SJeff LaBundy misc_b &= ~IQS269_MISC_B_TRACKING_UI_ENABLE; 93204e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,tracking-enable")) 93304e49867SJeff LaBundy misc_b |= IQS269_MISC_B_TRACKING_UI_ENABLE; 93404e49867SJeff LaBundy 93504e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-slider", 93604e49867SJeff LaBundy &val)) { 93704e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 93804e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 93904e49867SJeff LaBundy val); 94004e49867SJeff LaBundy return -EINVAL; 94104e49867SJeff LaBundy } 94204e49867SJeff LaBundy 94304e49867SJeff LaBundy misc_b &= ~IQS269_MISC_B_FILT_STR_SLIDER; 94404e49867SJeff LaBundy misc_b |= val; 94504e49867SJeff LaBundy } 94604e49867SJeff LaBundy 94704e49867SJeff LaBundy sys_reg->misc_a = cpu_to_be16(misc_a); 94804e49867SJeff LaBundy sys_reg->misc_b = cpu_to_be16(misc_b); 94904e49867SJeff LaBundy 95004e49867SJeff LaBundy sys_reg->active = 0; 95104e49867SJeff LaBundy sys_reg->reseed = 0; 95204e49867SJeff LaBundy 95304e49867SJeff LaBundy sys_reg->blocking = 0; 95404e49867SJeff LaBundy 95504e49867SJeff LaBundy sys_reg->slider_select[0] = 0; 95604e49867SJeff LaBundy sys_reg->slider_select[1] = 0; 95704e49867SJeff LaBundy 95804e49867SJeff LaBundy sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS); 95904e49867SJeff LaBundy 96004e49867SJeff LaBundy device_for_each_child_node(&client->dev, ch_node) { 96104e49867SJeff LaBundy error = iqs269_parse_chan(iqs269, ch_node); 96204e49867SJeff LaBundy if (error) { 96304e49867SJeff LaBundy fwnode_handle_put(ch_node); 96404e49867SJeff LaBundy return error; 96504e49867SJeff LaBundy } 96604e49867SJeff LaBundy } 96704e49867SJeff LaBundy 96804e49867SJeff LaBundy /* 96904e49867SJeff LaBundy * Volunteer all active channels to participate in ATI when REDO-ATI is 97004e49867SJeff LaBundy * manually triggered. 97104e49867SJeff LaBundy */ 97204e49867SJeff LaBundy sys_reg->redo_ati = sys_reg->active; 97304e49867SJeff LaBundy 97404e49867SJeff LaBundy general = be16_to_cpu(sys_reg->general); 97504e49867SJeff LaBundy 97604e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,clk-div")) { 97704e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_CLK_DIV; 97804e49867SJeff LaBundy iqs269->delay_mult = 4; 97904e49867SJeff LaBundy } else { 98004e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_CLK_DIV; 98104e49867SJeff LaBundy iqs269->delay_mult = 1; 98204e49867SJeff LaBundy } 98304e49867SJeff LaBundy 98404e49867SJeff LaBundy /* 98504e49867SJeff LaBundy * Configure the device to automatically switch between normal and low- 98604e49867SJeff LaBundy * power modes as a function of sensing activity. Ultra-low-power mode, 98704e49867SJeff LaBundy * if enabled, is reserved for suspend. 98804e49867SJeff LaBundy */ 98904e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_ULP_AUTO; 99004e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_DIS_AUTO; 99104e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_PWR_MODE_MASK; 99204e49867SJeff LaBundy 993*18ab69c8SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode", 994*18ab69c8SJeff LaBundy &val)) { 995*18ab69c8SJeff LaBundy if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) { 996*18ab69c8SJeff LaBundy dev_err(&client->dev, "Invalid suspend mode: %u\n", 997*18ab69c8SJeff LaBundy val); 998*18ab69c8SJeff LaBundy return -EINVAL; 999*18ab69c8SJeff LaBundy } 1000*18ab69c8SJeff LaBundy 1001*18ab69c8SJeff LaBundy general |= (val << IQS269_SYS_SETTINGS_PWR_MODE_SHIFT); 1002*18ab69c8SJeff LaBundy } 1003*18ab69c8SJeff LaBundy 100404e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,ulp-update", 100504e49867SJeff LaBundy &val)) { 100604e49867SJeff LaBundy if (val > IQS269_SYS_SETTINGS_ULP_UPDATE_MAX) { 100704e49867SJeff LaBundy dev_err(&client->dev, "Invalid update rate: %u\n", val); 100804e49867SJeff LaBundy return -EINVAL; 100904e49867SJeff LaBundy } 101004e49867SJeff LaBundy 101104e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_ULP_UPDATE_MASK; 101204e49867SJeff LaBundy general |= (val << IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT); 101304e49867SJeff LaBundy } 101404e49867SJeff LaBundy 101504e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_RESEED_OFFSET; 101604e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,reseed-offset")) 101704e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_RESEED_OFFSET; 101804e49867SJeff LaBundy 101904e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_EVENT_MODE; 102004e49867SJeff LaBundy 102104e49867SJeff LaBundy /* 102204e49867SJeff LaBundy * As per the datasheet, enable streaming during normal-power mode if 102304e49867SJeff LaBundy * either slider is in use. In that case, the device returns to event 102404e49867SJeff LaBundy * mode during low-power mode. 102504e49867SJeff LaBundy */ 102604e49867SJeff LaBundy if (sys_reg->slider_select[0] || sys_reg->slider_select[1]) 102704e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_EVENT_MODE_LP; 102804e49867SJeff LaBundy 102904e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_REDO_ATI; 103004e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_ACK_RESET; 103104e49867SJeff LaBundy 103204e49867SJeff LaBundy sys_reg->general = cpu_to_be16(general); 103304e49867SJeff LaBundy 103404e49867SJeff LaBundy return 0; 103504e49867SJeff LaBundy } 103604e49867SJeff LaBundy 103704e49867SJeff LaBundy static int iqs269_dev_init(struct iqs269_private *iqs269) 103804e49867SJeff LaBundy { 103904e49867SJeff LaBundy unsigned int val; 10403689abfcSJeff LaBundy int error; 104104e49867SJeff LaBundy 104204e49867SJeff LaBundy mutex_lock(&iqs269->lock); 104304e49867SJeff LaBundy 104404e49867SJeff LaBundy error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI, 104504e49867SJeff LaBundy IQS269_HALL_UI_ENABLE, 104604e49867SJeff LaBundy iqs269->hall_enable ? ~0 : 0); 104704e49867SJeff LaBundy if (error) 104804e49867SJeff LaBundy goto err_mutex; 104904e49867SJeff LaBundy 10503689abfcSJeff LaBundy error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS, 10513689abfcSJeff LaBundy &iqs269->sys_reg, sizeof(iqs269->sys_reg)); 105204e49867SJeff LaBundy if (error) 105304e49867SJeff LaBundy goto err_mutex; 105404e49867SJeff LaBundy 105504e49867SJeff LaBundy error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val, 105604e49867SJeff LaBundy !(val & IQS269_SYS_FLAGS_IN_ATI), 105704e49867SJeff LaBundy IQS269_ATI_POLL_SLEEP_US, 105804e49867SJeff LaBundy IQS269_ATI_POLL_TIMEOUT_US); 105904e49867SJeff LaBundy if (error) 106004e49867SJeff LaBundy goto err_mutex; 106104e49867SJeff LaBundy 106204e49867SJeff LaBundy msleep(IQS269_ATI_STABLE_DELAY_MS); 106304e49867SJeff LaBundy iqs269->ati_current = true; 106404e49867SJeff LaBundy 106504e49867SJeff LaBundy err_mutex: 106604e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 106704e49867SJeff LaBundy 106804e49867SJeff LaBundy return error; 106904e49867SJeff LaBundy } 107004e49867SJeff LaBundy 107104e49867SJeff LaBundy static int iqs269_input_init(struct iqs269_private *iqs269) 107204e49867SJeff LaBundy { 107304e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 107404e49867SJeff LaBundy struct iqs269_flags flags; 107504e49867SJeff LaBundy unsigned int sw_code, keycode; 107604e49867SJeff LaBundy int error, i, j; 107704e49867SJeff LaBundy u8 dir_mask, state; 107804e49867SJeff LaBundy 107904e49867SJeff LaBundy iqs269->keypad = devm_input_allocate_device(&client->dev); 108004e49867SJeff LaBundy if (!iqs269->keypad) 108104e49867SJeff LaBundy return -ENOMEM; 108204e49867SJeff LaBundy 108304e49867SJeff LaBundy iqs269->keypad->keycodemax = ARRAY_SIZE(iqs269->keycode); 108404e49867SJeff LaBundy iqs269->keypad->keycode = iqs269->keycode; 108504e49867SJeff LaBundy iqs269->keypad->keycodesize = sizeof(*iqs269->keycode); 108604e49867SJeff LaBundy 108704e49867SJeff LaBundy iqs269->keypad->name = "iqs269a_keypad"; 108804e49867SJeff LaBundy iqs269->keypad->id.bustype = BUS_I2C; 108904e49867SJeff LaBundy 109004e49867SJeff LaBundy if (iqs269->hall_enable) { 109104e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS, 109204e49867SJeff LaBundy &flags, sizeof(flags)); 109304e49867SJeff LaBundy if (error) { 109404e49867SJeff LaBundy dev_err(&client->dev, 109504e49867SJeff LaBundy "Failed to read initial status: %d\n", error); 109604e49867SJeff LaBundy return error; 109704e49867SJeff LaBundy } 109804e49867SJeff LaBundy } 109904e49867SJeff LaBundy 110004e49867SJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { 110104e49867SJeff LaBundy dir_mask = flags.states[IQS269_ST_OFFS_DIR]; 110204e49867SJeff LaBundy if (!iqs269_events[i].dir_up) 110304e49867SJeff LaBundy dir_mask = ~dir_mask; 110404e49867SJeff LaBundy 110504e49867SJeff LaBundy state = flags.states[iqs269_events[i].st_offs] & dir_mask; 110604e49867SJeff LaBundy 110704e49867SJeff LaBundy sw_code = iqs269->switches[i].code; 110804e49867SJeff LaBundy 110904e49867SJeff LaBundy for (j = 0; j < IQS269_NUM_CH; j++) { 111004e49867SJeff LaBundy keycode = iqs269->keycode[i * IQS269_NUM_CH + j]; 111104e49867SJeff LaBundy 111204e49867SJeff LaBundy /* 111304e49867SJeff LaBundy * Hall-effect sensing repurposes a pair of dedicated 111404e49867SJeff LaBundy * channels, only one of which reports events. 111504e49867SJeff LaBundy */ 111604e49867SJeff LaBundy switch (j) { 111704e49867SJeff LaBundy case IQS269_CHx_HALL_ACTIVE: 111804e49867SJeff LaBundy if (iqs269->hall_enable && 111904e49867SJeff LaBundy iqs269->switches[i].enabled) { 112004e49867SJeff LaBundy input_set_capability(iqs269->keypad, 112104e49867SJeff LaBundy EV_SW, sw_code); 112204e49867SJeff LaBundy input_report_switch(iqs269->keypad, 112304e49867SJeff LaBundy sw_code, 112404e49867SJeff LaBundy state & BIT(j)); 112504e49867SJeff LaBundy } 11266f49c4f5SGustavo A. R. Silva fallthrough; 112704e49867SJeff LaBundy 112804e49867SJeff LaBundy case IQS269_CHx_HALL_INACTIVE: 112904e49867SJeff LaBundy if (iqs269->hall_enable) 113004e49867SJeff LaBundy continue; 11316f49c4f5SGustavo A. R. Silva fallthrough; 113204e49867SJeff LaBundy 113304e49867SJeff LaBundy default: 113404e49867SJeff LaBundy if (keycode != KEY_RESERVED) 113504e49867SJeff LaBundy input_set_capability(iqs269->keypad, 113604e49867SJeff LaBundy EV_KEY, keycode); 113704e49867SJeff LaBundy } 113804e49867SJeff LaBundy } 113904e49867SJeff LaBundy } 114004e49867SJeff LaBundy 114104e49867SJeff LaBundy input_sync(iqs269->keypad); 114204e49867SJeff LaBundy 114304e49867SJeff LaBundy error = input_register_device(iqs269->keypad); 114404e49867SJeff LaBundy if (error) { 114504e49867SJeff LaBundy dev_err(&client->dev, "Failed to register keypad: %d\n", error); 114604e49867SJeff LaBundy return error; 114704e49867SJeff LaBundy } 114804e49867SJeff LaBundy 114904e49867SJeff LaBundy for (i = 0; i < IQS269_NUM_SL; i++) { 115004e49867SJeff LaBundy if (!iqs269->sys_reg.slider_select[i]) 115104e49867SJeff LaBundy continue; 115204e49867SJeff LaBundy 115304e49867SJeff LaBundy iqs269->slider[i] = devm_input_allocate_device(&client->dev); 115404e49867SJeff LaBundy if (!iqs269->slider[i]) 115504e49867SJeff LaBundy return -ENOMEM; 115604e49867SJeff LaBundy 115704e49867SJeff LaBundy iqs269->slider[i]->name = i ? "iqs269a_slider_1" 115804e49867SJeff LaBundy : "iqs269a_slider_0"; 115904e49867SJeff LaBundy iqs269->slider[i]->id.bustype = BUS_I2C; 116004e49867SJeff LaBundy 116104e49867SJeff LaBundy input_set_capability(iqs269->slider[i], EV_KEY, BTN_TOUCH); 116204e49867SJeff LaBundy input_set_abs_params(iqs269->slider[i], ABS_X, 0, 255, 0, 0); 116304e49867SJeff LaBundy 116404e49867SJeff LaBundy error = input_register_device(iqs269->slider[i]); 116504e49867SJeff LaBundy if (error) { 116604e49867SJeff LaBundy dev_err(&client->dev, 116704e49867SJeff LaBundy "Failed to register slider %d: %d\n", i, error); 116804e49867SJeff LaBundy return error; 116904e49867SJeff LaBundy } 117004e49867SJeff LaBundy } 117104e49867SJeff LaBundy 117204e49867SJeff LaBundy return 0; 117304e49867SJeff LaBundy } 117404e49867SJeff LaBundy 117504e49867SJeff LaBundy static int iqs269_report(struct iqs269_private *iqs269) 117604e49867SJeff LaBundy { 117704e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 117804e49867SJeff LaBundy struct iqs269_flags flags; 117904e49867SJeff LaBundy unsigned int sw_code, keycode; 118004e49867SJeff LaBundy int error, i, j; 118104e49867SJeff LaBundy u8 slider_x[IQS269_NUM_SL]; 118204e49867SJeff LaBundy u8 dir_mask, state; 118304e49867SJeff LaBundy 118404e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS, &flags, 118504e49867SJeff LaBundy sizeof(flags)); 118604e49867SJeff LaBundy if (error) { 118704e49867SJeff LaBundy dev_err(&client->dev, "Failed to read device status: %d\n", 118804e49867SJeff LaBundy error); 118904e49867SJeff LaBundy return error; 119004e49867SJeff LaBundy } 119104e49867SJeff LaBundy 119204e49867SJeff LaBundy /* 119304e49867SJeff LaBundy * The device resets itself if its own watchdog bites, which can happen 119404e49867SJeff LaBundy * in the event of an I2C communication error. In this case, the device 119504e49867SJeff LaBundy * asserts a SHOW_RESET interrupt and all registers must be restored. 119604e49867SJeff LaBundy */ 119704e49867SJeff LaBundy if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_SHOW_RESET) { 119804e49867SJeff LaBundy dev_err(&client->dev, "Unexpected device reset\n"); 119904e49867SJeff LaBundy 120004e49867SJeff LaBundy error = iqs269_dev_init(iqs269); 120104e49867SJeff LaBundy if (error) 120204e49867SJeff LaBundy dev_err(&client->dev, 120304e49867SJeff LaBundy "Failed to re-initialize device: %d\n", error); 120404e49867SJeff LaBundy 120504e49867SJeff LaBundy return error; 120604e49867SJeff LaBundy } 120704e49867SJeff LaBundy 120804e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X, slider_x, 120904e49867SJeff LaBundy sizeof(slider_x)); 121004e49867SJeff LaBundy if (error) { 121104e49867SJeff LaBundy dev_err(&client->dev, "Failed to read slider position: %d\n", 121204e49867SJeff LaBundy error); 121304e49867SJeff LaBundy return error; 121404e49867SJeff LaBundy } 121504e49867SJeff LaBundy 121604e49867SJeff LaBundy for (i = 0; i < IQS269_NUM_SL; i++) { 121704e49867SJeff LaBundy if (!iqs269->sys_reg.slider_select[i]) 121804e49867SJeff LaBundy continue; 121904e49867SJeff LaBundy 122004e49867SJeff LaBundy /* 122104e49867SJeff LaBundy * Report BTN_TOUCH if any channel that participates in the 122204e49867SJeff LaBundy * slider is in a state of touch. 122304e49867SJeff LaBundy */ 122404e49867SJeff LaBundy if (flags.states[IQS269_ST_OFFS_TOUCH] & 122504e49867SJeff LaBundy iqs269->sys_reg.slider_select[i]) { 122604e49867SJeff LaBundy input_report_key(iqs269->slider[i], BTN_TOUCH, 1); 122704e49867SJeff LaBundy input_report_abs(iqs269->slider[i], ABS_X, slider_x[i]); 122804e49867SJeff LaBundy } else { 122904e49867SJeff LaBundy input_report_key(iqs269->slider[i], BTN_TOUCH, 0); 123004e49867SJeff LaBundy } 123104e49867SJeff LaBundy 123204e49867SJeff LaBundy input_sync(iqs269->slider[i]); 123304e49867SJeff LaBundy } 123404e49867SJeff LaBundy 123504e49867SJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { 123604e49867SJeff LaBundy dir_mask = flags.states[IQS269_ST_OFFS_DIR]; 123704e49867SJeff LaBundy if (!iqs269_events[i].dir_up) 123804e49867SJeff LaBundy dir_mask = ~dir_mask; 123904e49867SJeff LaBundy 124004e49867SJeff LaBundy state = flags.states[iqs269_events[i].st_offs] & dir_mask; 124104e49867SJeff LaBundy 124204e49867SJeff LaBundy sw_code = iqs269->switches[i].code; 124304e49867SJeff LaBundy 124404e49867SJeff LaBundy for (j = 0; j < IQS269_NUM_CH; j++) { 124504e49867SJeff LaBundy keycode = iqs269->keycode[i * IQS269_NUM_CH + j]; 124604e49867SJeff LaBundy 124704e49867SJeff LaBundy switch (j) { 124804e49867SJeff LaBundy case IQS269_CHx_HALL_ACTIVE: 124904e49867SJeff LaBundy if (iqs269->hall_enable && 125004e49867SJeff LaBundy iqs269->switches[i].enabled) 125104e49867SJeff LaBundy input_report_switch(iqs269->keypad, 125204e49867SJeff LaBundy sw_code, 125304e49867SJeff LaBundy state & BIT(j)); 12546f49c4f5SGustavo A. R. Silva fallthrough; 125504e49867SJeff LaBundy 125604e49867SJeff LaBundy case IQS269_CHx_HALL_INACTIVE: 125704e49867SJeff LaBundy if (iqs269->hall_enable) 125804e49867SJeff LaBundy continue; 12596f49c4f5SGustavo A. R. Silva fallthrough; 126004e49867SJeff LaBundy 126104e49867SJeff LaBundy default: 126204e49867SJeff LaBundy input_report_key(iqs269->keypad, keycode, 126304e49867SJeff LaBundy state & BIT(j)); 126404e49867SJeff LaBundy } 126504e49867SJeff LaBundy } 126604e49867SJeff LaBundy } 126704e49867SJeff LaBundy 126804e49867SJeff LaBundy input_sync(iqs269->keypad); 126904e49867SJeff LaBundy 127004e49867SJeff LaBundy return 0; 127104e49867SJeff LaBundy } 127204e49867SJeff LaBundy 127304e49867SJeff LaBundy static irqreturn_t iqs269_irq(int irq, void *context) 127404e49867SJeff LaBundy { 127504e49867SJeff LaBundy struct iqs269_private *iqs269 = context; 127604e49867SJeff LaBundy 127704e49867SJeff LaBundy if (iqs269_report(iqs269)) 127804e49867SJeff LaBundy return IRQ_NONE; 127904e49867SJeff LaBundy 128004e49867SJeff LaBundy /* 128104e49867SJeff LaBundy * The device does not deassert its interrupt (RDY) pin until shortly 128204e49867SJeff LaBundy * after receiving an I2C stop condition; the following delay ensures 128304e49867SJeff LaBundy * the interrupt handler does not return before this time. 128404e49867SJeff LaBundy */ 128504e49867SJeff LaBundy iqs269_irq_wait(); 128604e49867SJeff LaBundy 128704e49867SJeff LaBundy return IRQ_HANDLED; 128804e49867SJeff LaBundy } 128904e49867SJeff LaBundy 129004e49867SJeff LaBundy static ssize_t counts_show(struct device *dev, 129104e49867SJeff LaBundy struct device_attribute *attr, char *buf) 129204e49867SJeff LaBundy { 129304e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 129404e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 129504e49867SJeff LaBundy __le16 counts; 129604e49867SJeff LaBundy int error; 129704e49867SJeff LaBundy 129804e49867SJeff LaBundy if (!iqs269->ati_current || iqs269->hall_enable) 129904e49867SJeff LaBundy return -EPERM; 130004e49867SJeff LaBundy 130104e49867SJeff LaBundy /* 130204e49867SJeff LaBundy * Unsolicited I2C communication prompts the device to assert its RDY 130304e49867SJeff LaBundy * pin, so disable the interrupt line until the operation is finished 130404e49867SJeff LaBundy * and RDY has been deasserted. 130504e49867SJeff LaBundy */ 130604e49867SJeff LaBundy disable_irq(client->irq); 130704e49867SJeff LaBundy 130804e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, 130904e49867SJeff LaBundy IQS269_CHx_COUNTS + iqs269->ch_num * 2, 131004e49867SJeff LaBundy &counts, sizeof(counts)); 131104e49867SJeff LaBundy 131204e49867SJeff LaBundy iqs269_irq_wait(); 131304e49867SJeff LaBundy enable_irq(client->irq); 131404e49867SJeff LaBundy 131504e49867SJeff LaBundy if (error) 131604e49867SJeff LaBundy return error; 131704e49867SJeff LaBundy 131804e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", le16_to_cpu(counts)); 131904e49867SJeff LaBundy } 132004e49867SJeff LaBundy 132104e49867SJeff LaBundy static ssize_t hall_bin_show(struct device *dev, 132204e49867SJeff LaBundy struct device_attribute *attr, char *buf) 132304e49867SJeff LaBundy { 132404e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 13253689abfcSJeff LaBundy struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 132604e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 132704e49867SJeff LaBundy unsigned int val; 132804e49867SJeff LaBundy int error; 132904e49867SJeff LaBundy 133004e49867SJeff LaBundy disable_irq(client->irq); 133104e49867SJeff LaBundy 133204e49867SJeff LaBundy error = regmap_read(iqs269->regmap, IQS269_CAL_DATA_A, &val); 133304e49867SJeff LaBundy 133404e49867SJeff LaBundy iqs269_irq_wait(); 133504e49867SJeff LaBundy enable_irq(client->irq); 133604e49867SJeff LaBundy 133704e49867SJeff LaBundy if (error) 133804e49867SJeff LaBundy return error; 133904e49867SJeff LaBundy 13403689abfcSJeff LaBundy switch (ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable & 13413689abfcSJeff LaBundy ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) { 134204e49867SJeff LaBundy case IQS269_HALL_PAD_R: 134304e49867SJeff LaBundy val &= IQS269_CAL_DATA_A_HALL_BIN_R_MASK; 134404e49867SJeff LaBundy val >>= IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT; 134504e49867SJeff LaBundy break; 134604e49867SJeff LaBundy 134704e49867SJeff LaBundy case IQS269_HALL_PAD_L: 134804e49867SJeff LaBundy val &= IQS269_CAL_DATA_A_HALL_BIN_L_MASK; 134904e49867SJeff LaBundy val >>= IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT; 135004e49867SJeff LaBundy break; 135104e49867SJeff LaBundy 135204e49867SJeff LaBundy default: 135304e49867SJeff LaBundy return -EINVAL; 135404e49867SJeff LaBundy } 135504e49867SJeff LaBundy 135604e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", val); 135704e49867SJeff LaBundy } 135804e49867SJeff LaBundy 135904e49867SJeff LaBundy static ssize_t hall_enable_show(struct device *dev, 136004e49867SJeff LaBundy struct device_attribute *attr, char *buf) 136104e49867SJeff LaBundy { 136204e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 136304e49867SJeff LaBundy 136404e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->hall_enable); 136504e49867SJeff LaBundy } 136604e49867SJeff LaBundy 136704e49867SJeff LaBundy static ssize_t hall_enable_store(struct device *dev, 136804e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 136904e49867SJeff LaBundy size_t count) 137004e49867SJeff LaBundy { 137104e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 137204e49867SJeff LaBundy unsigned int val; 137304e49867SJeff LaBundy int error; 137404e49867SJeff LaBundy 137504e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 137604e49867SJeff LaBundy if (error) 137704e49867SJeff LaBundy return error; 137804e49867SJeff LaBundy 137904e49867SJeff LaBundy mutex_lock(&iqs269->lock); 138004e49867SJeff LaBundy 138104e49867SJeff LaBundy iqs269->hall_enable = val; 138204e49867SJeff LaBundy iqs269->ati_current = false; 138304e49867SJeff LaBundy 138404e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 138504e49867SJeff LaBundy 138604e49867SJeff LaBundy return count; 138704e49867SJeff LaBundy } 138804e49867SJeff LaBundy 138904e49867SJeff LaBundy static ssize_t ch_number_show(struct device *dev, 139004e49867SJeff LaBundy struct device_attribute *attr, char *buf) 139104e49867SJeff LaBundy { 139204e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 139304e49867SJeff LaBundy 139404e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ch_num); 139504e49867SJeff LaBundy } 139604e49867SJeff LaBundy 139704e49867SJeff LaBundy static ssize_t ch_number_store(struct device *dev, 139804e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 139904e49867SJeff LaBundy size_t count) 140004e49867SJeff LaBundy { 140104e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 140204e49867SJeff LaBundy unsigned int val; 140304e49867SJeff LaBundy int error; 140404e49867SJeff LaBundy 140504e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 140604e49867SJeff LaBundy if (error) 140704e49867SJeff LaBundy return error; 140804e49867SJeff LaBundy 140904e49867SJeff LaBundy if (val >= IQS269_NUM_CH) 141004e49867SJeff LaBundy return -EINVAL; 141104e49867SJeff LaBundy 141204e49867SJeff LaBundy iqs269->ch_num = val; 141304e49867SJeff LaBundy 141404e49867SJeff LaBundy return count; 141504e49867SJeff LaBundy } 141604e49867SJeff LaBundy 141704e49867SJeff LaBundy static ssize_t rx_enable_show(struct device *dev, 141804e49867SJeff LaBundy struct device_attribute *attr, char *buf) 141904e49867SJeff LaBundy { 142004e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 14213689abfcSJeff LaBundy struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 142204e49867SJeff LaBundy 142304e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", 14243689abfcSJeff LaBundy ch_reg[iqs269->ch_num].rx_enable); 142504e49867SJeff LaBundy } 142604e49867SJeff LaBundy 142704e49867SJeff LaBundy static ssize_t rx_enable_store(struct device *dev, 142804e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 142904e49867SJeff LaBundy size_t count) 143004e49867SJeff LaBundy { 143104e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 14323689abfcSJeff LaBundy struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 143304e49867SJeff LaBundy unsigned int val; 143404e49867SJeff LaBundy int error; 143504e49867SJeff LaBundy 143604e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 143704e49867SJeff LaBundy if (error) 143804e49867SJeff LaBundy return error; 143904e49867SJeff LaBundy 144004e49867SJeff LaBundy if (val > 0xFF) 144104e49867SJeff LaBundy return -EINVAL; 144204e49867SJeff LaBundy 144304e49867SJeff LaBundy mutex_lock(&iqs269->lock); 144404e49867SJeff LaBundy 14453689abfcSJeff LaBundy ch_reg[iqs269->ch_num].rx_enable = val; 144604e49867SJeff LaBundy iqs269->ati_current = false; 144704e49867SJeff LaBundy 144804e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 144904e49867SJeff LaBundy 145004e49867SJeff LaBundy return count; 145104e49867SJeff LaBundy } 145204e49867SJeff LaBundy 145304e49867SJeff LaBundy static ssize_t ati_mode_show(struct device *dev, 145404e49867SJeff LaBundy struct device_attribute *attr, char *buf) 145504e49867SJeff LaBundy { 145604e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 145704e49867SJeff LaBundy unsigned int val; 145804e49867SJeff LaBundy int error; 145904e49867SJeff LaBundy 146004e49867SJeff LaBundy error = iqs269_ati_mode_get(iqs269, iqs269->ch_num, &val); 146104e49867SJeff LaBundy if (error) 146204e49867SJeff LaBundy return error; 146304e49867SJeff LaBundy 146404e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", val); 146504e49867SJeff LaBundy } 146604e49867SJeff LaBundy 146704e49867SJeff LaBundy static ssize_t ati_mode_store(struct device *dev, 146804e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 146904e49867SJeff LaBundy size_t count) 147004e49867SJeff LaBundy { 147104e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 147204e49867SJeff LaBundy unsigned int val; 147304e49867SJeff LaBundy int error; 147404e49867SJeff LaBundy 147504e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 147604e49867SJeff LaBundy if (error) 147704e49867SJeff LaBundy return error; 147804e49867SJeff LaBundy 147904e49867SJeff LaBundy error = iqs269_ati_mode_set(iqs269, iqs269->ch_num, val); 148004e49867SJeff LaBundy if (error) 148104e49867SJeff LaBundy return error; 148204e49867SJeff LaBundy 148304e49867SJeff LaBundy return count; 148404e49867SJeff LaBundy } 148504e49867SJeff LaBundy 148604e49867SJeff LaBundy static ssize_t ati_base_show(struct device *dev, 148704e49867SJeff LaBundy struct device_attribute *attr, char *buf) 148804e49867SJeff LaBundy { 148904e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 149004e49867SJeff LaBundy unsigned int val; 149104e49867SJeff LaBundy int error; 149204e49867SJeff LaBundy 149304e49867SJeff LaBundy error = iqs269_ati_base_get(iqs269, iqs269->ch_num, &val); 149404e49867SJeff LaBundy if (error) 149504e49867SJeff LaBundy return error; 149604e49867SJeff LaBundy 149704e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", val); 149804e49867SJeff LaBundy } 149904e49867SJeff LaBundy 150004e49867SJeff LaBundy static ssize_t ati_base_store(struct device *dev, 150104e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 150204e49867SJeff LaBundy size_t count) 150304e49867SJeff LaBundy { 150404e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 150504e49867SJeff LaBundy unsigned int val; 150604e49867SJeff LaBundy int error; 150704e49867SJeff LaBundy 150804e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 150904e49867SJeff LaBundy if (error) 151004e49867SJeff LaBundy return error; 151104e49867SJeff LaBundy 151204e49867SJeff LaBundy error = iqs269_ati_base_set(iqs269, iqs269->ch_num, val); 151304e49867SJeff LaBundy if (error) 151404e49867SJeff LaBundy return error; 151504e49867SJeff LaBundy 151604e49867SJeff LaBundy return count; 151704e49867SJeff LaBundy } 151804e49867SJeff LaBundy 151904e49867SJeff LaBundy static ssize_t ati_target_show(struct device *dev, 152004e49867SJeff LaBundy struct device_attribute *attr, char *buf) 152104e49867SJeff LaBundy { 152204e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 152304e49867SJeff LaBundy unsigned int val; 152404e49867SJeff LaBundy int error; 152504e49867SJeff LaBundy 152604e49867SJeff LaBundy error = iqs269_ati_target_get(iqs269, iqs269->ch_num, &val); 152704e49867SJeff LaBundy if (error) 152804e49867SJeff LaBundy return error; 152904e49867SJeff LaBundy 153004e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", val); 153104e49867SJeff LaBundy } 153204e49867SJeff LaBundy 153304e49867SJeff LaBundy static ssize_t ati_target_store(struct device *dev, 153404e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 153504e49867SJeff LaBundy size_t count) 153604e49867SJeff LaBundy { 153704e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 153804e49867SJeff LaBundy unsigned int val; 153904e49867SJeff LaBundy int error; 154004e49867SJeff LaBundy 154104e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 154204e49867SJeff LaBundy if (error) 154304e49867SJeff LaBundy return error; 154404e49867SJeff LaBundy 154504e49867SJeff LaBundy error = iqs269_ati_target_set(iqs269, iqs269->ch_num, val); 154604e49867SJeff LaBundy if (error) 154704e49867SJeff LaBundy return error; 154804e49867SJeff LaBundy 154904e49867SJeff LaBundy return count; 155004e49867SJeff LaBundy } 155104e49867SJeff LaBundy 155204e49867SJeff LaBundy static ssize_t ati_trigger_show(struct device *dev, 155304e49867SJeff LaBundy struct device_attribute *attr, char *buf) 155404e49867SJeff LaBundy { 155504e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 155604e49867SJeff LaBundy 155704e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ati_current); 155804e49867SJeff LaBundy } 155904e49867SJeff LaBundy 156004e49867SJeff LaBundy static ssize_t ati_trigger_store(struct device *dev, 156104e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 156204e49867SJeff LaBundy size_t count) 156304e49867SJeff LaBundy { 156404e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 156504e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 156604e49867SJeff LaBundy unsigned int val; 156704e49867SJeff LaBundy int error; 156804e49867SJeff LaBundy 156904e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 157004e49867SJeff LaBundy if (error) 157104e49867SJeff LaBundy return error; 157204e49867SJeff LaBundy 157304e49867SJeff LaBundy if (!val) 157404e49867SJeff LaBundy return count; 157504e49867SJeff LaBundy 157604e49867SJeff LaBundy disable_irq(client->irq); 157704e49867SJeff LaBundy 157804e49867SJeff LaBundy error = iqs269_dev_init(iqs269); 157904e49867SJeff LaBundy 158004e49867SJeff LaBundy iqs269_irq_wait(); 158104e49867SJeff LaBundy enable_irq(client->irq); 158204e49867SJeff LaBundy 158304e49867SJeff LaBundy if (error) 158404e49867SJeff LaBundy return error; 158504e49867SJeff LaBundy 158604e49867SJeff LaBundy return count; 158704e49867SJeff LaBundy } 158804e49867SJeff LaBundy 158904e49867SJeff LaBundy static DEVICE_ATTR_RO(counts); 159004e49867SJeff LaBundy static DEVICE_ATTR_RO(hall_bin); 159104e49867SJeff LaBundy static DEVICE_ATTR_RW(hall_enable); 159204e49867SJeff LaBundy static DEVICE_ATTR_RW(ch_number); 159304e49867SJeff LaBundy static DEVICE_ATTR_RW(rx_enable); 159404e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_mode); 159504e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_base); 159604e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_target); 159704e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_trigger); 159804e49867SJeff LaBundy 159904e49867SJeff LaBundy static struct attribute *iqs269_attrs[] = { 160004e49867SJeff LaBundy &dev_attr_counts.attr, 160104e49867SJeff LaBundy &dev_attr_hall_bin.attr, 160204e49867SJeff LaBundy &dev_attr_hall_enable.attr, 160304e49867SJeff LaBundy &dev_attr_ch_number.attr, 160404e49867SJeff LaBundy &dev_attr_rx_enable.attr, 160504e49867SJeff LaBundy &dev_attr_ati_mode.attr, 160604e49867SJeff LaBundy &dev_attr_ati_base.attr, 160704e49867SJeff LaBundy &dev_attr_ati_target.attr, 160804e49867SJeff LaBundy &dev_attr_ati_trigger.attr, 160904e49867SJeff LaBundy NULL, 161004e49867SJeff LaBundy }; 161104e49867SJeff LaBundy 161204e49867SJeff LaBundy static const struct attribute_group iqs269_attr_group = { 161304e49867SJeff LaBundy .attrs = iqs269_attrs, 161404e49867SJeff LaBundy }; 161504e49867SJeff LaBundy 161604e49867SJeff LaBundy static const struct regmap_config iqs269_regmap_config = { 161704e49867SJeff LaBundy .reg_bits = 8, 161804e49867SJeff LaBundy .val_bits = 16, 161904e49867SJeff LaBundy .max_register = IQS269_MAX_REG, 162004e49867SJeff LaBundy }; 162104e49867SJeff LaBundy 162204e49867SJeff LaBundy static int iqs269_probe(struct i2c_client *client) 162304e49867SJeff LaBundy { 162404e49867SJeff LaBundy struct iqs269_ver_info ver_info; 162504e49867SJeff LaBundy struct iqs269_private *iqs269; 162604e49867SJeff LaBundy int error; 162704e49867SJeff LaBundy 162804e49867SJeff LaBundy iqs269 = devm_kzalloc(&client->dev, sizeof(*iqs269), GFP_KERNEL); 162904e49867SJeff LaBundy if (!iqs269) 163004e49867SJeff LaBundy return -ENOMEM; 163104e49867SJeff LaBundy 163204e49867SJeff LaBundy i2c_set_clientdata(client, iqs269); 163304e49867SJeff LaBundy iqs269->client = client; 163404e49867SJeff LaBundy 163504e49867SJeff LaBundy iqs269->regmap = devm_regmap_init_i2c(client, &iqs269_regmap_config); 163604e49867SJeff LaBundy if (IS_ERR(iqs269->regmap)) { 163704e49867SJeff LaBundy error = PTR_ERR(iqs269->regmap); 163804e49867SJeff LaBundy dev_err(&client->dev, "Failed to initialize register map: %d\n", 163904e49867SJeff LaBundy error); 164004e49867SJeff LaBundy return error; 164104e49867SJeff LaBundy } 164204e49867SJeff LaBundy 164304e49867SJeff LaBundy mutex_init(&iqs269->lock); 164404e49867SJeff LaBundy 164504e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO, &ver_info, 164604e49867SJeff LaBundy sizeof(ver_info)); 164704e49867SJeff LaBundy if (error) 164804e49867SJeff LaBundy return error; 164904e49867SJeff LaBundy 165004e49867SJeff LaBundy if (ver_info.prod_num != IQS269_VER_INFO_PROD_NUM) { 165104e49867SJeff LaBundy dev_err(&client->dev, "Unrecognized product number: 0x%02X\n", 165204e49867SJeff LaBundy ver_info.prod_num); 165304e49867SJeff LaBundy return -EINVAL; 165404e49867SJeff LaBundy } 165504e49867SJeff LaBundy 165604e49867SJeff LaBundy error = iqs269_parse_prop(iqs269); 165704e49867SJeff LaBundy if (error) 165804e49867SJeff LaBundy return error; 165904e49867SJeff LaBundy 166004e49867SJeff LaBundy error = iqs269_dev_init(iqs269); 166104e49867SJeff LaBundy if (error) { 166204e49867SJeff LaBundy dev_err(&client->dev, "Failed to initialize device: %d\n", 166304e49867SJeff LaBundy error); 166404e49867SJeff LaBundy return error; 166504e49867SJeff LaBundy } 166604e49867SJeff LaBundy 166704e49867SJeff LaBundy error = iqs269_input_init(iqs269); 166804e49867SJeff LaBundy if (error) 166904e49867SJeff LaBundy return error; 167004e49867SJeff LaBundy 167104e49867SJeff LaBundy error = devm_request_threaded_irq(&client->dev, client->irq, 167204e49867SJeff LaBundy NULL, iqs269_irq, IRQF_ONESHOT, 167304e49867SJeff LaBundy client->name, iqs269); 167404e49867SJeff LaBundy if (error) { 167504e49867SJeff LaBundy dev_err(&client->dev, "Failed to request IRQ: %d\n", error); 167604e49867SJeff LaBundy return error; 167704e49867SJeff LaBundy } 167804e49867SJeff LaBundy 167904e49867SJeff LaBundy error = devm_device_add_group(&client->dev, &iqs269_attr_group); 168004e49867SJeff LaBundy if (error) 168104e49867SJeff LaBundy dev_err(&client->dev, "Failed to add attributes: %d\n", error); 168204e49867SJeff LaBundy 168304e49867SJeff LaBundy return error; 168404e49867SJeff LaBundy } 168504e49867SJeff LaBundy 1686*18ab69c8SJeff LaBundy static u16 iqs269_general_get(struct iqs269_private *iqs269) 1687*18ab69c8SJeff LaBundy { 1688*18ab69c8SJeff LaBundy u16 general = be16_to_cpu(iqs269->sys_reg.general); 1689*18ab69c8SJeff LaBundy 1690*18ab69c8SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_REDO_ATI; 1691*18ab69c8SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_ACK_RESET; 1692*18ab69c8SJeff LaBundy 1693*18ab69c8SJeff LaBundy return general | IQS269_SYS_SETTINGS_DIS_AUTO; 1694*18ab69c8SJeff LaBundy } 1695*18ab69c8SJeff LaBundy 169629eac950SJonathan Cameron static int iqs269_suspend(struct device *dev) 169704e49867SJeff LaBundy { 169804e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 169904e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 170004e49867SJeff LaBundy int error; 1701*18ab69c8SJeff LaBundy u16 general = iqs269_general_get(iqs269); 170204e49867SJeff LaBundy 1703*18ab69c8SJeff LaBundy if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK)) 170404e49867SJeff LaBundy return 0; 170504e49867SJeff LaBundy 170604e49867SJeff LaBundy disable_irq(client->irq); 170704e49867SJeff LaBundy 1708*18ab69c8SJeff LaBundy error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS, general); 170904e49867SJeff LaBundy 171004e49867SJeff LaBundy iqs269_irq_wait(); 171104e49867SJeff LaBundy enable_irq(client->irq); 171204e49867SJeff LaBundy 171304e49867SJeff LaBundy return error; 171404e49867SJeff LaBundy } 171504e49867SJeff LaBundy 171629eac950SJonathan Cameron static int iqs269_resume(struct device *dev) 171704e49867SJeff LaBundy { 171804e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 171904e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 172004e49867SJeff LaBundy int error; 1721*18ab69c8SJeff LaBundy u16 general = iqs269_general_get(iqs269); 172204e49867SJeff LaBundy 1723*18ab69c8SJeff LaBundy if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK)) 172404e49867SJeff LaBundy return 0; 172504e49867SJeff LaBundy 172604e49867SJeff LaBundy disable_irq(client->irq); 172704e49867SJeff LaBundy 1728*18ab69c8SJeff LaBundy error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS, 1729*18ab69c8SJeff LaBundy general & ~IQS269_SYS_SETTINGS_PWR_MODE_MASK); 1730*18ab69c8SJeff LaBundy if (!error) 1731*18ab69c8SJeff LaBundy error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS, 1732*18ab69c8SJeff LaBundy general & ~IQS269_SYS_SETTINGS_DIS_AUTO); 173304e49867SJeff LaBundy 173404e49867SJeff LaBundy iqs269_irq_wait(); 173504e49867SJeff LaBundy enable_irq(client->irq); 173604e49867SJeff LaBundy 173704e49867SJeff LaBundy return error; 173804e49867SJeff LaBundy } 173904e49867SJeff LaBundy 174029eac950SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume); 174104e49867SJeff LaBundy 174204e49867SJeff LaBundy static const struct of_device_id iqs269_of_match[] = { 174304e49867SJeff LaBundy { .compatible = "azoteq,iqs269a" }, 174404e49867SJeff LaBundy { } 174504e49867SJeff LaBundy }; 174604e49867SJeff LaBundy MODULE_DEVICE_TABLE(of, iqs269_of_match); 174704e49867SJeff LaBundy 174804e49867SJeff LaBundy static struct i2c_driver iqs269_i2c_driver = { 174904e49867SJeff LaBundy .driver = { 175004e49867SJeff LaBundy .name = "iqs269a", 175104e49867SJeff LaBundy .of_match_table = iqs269_of_match, 175229eac950SJonathan Cameron .pm = pm_sleep_ptr(&iqs269_pm), 175304e49867SJeff LaBundy }, 175404e49867SJeff LaBundy .probe_new = iqs269_probe, 175504e49867SJeff LaBundy }; 175604e49867SJeff LaBundy module_i2c_driver(iqs269_i2c_driver); 175704e49867SJeff LaBundy 175804e49867SJeff LaBundy MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); 175904e49867SJeff LaBundy MODULE_DESCRIPTION("Azoteq IQS269A Capacitive Touch Controller"); 176004e49867SJeff LaBundy MODULE_LICENSE("GPL"); 1761