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_SETTINGS 0x8C 10004e49867SJeff LaBundy 10104e49867SJeff LaBundy #define IQS269_CHx_ENG_A_MEAS_CAP_SIZE BIT(15) 10204e49867SJeff LaBundy #define IQS269_CHx_ENG_A_RX_GND_INACTIVE BIT(13) 10304e49867SJeff LaBundy #define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE BIT(12) 10404e49867SJeff LaBundy #define IQS269_CHx_ENG_A_ATI_MODE_MASK GENMASK(9, 8) 10504e49867SJeff LaBundy #define IQS269_CHx_ENG_A_ATI_MODE_SHIFT 8 10604e49867SJeff LaBundy #define IQS269_CHx_ENG_A_ATI_MODE_MAX 3 10704e49867SJeff LaBundy #define IQS269_CHx_ENG_A_INV_LOGIC BIT(7) 10804e49867SJeff LaBundy #define IQS269_CHx_ENG_A_PROJ_BIAS_MASK GENMASK(6, 5) 10904e49867SJeff LaBundy #define IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT 5 11004e49867SJeff LaBundy #define IQS269_CHx_ENG_A_PROJ_BIAS_MAX 3 11104e49867SJeff LaBundy #define IQS269_CHx_ENG_A_SENSE_MODE_MASK GENMASK(3, 0) 11204e49867SJeff LaBundy #define IQS269_CHx_ENG_A_SENSE_MODE_MAX 15 11304e49867SJeff LaBundy 11404e49867SJeff LaBundy #define IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE BIT(13) 11504e49867SJeff LaBundy #define IQS269_CHx_ENG_B_SENSE_FREQ_MASK GENMASK(10, 9) 11604e49867SJeff LaBundy #define IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT 9 11704e49867SJeff LaBundy #define IQS269_CHx_ENG_B_SENSE_FREQ_MAX 3 11804e49867SJeff LaBundy #define IQS269_CHx_ENG_B_STATIC_ENABLE BIT(8) 11904e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_MASK GENMASK(7, 6) 12004e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_75 0x00 12104e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_100 0x40 12204e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_150 0x80 12304e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_BASE_200 0xC0 12404e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_TARGET_MASK GENMASK(5, 0) 12504e49867SJeff LaBundy #define IQS269_CHx_ENG_B_ATI_TARGET_MAX 2016 12604e49867SJeff LaBundy 12704e49867SJeff LaBundy #define IQS269_CHx_WEIGHT_MAX 255 12804e49867SJeff LaBundy #define IQS269_CHx_THRESH_MAX 255 12904e49867SJeff LaBundy #define IQS269_CHx_HYST_DEEP_MASK GENMASK(7, 4) 13004e49867SJeff LaBundy #define IQS269_CHx_HYST_DEEP_SHIFT 4 13104e49867SJeff LaBundy #define IQS269_CHx_HYST_TOUCH_MASK GENMASK(3, 0) 13204e49867SJeff LaBundy #define IQS269_CHx_HYST_MAX 15 13304e49867SJeff LaBundy 13404e49867SJeff LaBundy #define IQS269_CHx_HALL_INACTIVE 6 13504e49867SJeff LaBundy #define IQS269_CHx_HALL_ACTIVE 7 13604e49867SJeff LaBundy 13704e49867SJeff LaBundy #define IQS269_HALL_PAD_R BIT(0) 13804e49867SJeff LaBundy #define IQS269_HALL_PAD_L BIT(1) 13904e49867SJeff LaBundy #define IQS269_HALL_PAD_INV BIT(6) 14004e49867SJeff LaBundy 14104e49867SJeff LaBundy #define IQS269_HALL_UI 0xF5 14204e49867SJeff LaBundy #define IQS269_HALL_UI_ENABLE BIT(15) 14304e49867SJeff LaBundy 14404e49867SJeff LaBundy #define IQS269_MAX_REG 0xFF 14504e49867SJeff LaBundy 14604e49867SJeff LaBundy #define IQS269_NUM_CH 8 14704e49867SJeff LaBundy #define IQS269_NUM_SL 2 14804e49867SJeff LaBundy 14904e49867SJeff LaBundy #define IQS269_ATI_POLL_SLEEP_US (iqs269->delay_mult * 10000) 15004e49867SJeff LaBundy #define IQS269_ATI_POLL_TIMEOUT_US (iqs269->delay_mult * 500000) 15104e49867SJeff LaBundy #define IQS269_ATI_STABLE_DELAY_MS (iqs269->delay_mult * 150) 15204e49867SJeff LaBundy 15304e49867SJeff LaBundy #define IQS269_PWR_MODE_POLL_SLEEP_US IQS269_ATI_POLL_SLEEP_US 15404e49867SJeff LaBundy #define IQS269_PWR_MODE_POLL_TIMEOUT_US IQS269_ATI_POLL_TIMEOUT_US 15504e49867SJeff LaBundy 15604e49867SJeff LaBundy #define iqs269_irq_wait() usleep_range(100, 150) 15704e49867SJeff LaBundy 15804e49867SJeff LaBundy enum iqs269_local_cap_size { 15904e49867SJeff LaBundy IQS269_LOCAL_CAP_SIZE_0, 16004e49867SJeff LaBundy IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY, 16104e49867SJeff LaBundy IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5, 16204e49867SJeff LaBundy }; 16304e49867SJeff LaBundy 16404e49867SJeff LaBundy enum iqs269_st_offs { 16504e49867SJeff LaBundy IQS269_ST_OFFS_PROX, 16604e49867SJeff LaBundy IQS269_ST_OFFS_DIR, 16704e49867SJeff LaBundy IQS269_ST_OFFS_TOUCH, 16804e49867SJeff LaBundy IQS269_ST_OFFS_DEEP, 16904e49867SJeff LaBundy }; 17004e49867SJeff LaBundy 17104e49867SJeff LaBundy enum iqs269_th_offs { 17204e49867SJeff LaBundy IQS269_TH_OFFS_PROX, 17304e49867SJeff LaBundy IQS269_TH_OFFS_TOUCH, 17404e49867SJeff LaBundy IQS269_TH_OFFS_DEEP, 17504e49867SJeff LaBundy }; 17604e49867SJeff LaBundy 17704e49867SJeff LaBundy enum iqs269_event_id { 17804e49867SJeff LaBundy IQS269_EVENT_PROX_DN, 17904e49867SJeff LaBundy IQS269_EVENT_PROX_UP, 18004e49867SJeff LaBundy IQS269_EVENT_TOUCH_DN, 18104e49867SJeff LaBundy IQS269_EVENT_TOUCH_UP, 18204e49867SJeff LaBundy IQS269_EVENT_DEEP_DN, 18304e49867SJeff LaBundy IQS269_EVENT_DEEP_UP, 18404e49867SJeff LaBundy }; 18504e49867SJeff LaBundy 18604e49867SJeff LaBundy struct iqs269_switch_desc { 18704e49867SJeff LaBundy unsigned int code; 18804e49867SJeff LaBundy bool enabled; 18904e49867SJeff LaBundy }; 19004e49867SJeff LaBundy 19104e49867SJeff LaBundy struct iqs269_event_desc { 19204e49867SJeff LaBundy const char *name; 19304e49867SJeff LaBundy enum iqs269_st_offs st_offs; 19404e49867SJeff LaBundy enum iqs269_th_offs th_offs; 19504e49867SJeff LaBundy bool dir_up; 19604e49867SJeff LaBundy u8 mask; 19704e49867SJeff LaBundy }; 19804e49867SJeff LaBundy 19904e49867SJeff LaBundy static const struct iqs269_event_desc iqs269_events[] = { 20004e49867SJeff LaBundy [IQS269_EVENT_PROX_DN] = { 20104e49867SJeff LaBundy .name = "event-prox", 20204e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_PROX, 20304e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_PROX, 20404e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_PROX, 20504e49867SJeff LaBundy }, 20604e49867SJeff LaBundy [IQS269_EVENT_PROX_UP] = { 20704e49867SJeff LaBundy .name = "event-prox-alt", 20804e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_PROX, 20904e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_PROX, 21004e49867SJeff LaBundy .dir_up = true, 21104e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_PROX, 21204e49867SJeff LaBundy }, 21304e49867SJeff LaBundy [IQS269_EVENT_TOUCH_DN] = { 21404e49867SJeff LaBundy .name = "event-touch", 21504e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_TOUCH, 21604e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_TOUCH, 21704e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_TOUCH, 21804e49867SJeff LaBundy }, 21904e49867SJeff LaBundy [IQS269_EVENT_TOUCH_UP] = { 22004e49867SJeff LaBundy .name = "event-touch-alt", 22104e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_TOUCH, 22204e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_TOUCH, 22304e49867SJeff LaBundy .dir_up = true, 22404e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_TOUCH, 22504e49867SJeff LaBundy }, 22604e49867SJeff LaBundy [IQS269_EVENT_DEEP_DN] = { 22704e49867SJeff LaBundy .name = "event-deep", 22804e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_DEEP, 22904e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_DEEP, 23004e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_DEEP, 23104e49867SJeff LaBundy }, 23204e49867SJeff LaBundy [IQS269_EVENT_DEEP_UP] = { 23304e49867SJeff LaBundy .name = "event-deep-alt", 23404e49867SJeff LaBundy .st_offs = IQS269_ST_OFFS_DEEP, 23504e49867SJeff LaBundy .th_offs = IQS269_TH_OFFS_DEEP, 23604e49867SJeff LaBundy .dir_up = true, 23704e49867SJeff LaBundy .mask = IQS269_EVENT_MASK_DEEP, 23804e49867SJeff LaBundy }, 23904e49867SJeff LaBundy }; 24004e49867SJeff LaBundy 24104e49867SJeff LaBundy struct iqs269_ver_info { 24204e49867SJeff LaBundy u8 prod_num; 24304e49867SJeff LaBundy u8 sw_num; 24404e49867SJeff LaBundy u8 hw_num; 24504e49867SJeff LaBundy u8 padding; 24604e49867SJeff LaBundy } __packed; 24704e49867SJeff LaBundy 24804e49867SJeff LaBundy struct iqs269_sys_reg { 24904e49867SJeff LaBundy __be16 general; 25004e49867SJeff LaBundy u8 active; 25104e49867SJeff LaBundy u8 filter; 25204e49867SJeff LaBundy u8 reseed; 25304e49867SJeff LaBundy u8 event_mask; 25404e49867SJeff LaBundy u8 rate_np; 25504e49867SJeff LaBundy u8 rate_lp; 25604e49867SJeff LaBundy u8 rate_ulp; 25704e49867SJeff LaBundy u8 timeout_pwr; 25804e49867SJeff LaBundy u8 timeout_rdy; 25904e49867SJeff LaBundy u8 timeout_lta; 26004e49867SJeff LaBundy __be16 misc_a; 26104e49867SJeff LaBundy __be16 misc_b; 26204e49867SJeff LaBundy u8 blocking; 26304e49867SJeff LaBundy u8 padding; 26404e49867SJeff LaBundy u8 slider_select[IQS269_NUM_SL]; 26504e49867SJeff LaBundy u8 timeout_tap; 26604e49867SJeff LaBundy u8 timeout_swipe; 26704e49867SJeff LaBundy u8 thresh_swipe; 26804e49867SJeff LaBundy u8 redo_ati; 26904e49867SJeff LaBundy } __packed; 27004e49867SJeff LaBundy 27104e49867SJeff LaBundy struct iqs269_ch_reg { 27204e49867SJeff LaBundy u8 rx_enable; 27304e49867SJeff LaBundy u8 tx_enable; 27404e49867SJeff LaBundy __be16 engine_a; 27504e49867SJeff LaBundy __be16 engine_b; 27604e49867SJeff LaBundy __be16 ati_comp; 27704e49867SJeff LaBundy u8 thresh[3]; 27804e49867SJeff LaBundy u8 hyst; 27904e49867SJeff LaBundy u8 assoc_select; 28004e49867SJeff LaBundy u8 assoc_weight; 28104e49867SJeff LaBundy } __packed; 28204e49867SJeff LaBundy 28304e49867SJeff LaBundy struct iqs269_flags { 28404e49867SJeff LaBundy __be16 system; 28504e49867SJeff LaBundy u8 gesture; 28604e49867SJeff LaBundy u8 padding; 28704e49867SJeff LaBundy u8 states[4]; 28804e49867SJeff LaBundy } __packed; 28904e49867SJeff LaBundy 29004e49867SJeff LaBundy struct iqs269_private { 29104e49867SJeff LaBundy struct i2c_client *client; 29204e49867SJeff LaBundy struct regmap *regmap; 29304e49867SJeff LaBundy struct mutex lock; 29404e49867SJeff LaBundy struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)]; 29504e49867SJeff LaBundy struct iqs269_ch_reg ch_reg[IQS269_NUM_CH]; 29604e49867SJeff LaBundy struct iqs269_sys_reg sys_reg; 29704e49867SJeff LaBundy struct input_dev *keypad; 29804e49867SJeff LaBundy struct input_dev *slider[IQS269_NUM_SL]; 29904e49867SJeff LaBundy unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH]; 30004e49867SJeff LaBundy unsigned int suspend_mode; 30104e49867SJeff LaBundy unsigned int delay_mult; 30204e49867SJeff LaBundy unsigned int ch_num; 30304e49867SJeff LaBundy bool hall_enable; 30404e49867SJeff LaBundy bool ati_current; 30504e49867SJeff LaBundy }; 30604e49867SJeff LaBundy 30704e49867SJeff LaBundy static int iqs269_ati_mode_set(struct iqs269_private *iqs269, 30804e49867SJeff LaBundy unsigned int ch_num, unsigned int mode) 30904e49867SJeff LaBundy { 31004e49867SJeff LaBundy u16 engine_a; 31104e49867SJeff LaBundy 31204e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 31304e49867SJeff LaBundy return -EINVAL; 31404e49867SJeff LaBundy 31504e49867SJeff LaBundy if (mode > IQS269_CHx_ENG_A_ATI_MODE_MAX) 31604e49867SJeff LaBundy return -EINVAL; 31704e49867SJeff LaBundy 31804e49867SJeff LaBundy mutex_lock(&iqs269->lock); 31904e49867SJeff LaBundy 32004e49867SJeff LaBundy engine_a = be16_to_cpu(iqs269->ch_reg[ch_num].engine_a); 32104e49867SJeff LaBundy 32204e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_ATI_MODE_MASK; 32304e49867SJeff LaBundy engine_a |= (mode << IQS269_CHx_ENG_A_ATI_MODE_SHIFT); 32404e49867SJeff LaBundy 32504e49867SJeff LaBundy iqs269->ch_reg[ch_num].engine_a = cpu_to_be16(engine_a); 32604e49867SJeff LaBundy iqs269->ati_current = false; 32704e49867SJeff LaBundy 32804e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 32904e49867SJeff LaBundy 33004e49867SJeff LaBundy return 0; 33104e49867SJeff LaBundy } 33204e49867SJeff LaBundy 33304e49867SJeff LaBundy static int iqs269_ati_mode_get(struct iqs269_private *iqs269, 33404e49867SJeff LaBundy unsigned int ch_num, unsigned int *mode) 33504e49867SJeff LaBundy { 33604e49867SJeff LaBundy u16 engine_a; 33704e49867SJeff LaBundy 33804e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 33904e49867SJeff LaBundy return -EINVAL; 34004e49867SJeff LaBundy 34104e49867SJeff LaBundy mutex_lock(&iqs269->lock); 34204e49867SJeff LaBundy engine_a = be16_to_cpu(iqs269->ch_reg[ch_num].engine_a); 34304e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 34404e49867SJeff LaBundy 34504e49867SJeff LaBundy engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK; 34604e49867SJeff LaBundy *mode = (engine_a >> IQS269_CHx_ENG_A_ATI_MODE_SHIFT); 34704e49867SJeff LaBundy 34804e49867SJeff LaBundy return 0; 34904e49867SJeff LaBundy } 35004e49867SJeff LaBundy 35104e49867SJeff LaBundy static int iqs269_ati_base_set(struct iqs269_private *iqs269, 35204e49867SJeff LaBundy unsigned int ch_num, unsigned int base) 35304e49867SJeff LaBundy { 35404e49867SJeff LaBundy u16 engine_b; 35504e49867SJeff LaBundy 35604e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 35704e49867SJeff LaBundy return -EINVAL; 35804e49867SJeff LaBundy 35904e49867SJeff LaBundy switch (base) { 36004e49867SJeff LaBundy case 75: 36104e49867SJeff LaBundy base = IQS269_CHx_ENG_B_ATI_BASE_75; 36204e49867SJeff LaBundy break; 36304e49867SJeff LaBundy 36404e49867SJeff LaBundy case 100: 36504e49867SJeff LaBundy base = IQS269_CHx_ENG_B_ATI_BASE_100; 36604e49867SJeff LaBundy break; 36704e49867SJeff LaBundy 36804e49867SJeff LaBundy case 150: 36904e49867SJeff LaBundy base = IQS269_CHx_ENG_B_ATI_BASE_150; 37004e49867SJeff LaBundy break; 37104e49867SJeff LaBundy 37204e49867SJeff LaBundy case 200: 37304e49867SJeff LaBundy base = IQS269_CHx_ENG_B_ATI_BASE_200; 37404e49867SJeff LaBundy break; 37504e49867SJeff LaBundy 37604e49867SJeff LaBundy default: 37704e49867SJeff LaBundy return -EINVAL; 37804e49867SJeff LaBundy } 37904e49867SJeff LaBundy 38004e49867SJeff LaBundy mutex_lock(&iqs269->lock); 38104e49867SJeff LaBundy 38204e49867SJeff LaBundy engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b); 38304e49867SJeff LaBundy 38404e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_ATI_BASE_MASK; 38504e49867SJeff LaBundy engine_b |= base; 38604e49867SJeff LaBundy 38704e49867SJeff LaBundy iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b); 38804e49867SJeff LaBundy iqs269->ati_current = false; 38904e49867SJeff LaBundy 39004e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 39104e49867SJeff LaBundy 39204e49867SJeff LaBundy return 0; 39304e49867SJeff LaBundy } 39404e49867SJeff LaBundy 39504e49867SJeff LaBundy static int iqs269_ati_base_get(struct iqs269_private *iqs269, 39604e49867SJeff LaBundy unsigned int ch_num, unsigned int *base) 39704e49867SJeff LaBundy { 39804e49867SJeff LaBundy u16 engine_b; 39904e49867SJeff LaBundy 40004e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 40104e49867SJeff LaBundy return -EINVAL; 40204e49867SJeff LaBundy 40304e49867SJeff LaBundy mutex_lock(&iqs269->lock); 40404e49867SJeff LaBundy engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b); 40504e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 40604e49867SJeff LaBundy 40704e49867SJeff LaBundy switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) { 40804e49867SJeff LaBundy case IQS269_CHx_ENG_B_ATI_BASE_75: 40904e49867SJeff LaBundy *base = 75; 41004e49867SJeff LaBundy return 0; 41104e49867SJeff LaBundy 41204e49867SJeff LaBundy case IQS269_CHx_ENG_B_ATI_BASE_100: 41304e49867SJeff LaBundy *base = 100; 41404e49867SJeff LaBundy return 0; 41504e49867SJeff LaBundy 41604e49867SJeff LaBundy case IQS269_CHx_ENG_B_ATI_BASE_150: 41704e49867SJeff LaBundy *base = 150; 41804e49867SJeff LaBundy return 0; 41904e49867SJeff LaBundy 42004e49867SJeff LaBundy case IQS269_CHx_ENG_B_ATI_BASE_200: 42104e49867SJeff LaBundy *base = 200; 42204e49867SJeff LaBundy return 0; 42304e49867SJeff LaBundy 42404e49867SJeff LaBundy default: 42504e49867SJeff LaBundy return -EINVAL; 42604e49867SJeff LaBundy } 42704e49867SJeff LaBundy } 42804e49867SJeff LaBundy 42904e49867SJeff LaBundy static int iqs269_ati_target_set(struct iqs269_private *iqs269, 43004e49867SJeff LaBundy unsigned int ch_num, unsigned int target) 43104e49867SJeff LaBundy { 43204e49867SJeff LaBundy u16 engine_b; 43304e49867SJeff LaBundy 43404e49867SJeff LaBundy if (ch_num >= IQS269_NUM_CH) 43504e49867SJeff LaBundy return -EINVAL; 43604e49867SJeff LaBundy 43704e49867SJeff LaBundy if (target > IQS269_CHx_ENG_B_ATI_TARGET_MAX) 43804e49867SJeff LaBundy return -EINVAL; 43904e49867SJeff LaBundy 44004e49867SJeff LaBundy mutex_lock(&iqs269->lock); 44104e49867SJeff LaBundy 44204e49867SJeff LaBundy engine_b = be16_to_cpu(iqs269->ch_reg[ch_num].engine_b); 44304e49867SJeff LaBundy 44404e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_ATI_TARGET_MASK; 44504e49867SJeff LaBundy engine_b |= target / 32; 44604e49867SJeff LaBundy 44704e49867SJeff LaBundy iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b); 44804e49867SJeff LaBundy iqs269->ati_current = false; 44904e49867SJeff LaBundy 45004e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 45104e49867SJeff LaBundy 45204e49867SJeff LaBundy return 0; 45304e49867SJeff LaBundy } 45404e49867SJeff LaBundy 45504e49867SJeff LaBundy static int iqs269_ati_target_get(struct iqs269_private *iqs269, 45604e49867SJeff LaBundy unsigned int ch_num, unsigned int *target) 45704e49867SJeff LaBundy { 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); 46404e49867SJeff LaBundy engine_b = be16_to_cpu(iqs269->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 53404e49867SJeff LaBundy ch_reg = &iqs269->ch_reg[reg]; 53504e49867SJeff LaBundy 53604e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, 53704e49867SJeff LaBundy IQS269_CHx_SETTINGS + reg * sizeof(*ch_reg) / 2, 53804e49867SJeff LaBundy ch_reg, sizeof(*ch_reg)); 53904e49867SJeff LaBundy if (error) 54004e49867SJeff LaBundy return error; 54104e49867SJeff LaBundy 54204e49867SJeff LaBundy error = iqs269_parse_mask(ch_node, "azoteq,rx-enable", 54304e49867SJeff LaBundy &ch_reg->rx_enable); 54404e49867SJeff LaBundy if (error) { 54504e49867SJeff LaBundy dev_err(&client->dev, "Invalid channel %u RX enable mask: %d\n", 54604e49867SJeff LaBundy reg, error); 54704e49867SJeff LaBundy return error; 54804e49867SJeff LaBundy } 54904e49867SJeff LaBundy 55004e49867SJeff LaBundy error = iqs269_parse_mask(ch_node, "azoteq,tx-enable", 55104e49867SJeff LaBundy &ch_reg->tx_enable); 55204e49867SJeff LaBundy if (error) { 55304e49867SJeff LaBundy dev_err(&client->dev, "Invalid channel %u TX enable mask: %d\n", 55404e49867SJeff LaBundy reg, error); 55504e49867SJeff LaBundy return error; 55604e49867SJeff LaBundy } 55704e49867SJeff LaBundy 55804e49867SJeff LaBundy engine_a = be16_to_cpu(ch_reg->engine_a); 55904e49867SJeff LaBundy engine_b = be16_to_cpu(ch_reg->engine_b); 56004e49867SJeff LaBundy 56104e49867SJeff LaBundy engine_a |= IQS269_CHx_ENG_A_MEAS_CAP_SIZE; 56204e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,meas-cap-decrease")) 56304e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_MEAS_CAP_SIZE; 56404e49867SJeff LaBundy 56504e49867SJeff LaBundy engine_a |= IQS269_CHx_ENG_A_RX_GND_INACTIVE; 56604e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,rx-float-inactive")) 56704e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_RX_GND_INACTIVE; 56804e49867SJeff LaBundy 56904e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_LOCAL_CAP_SIZE; 57004e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE; 57104e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,local-cap-size", &val)) { 57204e49867SJeff LaBundy switch (val) { 57304e49867SJeff LaBundy case IQS269_LOCAL_CAP_SIZE_0: 57404e49867SJeff LaBundy break; 57504e49867SJeff LaBundy 57604e49867SJeff LaBundy case IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5: 57704e49867SJeff LaBundy engine_a |= IQS269_CHx_ENG_A_LOCAL_CAP_SIZE; 5786f49c4f5SGustavo A. R. Silva fallthrough; 57904e49867SJeff LaBundy 58004e49867SJeff LaBundy case IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY: 58104e49867SJeff LaBundy engine_b |= IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE; 58204e49867SJeff LaBundy break; 58304e49867SJeff LaBundy 58404e49867SJeff LaBundy default: 58504e49867SJeff LaBundy dev_err(&client->dev, 58604e49867SJeff LaBundy "Invalid channel %u local cap. size: %u\n", reg, 58704e49867SJeff LaBundy val); 58804e49867SJeff LaBundy return -EINVAL; 58904e49867SJeff LaBundy } 59004e49867SJeff LaBundy } 59104e49867SJeff LaBundy 59204e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_INV_LOGIC; 59304e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,invert-enable")) 59404e49867SJeff LaBundy engine_a |= IQS269_CHx_ENG_A_INV_LOGIC; 59504e49867SJeff LaBundy 59604e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,proj-bias", &val)) { 59704e49867SJeff LaBundy if (val > IQS269_CHx_ENG_A_PROJ_BIAS_MAX) { 59804e49867SJeff LaBundy dev_err(&client->dev, 59904e49867SJeff LaBundy "Invalid channel %u bias current: %u\n", reg, 60004e49867SJeff LaBundy val); 60104e49867SJeff LaBundy return -EINVAL; 60204e49867SJeff LaBundy } 60304e49867SJeff LaBundy 60404e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_PROJ_BIAS_MASK; 60504e49867SJeff LaBundy engine_a |= (val << IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT); 60604e49867SJeff LaBundy } 60704e49867SJeff LaBundy 60804e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,sense-mode", &val)) { 60904e49867SJeff LaBundy if (val > IQS269_CHx_ENG_A_SENSE_MODE_MAX) { 61004e49867SJeff LaBundy dev_err(&client->dev, 61104e49867SJeff LaBundy "Invalid channel %u sensing mode: %u\n", reg, 61204e49867SJeff LaBundy val); 61304e49867SJeff LaBundy return -EINVAL; 61404e49867SJeff LaBundy } 61504e49867SJeff LaBundy 61604e49867SJeff LaBundy engine_a &= ~IQS269_CHx_ENG_A_SENSE_MODE_MASK; 61704e49867SJeff LaBundy engine_a |= val; 61804e49867SJeff LaBundy } 61904e49867SJeff LaBundy 62004e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,sense-freq", &val)) { 62104e49867SJeff LaBundy if (val > IQS269_CHx_ENG_B_SENSE_FREQ_MAX) { 62204e49867SJeff LaBundy dev_err(&client->dev, 62304e49867SJeff LaBundy "Invalid channel %u sensing frequency: %u\n", 62404e49867SJeff LaBundy reg, val); 62504e49867SJeff LaBundy return -EINVAL; 62604e49867SJeff LaBundy } 62704e49867SJeff LaBundy 62804e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_SENSE_FREQ_MASK; 62904e49867SJeff LaBundy engine_b |= (val << IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT); 63004e49867SJeff LaBundy } 63104e49867SJeff LaBundy 63204e49867SJeff LaBundy engine_b &= ~IQS269_CHx_ENG_B_STATIC_ENABLE; 63304e49867SJeff LaBundy if (fwnode_property_present(ch_node, "azoteq,static-enable")) 63404e49867SJeff LaBundy engine_b |= IQS269_CHx_ENG_B_STATIC_ENABLE; 63504e49867SJeff LaBundy 63604e49867SJeff LaBundy ch_reg->engine_a = cpu_to_be16(engine_a); 63704e49867SJeff LaBundy ch_reg->engine_b = cpu_to_be16(engine_b); 63804e49867SJeff LaBundy 63904e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,ati-mode", &val)) { 64004e49867SJeff LaBundy error = iqs269_ati_mode_set(iqs269, reg, val); 64104e49867SJeff LaBundy if (error) { 64204e49867SJeff LaBundy dev_err(&client->dev, 64304e49867SJeff LaBundy "Invalid channel %u ATI mode: %u\n", reg, val); 64404e49867SJeff LaBundy return error; 64504e49867SJeff LaBundy } 64604e49867SJeff LaBundy } 64704e49867SJeff LaBundy 64804e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,ati-base", &val)) { 64904e49867SJeff LaBundy error = iqs269_ati_base_set(iqs269, reg, val); 65004e49867SJeff LaBundy if (error) { 65104e49867SJeff LaBundy dev_err(&client->dev, 65204e49867SJeff LaBundy "Invalid channel %u ATI base: %u\n", reg, val); 65304e49867SJeff LaBundy return error; 65404e49867SJeff LaBundy } 65504e49867SJeff LaBundy } 65604e49867SJeff LaBundy 65704e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,ati-target", &val)) { 65804e49867SJeff LaBundy error = iqs269_ati_target_set(iqs269, reg, val); 65904e49867SJeff LaBundy if (error) { 66004e49867SJeff LaBundy dev_err(&client->dev, 66104e49867SJeff LaBundy "Invalid channel %u ATI target: %u\n", reg, 66204e49867SJeff LaBundy val); 66304e49867SJeff LaBundy return error; 66404e49867SJeff LaBundy } 66504e49867SJeff LaBundy } 66604e49867SJeff LaBundy 66704e49867SJeff LaBundy error = iqs269_parse_mask(ch_node, "azoteq,assoc-select", 66804e49867SJeff LaBundy &ch_reg->assoc_select); 66904e49867SJeff LaBundy if (error) { 67004e49867SJeff LaBundy dev_err(&client->dev, "Invalid channel %u association: %d\n", 67104e49867SJeff LaBundy reg, error); 67204e49867SJeff LaBundy return error; 67304e49867SJeff LaBundy } 67404e49867SJeff LaBundy 67504e49867SJeff LaBundy if (!fwnode_property_read_u32(ch_node, "azoteq,assoc-weight", &val)) { 67604e49867SJeff LaBundy if (val > IQS269_CHx_WEIGHT_MAX) { 67704e49867SJeff LaBundy dev_err(&client->dev, 67804e49867SJeff LaBundy "Invalid channel %u associated weight: %u\n", 67904e49867SJeff LaBundy reg, val); 68004e49867SJeff LaBundy return -EINVAL; 68104e49867SJeff LaBundy } 68204e49867SJeff LaBundy 68304e49867SJeff LaBundy ch_reg->assoc_weight = val; 68404e49867SJeff LaBundy } 68504e49867SJeff LaBundy 68604e49867SJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { 68704e49867SJeff LaBundy ev_node = fwnode_get_named_child_node(ch_node, 68804e49867SJeff LaBundy iqs269_events[i].name); 68904e49867SJeff LaBundy if (!ev_node) 69004e49867SJeff LaBundy continue; 69104e49867SJeff LaBundy 69204e49867SJeff LaBundy if (!fwnode_property_read_u32(ev_node, "azoteq,thresh", &val)) { 69304e49867SJeff LaBundy if (val > IQS269_CHx_THRESH_MAX) { 69404e49867SJeff LaBundy dev_err(&client->dev, 69504e49867SJeff LaBundy "Invalid channel %u threshold: %u\n", 69604e49867SJeff LaBundy reg, val); 69704e49867SJeff LaBundy return -EINVAL; 69804e49867SJeff LaBundy } 69904e49867SJeff LaBundy 70004e49867SJeff LaBundy ch_reg->thresh[iqs269_events[i].th_offs] = val; 70104e49867SJeff LaBundy } 70204e49867SJeff LaBundy 70304e49867SJeff LaBundy if (!fwnode_property_read_u32(ev_node, "azoteq,hyst", &val)) { 70404e49867SJeff LaBundy u8 *hyst = &ch_reg->hyst; 70504e49867SJeff LaBundy 70604e49867SJeff LaBundy if (val > IQS269_CHx_HYST_MAX) { 70704e49867SJeff LaBundy dev_err(&client->dev, 70804e49867SJeff LaBundy "Invalid channel %u hysteresis: %u\n", 70904e49867SJeff LaBundy reg, val); 71004e49867SJeff LaBundy return -EINVAL; 71104e49867SJeff LaBundy } 71204e49867SJeff LaBundy 71304e49867SJeff LaBundy if (i == IQS269_EVENT_DEEP_DN || 71404e49867SJeff LaBundy i == IQS269_EVENT_DEEP_UP) { 71504e49867SJeff LaBundy *hyst &= ~IQS269_CHx_HYST_DEEP_MASK; 71604e49867SJeff LaBundy *hyst |= (val << IQS269_CHx_HYST_DEEP_SHIFT); 71704e49867SJeff LaBundy } else if (i == IQS269_EVENT_TOUCH_DN || 71804e49867SJeff LaBundy i == IQS269_EVENT_TOUCH_UP) { 71904e49867SJeff LaBundy *hyst &= ~IQS269_CHx_HYST_TOUCH_MASK; 72004e49867SJeff LaBundy *hyst |= val; 72104e49867SJeff LaBundy } 72204e49867SJeff LaBundy } 72304e49867SJeff LaBundy 72404e49867SJeff LaBundy if (fwnode_property_read_u32(ev_node, "linux,code", &val)) 72504e49867SJeff LaBundy continue; 72604e49867SJeff LaBundy 72704e49867SJeff LaBundy switch (reg) { 72804e49867SJeff LaBundy case IQS269_CHx_HALL_ACTIVE: 72904e49867SJeff LaBundy if (iqs269->hall_enable) { 73004e49867SJeff LaBundy iqs269->switches[i].code = val; 73104e49867SJeff LaBundy iqs269->switches[i].enabled = true; 73204e49867SJeff LaBundy } 7336f49c4f5SGustavo A. R. Silva fallthrough; 73404e49867SJeff LaBundy 73504e49867SJeff LaBundy case IQS269_CHx_HALL_INACTIVE: 73604e49867SJeff LaBundy if (iqs269->hall_enable) 73704e49867SJeff LaBundy break; 7386f49c4f5SGustavo A. R. Silva fallthrough; 73904e49867SJeff LaBundy 74004e49867SJeff LaBundy default: 74104e49867SJeff LaBundy iqs269->keycode[i * IQS269_NUM_CH + reg] = val; 74204e49867SJeff LaBundy } 74304e49867SJeff LaBundy 74404e49867SJeff LaBundy iqs269->sys_reg.event_mask &= ~iqs269_events[i].mask; 74504e49867SJeff LaBundy } 74604e49867SJeff LaBundy 74704e49867SJeff LaBundy return 0; 74804e49867SJeff LaBundy } 74904e49867SJeff LaBundy 75004e49867SJeff LaBundy static int iqs269_parse_prop(struct iqs269_private *iqs269) 75104e49867SJeff LaBundy { 75204e49867SJeff LaBundy struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg; 75304e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 75404e49867SJeff LaBundy struct fwnode_handle *ch_node; 75504e49867SJeff LaBundy u16 general, misc_a, misc_b; 75604e49867SJeff LaBundy unsigned int val; 75704e49867SJeff LaBundy int error; 75804e49867SJeff LaBundy 75904e49867SJeff LaBundy iqs269->hall_enable = device_property_present(&client->dev, 76004e49867SJeff LaBundy "azoteq,hall-enable"); 76104e49867SJeff LaBundy 76204e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode", 76304e49867SJeff LaBundy &val)) { 76404e49867SJeff LaBundy if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) { 76504e49867SJeff LaBundy dev_err(&client->dev, "Invalid suspend mode: %u\n", 76604e49867SJeff LaBundy val); 76704e49867SJeff LaBundy return -EINVAL; 76804e49867SJeff LaBundy } 76904e49867SJeff LaBundy 77004e49867SJeff LaBundy iqs269->suspend_mode = val; 77104e49867SJeff LaBundy } 77204e49867SJeff LaBundy 77304e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg, 77404e49867SJeff LaBundy sizeof(*sys_reg)); 77504e49867SJeff LaBundy if (error) 77604e49867SJeff LaBundy return error; 77704e49867SJeff LaBundy 77804e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-lta", 77904e49867SJeff LaBundy &val)) { 78004e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 78104e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 78204e49867SJeff LaBundy val); 78304e49867SJeff LaBundy return -EINVAL; 78404e49867SJeff LaBundy } 78504e49867SJeff LaBundy 78604e49867SJeff LaBundy sys_reg->filter &= ~IQS269_FILT_STR_LP_LTA_MASK; 78704e49867SJeff LaBundy sys_reg->filter |= (val << IQS269_FILT_STR_LP_LTA_SHIFT); 78804e49867SJeff LaBundy } 78904e49867SJeff LaBundy 79004e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-cnt", 79104e49867SJeff LaBundy &val)) { 79204e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 79304e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 79404e49867SJeff LaBundy val); 79504e49867SJeff LaBundy return -EINVAL; 79604e49867SJeff LaBundy } 79704e49867SJeff LaBundy 79804e49867SJeff LaBundy sys_reg->filter &= ~IQS269_FILT_STR_LP_CNT_MASK; 79904e49867SJeff LaBundy sys_reg->filter |= (val << IQS269_FILT_STR_LP_CNT_SHIFT); 80004e49867SJeff LaBundy } 80104e49867SJeff LaBundy 80204e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-lta", 80304e49867SJeff LaBundy &val)) { 80404e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 80504e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 80604e49867SJeff LaBundy val); 80704e49867SJeff LaBundy return -EINVAL; 80804e49867SJeff LaBundy } 80904e49867SJeff LaBundy 81004e49867SJeff LaBundy sys_reg->filter &= ~IQS269_FILT_STR_NP_LTA_MASK; 81104e49867SJeff LaBundy sys_reg->filter |= (val << IQS269_FILT_STR_NP_LTA_SHIFT); 81204e49867SJeff LaBundy } 81304e49867SJeff LaBundy 81404e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-cnt", 81504e49867SJeff LaBundy &val)) { 81604e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 81704e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 81804e49867SJeff LaBundy val); 81904e49867SJeff LaBundy return -EINVAL; 82004e49867SJeff LaBundy } 82104e49867SJeff LaBundy 82204e49867SJeff LaBundy sys_reg->filter &= ~IQS269_FILT_STR_NP_CNT_MASK; 82304e49867SJeff LaBundy sys_reg->filter |= val; 82404e49867SJeff LaBundy } 82504e49867SJeff LaBundy 82604e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,rate-np-ms", 82704e49867SJeff LaBundy &val)) { 82804e49867SJeff LaBundy if (val > IQS269_RATE_NP_MS_MAX) { 82904e49867SJeff LaBundy dev_err(&client->dev, "Invalid report rate: %u\n", val); 83004e49867SJeff LaBundy return -EINVAL; 83104e49867SJeff LaBundy } 83204e49867SJeff LaBundy 83304e49867SJeff LaBundy sys_reg->rate_np = val; 83404e49867SJeff LaBundy } 83504e49867SJeff LaBundy 83604e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,rate-lp-ms", 83704e49867SJeff LaBundy &val)) { 83804e49867SJeff LaBundy if (val > IQS269_RATE_LP_MS_MAX) { 83904e49867SJeff LaBundy dev_err(&client->dev, "Invalid report rate: %u\n", val); 84004e49867SJeff LaBundy return -EINVAL; 84104e49867SJeff LaBundy } 84204e49867SJeff LaBundy 84304e49867SJeff LaBundy sys_reg->rate_lp = val; 84404e49867SJeff LaBundy } 84504e49867SJeff LaBundy 84604e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,rate-ulp-ms", 84704e49867SJeff LaBundy &val)) { 84804e49867SJeff LaBundy if (val > IQS269_RATE_ULP_MS_MAX) { 84904e49867SJeff LaBundy dev_err(&client->dev, "Invalid report rate: %u\n", val); 85004e49867SJeff LaBundy return -EINVAL; 85104e49867SJeff LaBundy } 85204e49867SJeff LaBundy 85304e49867SJeff LaBundy sys_reg->rate_ulp = val / 16; 85404e49867SJeff LaBundy } 85504e49867SJeff LaBundy 85604e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,timeout-pwr-ms", 85704e49867SJeff LaBundy &val)) { 85804e49867SJeff LaBundy if (val > IQS269_TIMEOUT_PWR_MS_MAX) { 85904e49867SJeff LaBundy dev_err(&client->dev, "Invalid timeout: %u\n", val); 86004e49867SJeff LaBundy return -EINVAL; 86104e49867SJeff LaBundy } 86204e49867SJeff LaBundy 86304e49867SJeff LaBundy sys_reg->timeout_pwr = val / 512; 86404e49867SJeff LaBundy } 86504e49867SJeff LaBundy 86604e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,timeout-lta-ms", 86704e49867SJeff LaBundy &val)) { 86804e49867SJeff LaBundy if (val > IQS269_TIMEOUT_LTA_MS_MAX) { 86904e49867SJeff LaBundy dev_err(&client->dev, "Invalid timeout: %u\n", val); 87004e49867SJeff LaBundy return -EINVAL; 87104e49867SJeff LaBundy } 87204e49867SJeff LaBundy 87304e49867SJeff LaBundy sys_reg->timeout_lta = val / 512; 87404e49867SJeff LaBundy } 87504e49867SJeff LaBundy 87604e49867SJeff LaBundy misc_a = be16_to_cpu(sys_reg->misc_a); 87704e49867SJeff LaBundy misc_b = be16_to_cpu(sys_reg->misc_b); 87804e49867SJeff LaBundy 87904e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_ATI_BAND_DISABLE; 88004e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,ati-band-disable")) 88104e49867SJeff LaBundy misc_a |= IQS269_MISC_A_ATI_BAND_DISABLE; 88204e49867SJeff LaBundy 88304e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_ATI_LP_ONLY; 88404e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,ati-lp-only")) 88504e49867SJeff LaBundy misc_a |= IQS269_MISC_A_ATI_LP_ONLY; 88604e49867SJeff LaBundy 88704e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_ATI_BAND_TIGHTEN; 88804e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,ati-band-tighten")) 88904e49867SJeff LaBundy misc_a |= IQS269_MISC_A_ATI_BAND_TIGHTEN; 89004e49867SJeff LaBundy 89104e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_FILT_DISABLE; 89204e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,filt-disable")) 89304e49867SJeff LaBundy misc_a |= IQS269_MISC_A_FILT_DISABLE; 89404e49867SJeff LaBundy 89504e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,gpio3-select", 89604e49867SJeff LaBundy &val)) { 89704e49867SJeff LaBundy if (val >= IQS269_NUM_CH) { 89804e49867SJeff LaBundy dev_err(&client->dev, "Invalid GPIO3 selection: %u\n", 89904e49867SJeff LaBundy val); 90004e49867SJeff LaBundy return -EINVAL; 90104e49867SJeff LaBundy } 90204e49867SJeff LaBundy 90304e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_GPIO3_SELECT_MASK; 90404e49867SJeff LaBundy misc_a |= (val << IQS269_MISC_A_GPIO3_SELECT_SHIFT); 90504e49867SJeff LaBundy } 90604e49867SJeff LaBundy 90704e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_DUAL_DIR; 90804e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,dual-direction")) 90904e49867SJeff LaBundy misc_a |= IQS269_MISC_A_DUAL_DIR; 91004e49867SJeff LaBundy 91104e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,tx-freq", &val)) { 91204e49867SJeff LaBundy if (val > IQS269_MISC_A_TX_FREQ_MAX) { 91304e49867SJeff LaBundy dev_err(&client->dev, 91404e49867SJeff LaBundy "Invalid excitation frequency: %u\n", val); 91504e49867SJeff LaBundy return -EINVAL; 91604e49867SJeff LaBundy } 91704e49867SJeff LaBundy 91804e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_TX_FREQ_MASK; 91904e49867SJeff LaBundy misc_a |= (val << IQS269_MISC_A_TX_FREQ_SHIFT); 92004e49867SJeff LaBundy } 92104e49867SJeff LaBundy 92204e49867SJeff LaBundy misc_a &= ~IQS269_MISC_A_GLOBAL_CAP_SIZE; 92304e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,global-cap-increase")) 92404e49867SJeff LaBundy misc_a |= IQS269_MISC_A_GLOBAL_CAP_SIZE; 92504e49867SJeff LaBundy 92604e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,reseed-select", 92704e49867SJeff LaBundy &val)) { 92804e49867SJeff LaBundy if (val > IQS269_MISC_B_RESEED_UI_SEL_MAX) { 92904e49867SJeff LaBundy dev_err(&client->dev, "Invalid reseed selection: %u\n", 93004e49867SJeff LaBundy val); 93104e49867SJeff LaBundy return -EINVAL; 93204e49867SJeff LaBundy } 93304e49867SJeff LaBundy 93404e49867SJeff LaBundy misc_b &= ~IQS269_MISC_B_RESEED_UI_SEL_MASK; 93504e49867SJeff LaBundy misc_b |= (val << IQS269_MISC_B_RESEED_UI_SEL_SHIFT); 93604e49867SJeff LaBundy } 93704e49867SJeff LaBundy 93804e49867SJeff LaBundy misc_b &= ~IQS269_MISC_B_TRACKING_UI_ENABLE; 93904e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,tracking-enable")) 94004e49867SJeff LaBundy misc_b |= IQS269_MISC_B_TRACKING_UI_ENABLE; 94104e49867SJeff LaBundy 94204e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,filt-str-slider", 94304e49867SJeff LaBundy &val)) { 94404e49867SJeff LaBundy if (val > IQS269_FILT_STR_MAX) { 94504e49867SJeff LaBundy dev_err(&client->dev, "Invalid filter strength: %u\n", 94604e49867SJeff LaBundy val); 94704e49867SJeff LaBundy return -EINVAL; 94804e49867SJeff LaBundy } 94904e49867SJeff LaBundy 95004e49867SJeff LaBundy misc_b &= ~IQS269_MISC_B_FILT_STR_SLIDER; 95104e49867SJeff LaBundy misc_b |= val; 95204e49867SJeff LaBundy } 95304e49867SJeff LaBundy 95404e49867SJeff LaBundy sys_reg->misc_a = cpu_to_be16(misc_a); 95504e49867SJeff LaBundy sys_reg->misc_b = cpu_to_be16(misc_b); 95604e49867SJeff LaBundy 95704e49867SJeff LaBundy sys_reg->active = 0; 95804e49867SJeff LaBundy sys_reg->reseed = 0; 95904e49867SJeff LaBundy 96004e49867SJeff LaBundy sys_reg->blocking = 0; 96104e49867SJeff LaBundy 96204e49867SJeff LaBundy sys_reg->slider_select[0] = 0; 96304e49867SJeff LaBundy sys_reg->slider_select[1] = 0; 96404e49867SJeff LaBundy 96504e49867SJeff LaBundy sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS); 96604e49867SJeff LaBundy 96704e49867SJeff LaBundy device_for_each_child_node(&client->dev, ch_node) { 96804e49867SJeff LaBundy error = iqs269_parse_chan(iqs269, ch_node); 96904e49867SJeff LaBundy if (error) { 97004e49867SJeff LaBundy fwnode_handle_put(ch_node); 97104e49867SJeff LaBundy return error; 97204e49867SJeff LaBundy } 97304e49867SJeff LaBundy } 97404e49867SJeff LaBundy 97504e49867SJeff LaBundy /* 97604e49867SJeff LaBundy * Volunteer all active channels to participate in ATI when REDO-ATI is 97704e49867SJeff LaBundy * manually triggered. 97804e49867SJeff LaBundy */ 97904e49867SJeff LaBundy sys_reg->redo_ati = sys_reg->active; 98004e49867SJeff LaBundy 98104e49867SJeff LaBundy general = be16_to_cpu(sys_reg->general); 98204e49867SJeff LaBundy 98304e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,clk-div")) { 98404e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_CLK_DIV; 98504e49867SJeff LaBundy iqs269->delay_mult = 4; 98604e49867SJeff LaBundy } else { 98704e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_CLK_DIV; 98804e49867SJeff LaBundy iqs269->delay_mult = 1; 98904e49867SJeff LaBundy } 99004e49867SJeff LaBundy 99104e49867SJeff LaBundy /* 99204e49867SJeff LaBundy * Configure the device to automatically switch between normal and low- 99304e49867SJeff LaBundy * power modes as a function of sensing activity. Ultra-low-power mode, 99404e49867SJeff LaBundy * if enabled, is reserved for suspend. 99504e49867SJeff LaBundy */ 99604e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_ULP_AUTO; 99704e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_DIS_AUTO; 99804e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_PWR_MODE_MASK; 99904e49867SJeff LaBundy 100004e49867SJeff LaBundy if (!device_property_read_u32(&client->dev, "azoteq,ulp-update", 100104e49867SJeff LaBundy &val)) { 100204e49867SJeff LaBundy if (val > IQS269_SYS_SETTINGS_ULP_UPDATE_MAX) { 100304e49867SJeff LaBundy dev_err(&client->dev, "Invalid update rate: %u\n", val); 100404e49867SJeff LaBundy return -EINVAL; 100504e49867SJeff LaBundy } 100604e49867SJeff LaBundy 100704e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_ULP_UPDATE_MASK; 100804e49867SJeff LaBundy general |= (val << IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT); 100904e49867SJeff LaBundy } 101004e49867SJeff LaBundy 101104e49867SJeff LaBundy general &= ~IQS269_SYS_SETTINGS_RESEED_OFFSET; 101204e49867SJeff LaBundy if (device_property_present(&client->dev, "azoteq,reseed-offset")) 101304e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_RESEED_OFFSET; 101404e49867SJeff LaBundy 101504e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_EVENT_MODE; 101604e49867SJeff LaBundy 101704e49867SJeff LaBundy /* 101804e49867SJeff LaBundy * As per the datasheet, enable streaming during normal-power mode if 101904e49867SJeff LaBundy * either slider is in use. In that case, the device returns to event 102004e49867SJeff LaBundy * mode during low-power mode. 102104e49867SJeff LaBundy */ 102204e49867SJeff LaBundy if (sys_reg->slider_select[0] || sys_reg->slider_select[1]) 102304e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_EVENT_MODE_LP; 102404e49867SJeff LaBundy 102504e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_REDO_ATI; 102604e49867SJeff LaBundy general |= IQS269_SYS_SETTINGS_ACK_RESET; 102704e49867SJeff LaBundy 102804e49867SJeff LaBundy sys_reg->general = cpu_to_be16(general); 102904e49867SJeff LaBundy 103004e49867SJeff LaBundy return 0; 103104e49867SJeff LaBundy } 103204e49867SJeff LaBundy 103304e49867SJeff LaBundy static int iqs269_dev_init(struct iqs269_private *iqs269) 103404e49867SJeff LaBundy { 103504e49867SJeff LaBundy struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg; 103604e49867SJeff LaBundy struct iqs269_ch_reg *ch_reg; 103704e49867SJeff LaBundy unsigned int val; 103804e49867SJeff LaBundy int error, i; 103904e49867SJeff LaBundy 104004e49867SJeff LaBundy mutex_lock(&iqs269->lock); 104104e49867SJeff LaBundy 104204e49867SJeff LaBundy error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI, 104304e49867SJeff LaBundy IQS269_HALL_UI_ENABLE, 104404e49867SJeff LaBundy iqs269->hall_enable ? ~0 : 0); 104504e49867SJeff LaBundy if (error) 104604e49867SJeff LaBundy goto err_mutex; 104704e49867SJeff LaBundy 104804e49867SJeff LaBundy for (i = 0; i < IQS269_NUM_CH; i++) { 104904e49867SJeff LaBundy if (!(sys_reg->active & BIT(i))) 105004e49867SJeff LaBundy continue; 105104e49867SJeff LaBundy 105204e49867SJeff LaBundy ch_reg = &iqs269->ch_reg[i]; 105304e49867SJeff LaBundy 105404e49867SJeff LaBundy error = regmap_raw_write(iqs269->regmap, 105504e49867SJeff LaBundy IQS269_CHx_SETTINGS + i * 105604e49867SJeff LaBundy sizeof(*ch_reg) / 2, ch_reg, 105704e49867SJeff LaBundy sizeof(*ch_reg)); 105804e49867SJeff LaBundy if (error) 105904e49867SJeff LaBundy goto err_mutex; 106004e49867SJeff LaBundy } 106104e49867SJeff LaBundy 106204e49867SJeff LaBundy /* 106304e49867SJeff LaBundy * The REDO-ATI and ATI channel selection fields must be written in the 106404e49867SJeff LaBundy * same block write, so every field between registers 0x80 through 0x8B 106504e49867SJeff LaBundy * (inclusive) must be written as well. 106604e49867SJeff LaBundy */ 106704e49867SJeff LaBundy error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg, 106804e49867SJeff LaBundy sizeof(*sys_reg)); 106904e49867SJeff LaBundy if (error) 107004e49867SJeff LaBundy goto err_mutex; 107104e49867SJeff LaBundy 107204e49867SJeff LaBundy error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val, 107304e49867SJeff LaBundy !(val & IQS269_SYS_FLAGS_IN_ATI), 107404e49867SJeff LaBundy IQS269_ATI_POLL_SLEEP_US, 107504e49867SJeff LaBundy IQS269_ATI_POLL_TIMEOUT_US); 107604e49867SJeff LaBundy if (error) 107704e49867SJeff LaBundy goto err_mutex; 107804e49867SJeff LaBundy 107904e49867SJeff LaBundy msleep(IQS269_ATI_STABLE_DELAY_MS); 108004e49867SJeff LaBundy iqs269->ati_current = true; 108104e49867SJeff LaBundy 108204e49867SJeff LaBundy err_mutex: 108304e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 108404e49867SJeff LaBundy 108504e49867SJeff LaBundy return error; 108604e49867SJeff LaBundy } 108704e49867SJeff LaBundy 108804e49867SJeff LaBundy static int iqs269_input_init(struct iqs269_private *iqs269) 108904e49867SJeff LaBundy { 109004e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 109104e49867SJeff LaBundy struct iqs269_flags flags; 109204e49867SJeff LaBundy unsigned int sw_code, keycode; 109304e49867SJeff LaBundy int error, i, j; 109404e49867SJeff LaBundy u8 dir_mask, state; 109504e49867SJeff LaBundy 109604e49867SJeff LaBundy iqs269->keypad = devm_input_allocate_device(&client->dev); 109704e49867SJeff LaBundy if (!iqs269->keypad) 109804e49867SJeff LaBundy return -ENOMEM; 109904e49867SJeff LaBundy 110004e49867SJeff LaBundy iqs269->keypad->keycodemax = ARRAY_SIZE(iqs269->keycode); 110104e49867SJeff LaBundy iqs269->keypad->keycode = iqs269->keycode; 110204e49867SJeff LaBundy iqs269->keypad->keycodesize = sizeof(*iqs269->keycode); 110304e49867SJeff LaBundy 110404e49867SJeff LaBundy iqs269->keypad->name = "iqs269a_keypad"; 110504e49867SJeff LaBundy iqs269->keypad->id.bustype = BUS_I2C; 110604e49867SJeff LaBundy 110704e49867SJeff LaBundy if (iqs269->hall_enable) { 110804e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS, 110904e49867SJeff LaBundy &flags, sizeof(flags)); 111004e49867SJeff LaBundy if (error) { 111104e49867SJeff LaBundy dev_err(&client->dev, 111204e49867SJeff LaBundy "Failed to read initial status: %d\n", error); 111304e49867SJeff LaBundy return error; 111404e49867SJeff LaBundy } 111504e49867SJeff LaBundy } 111604e49867SJeff LaBundy 111704e49867SJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { 111804e49867SJeff LaBundy dir_mask = flags.states[IQS269_ST_OFFS_DIR]; 111904e49867SJeff LaBundy if (!iqs269_events[i].dir_up) 112004e49867SJeff LaBundy dir_mask = ~dir_mask; 112104e49867SJeff LaBundy 112204e49867SJeff LaBundy state = flags.states[iqs269_events[i].st_offs] & dir_mask; 112304e49867SJeff LaBundy 112404e49867SJeff LaBundy sw_code = iqs269->switches[i].code; 112504e49867SJeff LaBundy 112604e49867SJeff LaBundy for (j = 0; j < IQS269_NUM_CH; j++) { 112704e49867SJeff LaBundy keycode = iqs269->keycode[i * IQS269_NUM_CH + j]; 112804e49867SJeff LaBundy 112904e49867SJeff LaBundy /* 113004e49867SJeff LaBundy * Hall-effect sensing repurposes a pair of dedicated 113104e49867SJeff LaBundy * channels, only one of which reports events. 113204e49867SJeff LaBundy */ 113304e49867SJeff LaBundy switch (j) { 113404e49867SJeff LaBundy case IQS269_CHx_HALL_ACTIVE: 113504e49867SJeff LaBundy if (iqs269->hall_enable && 113604e49867SJeff LaBundy iqs269->switches[i].enabled) { 113704e49867SJeff LaBundy input_set_capability(iqs269->keypad, 113804e49867SJeff LaBundy EV_SW, sw_code); 113904e49867SJeff LaBundy input_report_switch(iqs269->keypad, 114004e49867SJeff LaBundy sw_code, 114104e49867SJeff LaBundy state & BIT(j)); 114204e49867SJeff LaBundy } 11436f49c4f5SGustavo A. R. Silva fallthrough; 114404e49867SJeff LaBundy 114504e49867SJeff LaBundy case IQS269_CHx_HALL_INACTIVE: 114604e49867SJeff LaBundy if (iqs269->hall_enable) 114704e49867SJeff LaBundy continue; 11486f49c4f5SGustavo A. R. Silva fallthrough; 114904e49867SJeff LaBundy 115004e49867SJeff LaBundy default: 115104e49867SJeff LaBundy if (keycode != KEY_RESERVED) 115204e49867SJeff LaBundy input_set_capability(iqs269->keypad, 115304e49867SJeff LaBundy EV_KEY, keycode); 115404e49867SJeff LaBundy } 115504e49867SJeff LaBundy } 115604e49867SJeff LaBundy } 115704e49867SJeff LaBundy 115804e49867SJeff LaBundy input_sync(iqs269->keypad); 115904e49867SJeff LaBundy 116004e49867SJeff LaBundy error = input_register_device(iqs269->keypad); 116104e49867SJeff LaBundy if (error) { 116204e49867SJeff LaBundy dev_err(&client->dev, "Failed to register keypad: %d\n", error); 116304e49867SJeff LaBundy return error; 116404e49867SJeff LaBundy } 116504e49867SJeff LaBundy 116604e49867SJeff LaBundy for (i = 0; i < IQS269_NUM_SL; i++) { 116704e49867SJeff LaBundy if (!iqs269->sys_reg.slider_select[i]) 116804e49867SJeff LaBundy continue; 116904e49867SJeff LaBundy 117004e49867SJeff LaBundy iqs269->slider[i] = devm_input_allocate_device(&client->dev); 117104e49867SJeff LaBundy if (!iqs269->slider[i]) 117204e49867SJeff LaBundy return -ENOMEM; 117304e49867SJeff LaBundy 117404e49867SJeff LaBundy iqs269->slider[i]->name = i ? "iqs269a_slider_1" 117504e49867SJeff LaBundy : "iqs269a_slider_0"; 117604e49867SJeff LaBundy iqs269->slider[i]->id.bustype = BUS_I2C; 117704e49867SJeff LaBundy 117804e49867SJeff LaBundy input_set_capability(iqs269->slider[i], EV_KEY, BTN_TOUCH); 117904e49867SJeff LaBundy input_set_abs_params(iqs269->slider[i], ABS_X, 0, 255, 0, 0); 118004e49867SJeff LaBundy 118104e49867SJeff LaBundy error = input_register_device(iqs269->slider[i]); 118204e49867SJeff LaBundy if (error) { 118304e49867SJeff LaBundy dev_err(&client->dev, 118404e49867SJeff LaBundy "Failed to register slider %d: %d\n", i, error); 118504e49867SJeff LaBundy return error; 118604e49867SJeff LaBundy } 118704e49867SJeff LaBundy } 118804e49867SJeff LaBundy 118904e49867SJeff LaBundy return 0; 119004e49867SJeff LaBundy } 119104e49867SJeff LaBundy 119204e49867SJeff LaBundy static int iqs269_report(struct iqs269_private *iqs269) 119304e49867SJeff LaBundy { 119404e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 119504e49867SJeff LaBundy struct iqs269_flags flags; 119604e49867SJeff LaBundy unsigned int sw_code, keycode; 119704e49867SJeff LaBundy int error, i, j; 119804e49867SJeff LaBundy u8 slider_x[IQS269_NUM_SL]; 119904e49867SJeff LaBundy u8 dir_mask, state; 120004e49867SJeff LaBundy 120104e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS, &flags, 120204e49867SJeff LaBundy sizeof(flags)); 120304e49867SJeff LaBundy if (error) { 120404e49867SJeff LaBundy dev_err(&client->dev, "Failed to read device status: %d\n", 120504e49867SJeff LaBundy error); 120604e49867SJeff LaBundy return error; 120704e49867SJeff LaBundy } 120804e49867SJeff LaBundy 120904e49867SJeff LaBundy /* 121004e49867SJeff LaBundy * The device resets itself if its own watchdog bites, which can happen 121104e49867SJeff LaBundy * in the event of an I2C communication error. In this case, the device 121204e49867SJeff LaBundy * asserts a SHOW_RESET interrupt and all registers must be restored. 121304e49867SJeff LaBundy */ 121404e49867SJeff LaBundy if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_SHOW_RESET) { 121504e49867SJeff LaBundy dev_err(&client->dev, "Unexpected device reset\n"); 121604e49867SJeff LaBundy 121704e49867SJeff LaBundy error = iqs269_dev_init(iqs269); 121804e49867SJeff LaBundy if (error) 121904e49867SJeff LaBundy dev_err(&client->dev, 122004e49867SJeff LaBundy "Failed to re-initialize device: %d\n", error); 122104e49867SJeff LaBundy 122204e49867SJeff LaBundy return error; 122304e49867SJeff LaBundy } 122404e49867SJeff LaBundy 122504e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X, slider_x, 122604e49867SJeff LaBundy sizeof(slider_x)); 122704e49867SJeff LaBundy if (error) { 122804e49867SJeff LaBundy dev_err(&client->dev, "Failed to read slider position: %d\n", 122904e49867SJeff LaBundy error); 123004e49867SJeff LaBundy return error; 123104e49867SJeff LaBundy } 123204e49867SJeff LaBundy 123304e49867SJeff LaBundy for (i = 0; i < IQS269_NUM_SL; i++) { 123404e49867SJeff LaBundy if (!iqs269->sys_reg.slider_select[i]) 123504e49867SJeff LaBundy continue; 123604e49867SJeff LaBundy 123704e49867SJeff LaBundy /* 123804e49867SJeff LaBundy * Report BTN_TOUCH if any channel that participates in the 123904e49867SJeff LaBundy * slider is in a state of touch. 124004e49867SJeff LaBundy */ 124104e49867SJeff LaBundy if (flags.states[IQS269_ST_OFFS_TOUCH] & 124204e49867SJeff LaBundy iqs269->sys_reg.slider_select[i]) { 124304e49867SJeff LaBundy input_report_key(iqs269->slider[i], BTN_TOUCH, 1); 124404e49867SJeff LaBundy input_report_abs(iqs269->slider[i], ABS_X, slider_x[i]); 124504e49867SJeff LaBundy } else { 124604e49867SJeff LaBundy input_report_key(iqs269->slider[i], BTN_TOUCH, 0); 124704e49867SJeff LaBundy } 124804e49867SJeff LaBundy 124904e49867SJeff LaBundy input_sync(iqs269->slider[i]); 125004e49867SJeff LaBundy } 125104e49867SJeff LaBundy 125204e49867SJeff LaBundy for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { 125304e49867SJeff LaBundy dir_mask = flags.states[IQS269_ST_OFFS_DIR]; 125404e49867SJeff LaBundy if (!iqs269_events[i].dir_up) 125504e49867SJeff LaBundy dir_mask = ~dir_mask; 125604e49867SJeff LaBundy 125704e49867SJeff LaBundy state = flags.states[iqs269_events[i].st_offs] & dir_mask; 125804e49867SJeff LaBundy 125904e49867SJeff LaBundy sw_code = iqs269->switches[i].code; 126004e49867SJeff LaBundy 126104e49867SJeff LaBundy for (j = 0; j < IQS269_NUM_CH; j++) { 126204e49867SJeff LaBundy keycode = iqs269->keycode[i * IQS269_NUM_CH + j]; 126304e49867SJeff LaBundy 126404e49867SJeff LaBundy switch (j) { 126504e49867SJeff LaBundy case IQS269_CHx_HALL_ACTIVE: 126604e49867SJeff LaBundy if (iqs269->hall_enable && 126704e49867SJeff LaBundy iqs269->switches[i].enabled) 126804e49867SJeff LaBundy input_report_switch(iqs269->keypad, 126904e49867SJeff LaBundy sw_code, 127004e49867SJeff LaBundy state & BIT(j)); 12716f49c4f5SGustavo A. R. Silva fallthrough; 127204e49867SJeff LaBundy 127304e49867SJeff LaBundy case IQS269_CHx_HALL_INACTIVE: 127404e49867SJeff LaBundy if (iqs269->hall_enable) 127504e49867SJeff LaBundy continue; 12766f49c4f5SGustavo A. R. Silva fallthrough; 127704e49867SJeff LaBundy 127804e49867SJeff LaBundy default: 127904e49867SJeff LaBundy input_report_key(iqs269->keypad, keycode, 128004e49867SJeff LaBundy state & BIT(j)); 128104e49867SJeff LaBundy } 128204e49867SJeff LaBundy } 128304e49867SJeff LaBundy } 128404e49867SJeff LaBundy 128504e49867SJeff LaBundy input_sync(iqs269->keypad); 128604e49867SJeff LaBundy 128704e49867SJeff LaBundy return 0; 128804e49867SJeff LaBundy } 128904e49867SJeff LaBundy 129004e49867SJeff LaBundy static irqreturn_t iqs269_irq(int irq, void *context) 129104e49867SJeff LaBundy { 129204e49867SJeff LaBundy struct iqs269_private *iqs269 = context; 129304e49867SJeff LaBundy 129404e49867SJeff LaBundy if (iqs269_report(iqs269)) 129504e49867SJeff LaBundy return IRQ_NONE; 129604e49867SJeff LaBundy 129704e49867SJeff LaBundy /* 129804e49867SJeff LaBundy * The device does not deassert its interrupt (RDY) pin until shortly 129904e49867SJeff LaBundy * after receiving an I2C stop condition; the following delay ensures 130004e49867SJeff LaBundy * the interrupt handler does not return before this time. 130104e49867SJeff LaBundy */ 130204e49867SJeff LaBundy iqs269_irq_wait(); 130304e49867SJeff LaBundy 130404e49867SJeff LaBundy return IRQ_HANDLED; 130504e49867SJeff LaBundy } 130604e49867SJeff LaBundy 130704e49867SJeff LaBundy static ssize_t counts_show(struct device *dev, 130804e49867SJeff LaBundy struct device_attribute *attr, char *buf) 130904e49867SJeff LaBundy { 131004e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 131104e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 131204e49867SJeff LaBundy __le16 counts; 131304e49867SJeff LaBundy int error; 131404e49867SJeff LaBundy 131504e49867SJeff LaBundy if (!iqs269->ati_current || iqs269->hall_enable) 131604e49867SJeff LaBundy return -EPERM; 131704e49867SJeff LaBundy 131804e49867SJeff LaBundy /* 131904e49867SJeff LaBundy * Unsolicited I2C communication prompts the device to assert its RDY 132004e49867SJeff LaBundy * pin, so disable the interrupt line until the operation is finished 132104e49867SJeff LaBundy * and RDY has been deasserted. 132204e49867SJeff LaBundy */ 132304e49867SJeff LaBundy disable_irq(client->irq); 132404e49867SJeff LaBundy 132504e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, 132604e49867SJeff LaBundy IQS269_CHx_COUNTS + iqs269->ch_num * 2, 132704e49867SJeff LaBundy &counts, sizeof(counts)); 132804e49867SJeff LaBundy 132904e49867SJeff LaBundy iqs269_irq_wait(); 133004e49867SJeff LaBundy enable_irq(client->irq); 133104e49867SJeff LaBundy 133204e49867SJeff LaBundy if (error) 133304e49867SJeff LaBundy return error; 133404e49867SJeff LaBundy 133504e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", le16_to_cpu(counts)); 133604e49867SJeff LaBundy } 133704e49867SJeff LaBundy 133804e49867SJeff LaBundy static ssize_t hall_bin_show(struct device *dev, 133904e49867SJeff LaBundy struct device_attribute *attr, char *buf) 134004e49867SJeff LaBundy { 134104e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 134204e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 134304e49867SJeff LaBundy unsigned int val; 134404e49867SJeff LaBundy int error; 134504e49867SJeff LaBundy 134604e49867SJeff LaBundy disable_irq(client->irq); 134704e49867SJeff LaBundy 134804e49867SJeff LaBundy error = regmap_read(iqs269->regmap, IQS269_CAL_DATA_A, &val); 134904e49867SJeff LaBundy 135004e49867SJeff LaBundy iqs269_irq_wait(); 135104e49867SJeff LaBundy enable_irq(client->irq); 135204e49867SJeff LaBundy 135304e49867SJeff LaBundy if (error) 135404e49867SJeff LaBundy return error; 135504e49867SJeff LaBundy 135604e49867SJeff LaBundy switch (iqs269->ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable & 135704e49867SJeff LaBundy iqs269->ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) { 135804e49867SJeff LaBundy case IQS269_HALL_PAD_R: 135904e49867SJeff LaBundy val &= IQS269_CAL_DATA_A_HALL_BIN_R_MASK; 136004e49867SJeff LaBundy val >>= IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT; 136104e49867SJeff LaBundy break; 136204e49867SJeff LaBundy 136304e49867SJeff LaBundy case IQS269_HALL_PAD_L: 136404e49867SJeff LaBundy val &= IQS269_CAL_DATA_A_HALL_BIN_L_MASK; 136504e49867SJeff LaBundy val >>= IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT; 136604e49867SJeff LaBundy break; 136704e49867SJeff LaBundy 136804e49867SJeff LaBundy default: 136904e49867SJeff LaBundy return -EINVAL; 137004e49867SJeff LaBundy } 137104e49867SJeff LaBundy 137204e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", val); 137304e49867SJeff LaBundy } 137404e49867SJeff LaBundy 137504e49867SJeff LaBundy static ssize_t hall_enable_show(struct device *dev, 137604e49867SJeff LaBundy struct device_attribute *attr, char *buf) 137704e49867SJeff LaBundy { 137804e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 137904e49867SJeff LaBundy 138004e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->hall_enable); 138104e49867SJeff LaBundy } 138204e49867SJeff LaBundy 138304e49867SJeff LaBundy static ssize_t hall_enable_store(struct device *dev, 138404e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 138504e49867SJeff LaBundy size_t count) 138604e49867SJeff LaBundy { 138704e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 138804e49867SJeff LaBundy unsigned int val; 138904e49867SJeff LaBundy int error; 139004e49867SJeff LaBundy 139104e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 139204e49867SJeff LaBundy if (error) 139304e49867SJeff LaBundy return error; 139404e49867SJeff LaBundy 139504e49867SJeff LaBundy mutex_lock(&iqs269->lock); 139604e49867SJeff LaBundy 139704e49867SJeff LaBundy iqs269->hall_enable = val; 139804e49867SJeff LaBundy iqs269->ati_current = false; 139904e49867SJeff LaBundy 140004e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 140104e49867SJeff LaBundy 140204e49867SJeff LaBundy return count; 140304e49867SJeff LaBundy } 140404e49867SJeff LaBundy 140504e49867SJeff LaBundy static ssize_t ch_number_show(struct device *dev, 140604e49867SJeff LaBundy struct device_attribute *attr, char *buf) 140704e49867SJeff LaBundy { 140804e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 140904e49867SJeff LaBundy 141004e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ch_num); 141104e49867SJeff LaBundy } 141204e49867SJeff LaBundy 141304e49867SJeff LaBundy static ssize_t ch_number_store(struct device *dev, 141404e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 141504e49867SJeff LaBundy size_t count) 141604e49867SJeff LaBundy { 141704e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 141804e49867SJeff LaBundy unsigned int val; 141904e49867SJeff LaBundy int error; 142004e49867SJeff LaBundy 142104e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 142204e49867SJeff LaBundy if (error) 142304e49867SJeff LaBundy return error; 142404e49867SJeff LaBundy 142504e49867SJeff LaBundy if (val >= IQS269_NUM_CH) 142604e49867SJeff LaBundy return -EINVAL; 142704e49867SJeff LaBundy 142804e49867SJeff LaBundy iqs269->ch_num = val; 142904e49867SJeff LaBundy 143004e49867SJeff LaBundy return count; 143104e49867SJeff LaBundy } 143204e49867SJeff LaBundy 143304e49867SJeff LaBundy static ssize_t rx_enable_show(struct device *dev, 143404e49867SJeff LaBundy struct device_attribute *attr, char *buf) 143504e49867SJeff LaBundy { 143604e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 143704e49867SJeff LaBundy 143804e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", 143904e49867SJeff LaBundy iqs269->ch_reg[iqs269->ch_num].rx_enable); 144004e49867SJeff LaBundy } 144104e49867SJeff LaBundy 144204e49867SJeff LaBundy static ssize_t rx_enable_store(struct device *dev, 144304e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 144404e49867SJeff LaBundy size_t count) 144504e49867SJeff LaBundy { 144604e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 144704e49867SJeff LaBundy unsigned int val; 144804e49867SJeff LaBundy int error; 144904e49867SJeff LaBundy 145004e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 145104e49867SJeff LaBundy if (error) 145204e49867SJeff LaBundy return error; 145304e49867SJeff LaBundy 145404e49867SJeff LaBundy if (val > 0xFF) 145504e49867SJeff LaBundy return -EINVAL; 145604e49867SJeff LaBundy 145704e49867SJeff LaBundy mutex_lock(&iqs269->lock); 145804e49867SJeff LaBundy 145904e49867SJeff LaBundy iqs269->ch_reg[iqs269->ch_num].rx_enable = val; 146004e49867SJeff LaBundy iqs269->ati_current = false; 146104e49867SJeff LaBundy 146204e49867SJeff LaBundy mutex_unlock(&iqs269->lock); 146304e49867SJeff LaBundy 146404e49867SJeff LaBundy return count; 146504e49867SJeff LaBundy } 146604e49867SJeff LaBundy 146704e49867SJeff LaBundy static ssize_t ati_mode_show(struct device *dev, 146804e49867SJeff LaBundy struct device_attribute *attr, char *buf) 146904e49867SJeff LaBundy { 147004e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 147104e49867SJeff LaBundy unsigned int val; 147204e49867SJeff LaBundy int error; 147304e49867SJeff LaBundy 147404e49867SJeff LaBundy error = iqs269_ati_mode_get(iqs269, iqs269->ch_num, &val); 147504e49867SJeff LaBundy if (error) 147604e49867SJeff LaBundy return error; 147704e49867SJeff LaBundy 147804e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", val); 147904e49867SJeff LaBundy } 148004e49867SJeff LaBundy 148104e49867SJeff LaBundy static ssize_t ati_mode_store(struct device *dev, 148204e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 148304e49867SJeff LaBundy size_t count) 148404e49867SJeff LaBundy { 148504e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 148604e49867SJeff LaBundy unsigned int val; 148704e49867SJeff LaBundy int error; 148804e49867SJeff LaBundy 148904e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 149004e49867SJeff LaBundy if (error) 149104e49867SJeff LaBundy return error; 149204e49867SJeff LaBundy 149304e49867SJeff LaBundy error = iqs269_ati_mode_set(iqs269, iqs269->ch_num, val); 149404e49867SJeff LaBundy if (error) 149504e49867SJeff LaBundy return error; 149604e49867SJeff LaBundy 149704e49867SJeff LaBundy return count; 149804e49867SJeff LaBundy } 149904e49867SJeff LaBundy 150004e49867SJeff LaBundy static ssize_t ati_base_show(struct device *dev, 150104e49867SJeff LaBundy struct device_attribute *attr, char *buf) 150204e49867SJeff LaBundy { 150304e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 150404e49867SJeff LaBundy unsigned int val; 150504e49867SJeff LaBundy int error; 150604e49867SJeff LaBundy 150704e49867SJeff LaBundy error = iqs269_ati_base_get(iqs269, iqs269->ch_num, &val); 150804e49867SJeff LaBundy if (error) 150904e49867SJeff LaBundy return error; 151004e49867SJeff LaBundy 151104e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", val); 151204e49867SJeff LaBundy } 151304e49867SJeff LaBundy 151404e49867SJeff LaBundy static ssize_t ati_base_store(struct device *dev, 151504e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 151604e49867SJeff LaBundy size_t count) 151704e49867SJeff LaBundy { 151804e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 151904e49867SJeff LaBundy unsigned int val; 152004e49867SJeff LaBundy int error; 152104e49867SJeff LaBundy 152204e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 152304e49867SJeff LaBundy if (error) 152404e49867SJeff LaBundy return error; 152504e49867SJeff LaBundy 152604e49867SJeff LaBundy error = iqs269_ati_base_set(iqs269, iqs269->ch_num, val); 152704e49867SJeff LaBundy if (error) 152804e49867SJeff LaBundy return error; 152904e49867SJeff LaBundy 153004e49867SJeff LaBundy return count; 153104e49867SJeff LaBundy } 153204e49867SJeff LaBundy 153304e49867SJeff LaBundy static ssize_t ati_target_show(struct device *dev, 153404e49867SJeff LaBundy struct device_attribute *attr, char *buf) 153504e49867SJeff LaBundy { 153604e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 153704e49867SJeff LaBundy unsigned int val; 153804e49867SJeff LaBundy int error; 153904e49867SJeff LaBundy 154004e49867SJeff LaBundy error = iqs269_ati_target_get(iqs269, iqs269->ch_num, &val); 154104e49867SJeff LaBundy if (error) 154204e49867SJeff LaBundy return error; 154304e49867SJeff LaBundy 154404e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", val); 154504e49867SJeff LaBundy } 154604e49867SJeff LaBundy 154704e49867SJeff LaBundy static ssize_t ati_target_store(struct device *dev, 154804e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 154904e49867SJeff LaBundy size_t count) 155004e49867SJeff LaBundy { 155104e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 155204e49867SJeff LaBundy unsigned int val; 155304e49867SJeff LaBundy int error; 155404e49867SJeff LaBundy 155504e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 155604e49867SJeff LaBundy if (error) 155704e49867SJeff LaBundy return error; 155804e49867SJeff LaBundy 155904e49867SJeff LaBundy error = iqs269_ati_target_set(iqs269, iqs269->ch_num, val); 156004e49867SJeff LaBundy if (error) 156104e49867SJeff LaBundy return error; 156204e49867SJeff LaBundy 156304e49867SJeff LaBundy return count; 156404e49867SJeff LaBundy } 156504e49867SJeff LaBundy 156604e49867SJeff LaBundy static ssize_t ati_trigger_show(struct device *dev, 156704e49867SJeff LaBundy struct device_attribute *attr, char *buf) 156804e49867SJeff LaBundy { 156904e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 157004e49867SJeff LaBundy 157104e49867SJeff LaBundy return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ati_current); 157204e49867SJeff LaBundy } 157304e49867SJeff LaBundy 157404e49867SJeff LaBundy static ssize_t ati_trigger_store(struct device *dev, 157504e49867SJeff LaBundy struct device_attribute *attr, const char *buf, 157604e49867SJeff LaBundy size_t count) 157704e49867SJeff LaBundy { 157804e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 157904e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 158004e49867SJeff LaBundy unsigned int val; 158104e49867SJeff LaBundy int error; 158204e49867SJeff LaBundy 158304e49867SJeff LaBundy error = kstrtouint(buf, 10, &val); 158404e49867SJeff LaBundy if (error) 158504e49867SJeff LaBundy return error; 158604e49867SJeff LaBundy 158704e49867SJeff LaBundy if (!val) 158804e49867SJeff LaBundy return count; 158904e49867SJeff LaBundy 159004e49867SJeff LaBundy disable_irq(client->irq); 159104e49867SJeff LaBundy 159204e49867SJeff LaBundy error = iqs269_dev_init(iqs269); 159304e49867SJeff LaBundy 159404e49867SJeff LaBundy iqs269_irq_wait(); 159504e49867SJeff LaBundy enable_irq(client->irq); 159604e49867SJeff LaBundy 159704e49867SJeff LaBundy if (error) 159804e49867SJeff LaBundy return error; 159904e49867SJeff LaBundy 160004e49867SJeff LaBundy return count; 160104e49867SJeff LaBundy } 160204e49867SJeff LaBundy 160304e49867SJeff LaBundy static DEVICE_ATTR_RO(counts); 160404e49867SJeff LaBundy static DEVICE_ATTR_RO(hall_bin); 160504e49867SJeff LaBundy static DEVICE_ATTR_RW(hall_enable); 160604e49867SJeff LaBundy static DEVICE_ATTR_RW(ch_number); 160704e49867SJeff LaBundy static DEVICE_ATTR_RW(rx_enable); 160804e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_mode); 160904e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_base); 161004e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_target); 161104e49867SJeff LaBundy static DEVICE_ATTR_RW(ati_trigger); 161204e49867SJeff LaBundy 161304e49867SJeff LaBundy static struct attribute *iqs269_attrs[] = { 161404e49867SJeff LaBundy &dev_attr_counts.attr, 161504e49867SJeff LaBundy &dev_attr_hall_bin.attr, 161604e49867SJeff LaBundy &dev_attr_hall_enable.attr, 161704e49867SJeff LaBundy &dev_attr_ch_number.attr, 161804e49867SJeff LaBundy &dev_attr_rx_enable.attr, 161904e49867SJeff LaBundy &dev_attr_ati_mode.attr, 162004e49867SJeff LaBundy &dev_attr_ati_base.attr, 162104e49867SJeff LaBundy &dev_attr_ati_target.attr, 162204e49867SJeff LaBundy &dev_attr_ati_trigger.attr, 162304e49867SJeff LaBundy NULL, 162404e49867SJeff LaBundy }; 162504e49867SJeff LaBundy 162604e49867SJeff LaBundy static const struct attribute_group iqs269_attr_group = { 162704e49867SJeff LaBundy .attrs = iqs269_attrs, 162804e49867SJeff LaBundy }; 162904e49867SJeff LaBundy 163004e49867SJeff LaBundy static const struct regmap_config iqs269_regmap_config = { 163104e49867SJeff LaBundy .reg_bits = 8, 163204e49867SJeff LaBundy .val_bits = 16, 163304e49867SJeff LaBundy .max_register = IQS269_MAX_REG, 163404e49867SJeff LaBundy }; 163504e49867SJeff LaBundy 163604e49867SJeff LaBundy static int iqs269_probe(struct i2c_client *client) 163704e49867SJeff LaBundy { 163804e49867SJeff LaBundy struct iqs269_ver_info ver_info; 163904e49867SJeff LaBundy struct iqs269_private *iqs269; 164004e49867SJeff LaBundy int error; 164104e49867SJeff LaBundy 164204e49867SJeff LaBundy iqs269 = devm_kzalloc(&client->dev, sizeof(*iqs269), GFP_KERNEL); 164304e49867SJeff LaBundy if (!iqs269) 164404e49867SJeff LaBundy return -ENOMEM; 164504e49867SJeff LaBundy 164604e49867SJeff LaBundy i2c_set_clientdata(client, iqs269); 164704e49867SJeff LaBundy iqs269->client = client; 164804e49867SJeff LaBundy 164904e49867SJeff LaBundy iqs269->regmap = devm_regmap_init_i2c(client, &iqs269_regmap_config); 165004e49867SJeff LaBundy if (IS_ERR(iqs269->regmap)) { 165104e49867SJeff LaBundy error = PTR_ERR(iqs269->regmap); 165204e49867SJeff LaBundy dev_err(&client->dev, "Failed to initialize register map: %d\n", 165304e49867SJeff LaBundy error); 165404e49867SJeff LaBundy return error; 165504e49867SJeff LaBundy } 165604e49867SJeff LaBundy 165704e49867SJeff LaBundy mutex_init(&iqs269->lock); 165804e49867SJeff LaBundy 165904e49867SJeff LaBundy error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO, &ver_info, 166004e49867SJeff LaBundy sizeof(ver_info)); 166104e49867SJeff LaBundy if (error) 166204e49867SJeff LaBundy return error; 166304e49867SJeff LaBundy 166404e49867SJeff LaBundy if (ver_info.prod_num != IQS269_VER_INFO_PROD_NUM) { 166504e49867SJeff LaBundy dev_err(&client->dev, "Unrecognized product number: 0x%02X\n", 166604e49867SJeff LaBundy ver_info.prod_num); 166704e49867SJeff LaBundy return -EINVAL; 166804e49867SJeff LaBundy } 166904e49867SJeff LaBundy 167004e49867SJeff LaBundy error = iqs269_parse_prop(iqs269); 167104e49867SJeff LaBundy if (error) 167204e49867SJeff LaBundy return error; 167304e49867SJeff LaBundy 167404e49867SJeff LaBundy error = iqs269_dev_init(iqs269); 167504e49867SJeff LaBundy if (error) { 167604e49867SJeff LaBundy dev_err(&client->dev, "Failed to initialize device: %d\n", 167704e49867SJeff LaBundy error); 167804e49867SJeff LaBundy return error; 167904e49867SJeff LaBundy } 168004e49867SJeff LaBundy 168104e49867SJeff LaBundy error = iqs269_input_init(iqs269); 168204e49867SJeff LaBundy if (error) 168304e49867SJeff LaBundy return error; 168404e49867SJeff LaBundy 168504e49867SJeff LaBundy error = devm_request_threaded_irq(&client->dev, client->irq, 168604e49867SJeff LaBundy NULL, iqs269_irq, IRQF_ONESHOT, 168704e49867SJeff LaBundy client->name, iqs269); 168804e49867SJeff LaBundy if (error) { 168904e49867SJeff LaBundy dev_err(&client->dev, "Failed to request IRQ: %d\n", error); 169004e49867SJeff LaBundy return error; 169104e49867SJeff LaBundy } 169204e49867SJeff LaBundy 169304e49867SJeff LaBundy error = devm_device_add_group(&client->dev, &iqs269_attr_group); 169404e49867SJeff LaBundy if (error) 169504e49867SJeff LaBundy dev_err(&client->dev, "Failed to add attributes: %d\n", error); 169604e49867SJeff LaBundy 169704e49867SJeff LaBundy return error; 169804e49867SJeff LaBundy } 169904e49867SJeff LaBundy 170004e49867SJeff LaBundy static int __maybe_unused iqs269_suspend(struct device *dev) 170104e49867SJeff LaBundy { 170204e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 170304e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 170404e49867SJeff LaBundy unsigned int val; 170504e49867SJeff LaBundy int error; 170604e49867SJeff LaBundy 170704e49867SJeff LaBundy if (!iqs269->suspend_mode) 170804e49867SJeff LaBundy return 0; 170904e49867SJeff LaBundy 171004e49867SJeff LaBundy disable_irq(client->irq); 171104e49867SJeff LaBundy 171204e49867SJeff LaBundy /* 171304e49867SJeff LaBundy * Automatic power mode switching must be disabled before the device is 171404e49867SJeff LaBundy * forced into any particular power mode. In this case, the device will 171504e49867SJeff LaBundy * transition into normal-power mode. 171604e49867SJeff LaBundy */ 171704e49867SJeff LaBundy error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS, 171804e49867SJeff LaBundy IQS269_SYS_SETTINGS_DIS_AUTO, ~0); 171904e49867SJeff LaBundy if (error) 172004e49867SJeff LaBundy goto err_irq; 172104e49867SJeff LaBundy 172204e49867SJeff LaBundy /* 172304e49867SJeff LaBundy * The following check ensures the device has completed its transition 172404e49867SJeff LaBundy * into normal-power mode before a manual mode switch is performed. 172504e49867SJeff LaBundy */ 172604e49867SJeff LaBundy error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val, 172704e49867SJeff LaBundy !(val & IQS269_SYS_FLAGS_PWR_MODE_MASK), 172804e49867SJeff LaBundy IQS269_PWR_MODE_POLL_SLEEP_US, 172904e49867SJeff LaBundy IQS269_PWR_MODE_POLL_TIMEOUT_US); 173004e49867SJeff LaBundy if (error) 173104e49867SJeff LaBundy goto err_irq; 173204e49867SJeff LaBundy 173304e49867SJeff LaBundy error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS, 173404e49867SJeff LaBundy IQS269_SYS_SETTINGS_PWR_MODE_MASK, 173504e49867SJeff LaBundy iqs269->suspend_mode << 173604e49867SJeff LaBundy IQS269_SYS_SETTINGS_PWR_MODE_SHIFT); 173704e49867SJeff LaBundy if (error) 173804e49867SJeff LaBundy goto err_irq; 173904e49867SJeff LaBundy 174004e49867SJeff LaBundy /* 174104e49867SJeff LaBundy * This last check ensures the device has completed its transition into 174204e49867SJeff LaBundy * the desired power mode to prevent any spurious interrupts from being 174304e49867SJeff LaBundy * triggered after iqs269_suspend has already returned. 174404e49867SJeff LaBundy */ 174504e49867SJeff LaBundy error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val, 174604e49867SJeff LaBundy (val & IQS269_SYS_FLAGS_PWR_MODE_MASK) 174704e49867SJeff LaBundy == (iqs269->suspend_mode << 174804e49867SJeff LaBundy IQS269_SYS_FLAGS_PWR_MODE_SHIFT), 174904e49867SJeff LaBundy IQS269_PWR_MODE_POLL_SLEEP_US, 175004e49867SJeff LaBundy IQS269_PWR_MODE_POLL_TIMEOUT_US); 175104e49867SJeff LaBundy 175204e49867SJeff LaBundy err_irq: 175304e49867SJeff LaBundy iqs269_irq_wait(); 175404e49867SJeff LaBundy enable_irq(client->irq); 175504e49867SJeff LaBundy 175604e49867SJeff LaBundy return error; 175704e49867SJeff LaBundy } 175804e49867SJeff LaBundy 175904e49867SJeff LaBundy static int __maybe_unused iqs269_resume(struct device *dev) 176004e49867SJeff LaBundy { 176104e49867SJeff LaBundy struct iqs269_private *iqs269 = dev_get_drvdata(dev); 176204e49867SJeff LaBundy struct i2c_client *client = iqs269->client; 176304e49867SJeff LaBundy unsigned int val; 176404e49867SJeff LaBundy int error; 176504e49867SJeff LaBundy 176604e49867SJeff LaBundy if (!iqs269->suspend_mode) 176704e49867SJeff LaBundy return 0; 176804e49867SJeff LaBundy 176904e49867SJeff LaBundy disable_irq(client->irq); 177004e49867SJeff LaBundy 177104e49867SJeff LaBundy error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS, 177204e49867SJeff LaBundy IQS269_SYS_SETTINGS_PWR_MODE_MASK, 0); 177304e49867SJeff LaBundy if (error) 177404e49867SJeff LaBundy goto err_irq; 177504e49867SJeff LaBundy 177604e49867SJeff LaBundy /* 177704e49867SJeff LaBundy * This check ensures the device has returned to normal-power mode 177804e49867SJeff LaBundy * before automatic power mode switching is re-enabled. 177904e49867SJeff LaBundy */ 178004e49867SJeff LaBundy error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val, 178104e49867SJeff LaBundy !(val & IQS269_SYS_FLAGS_PWR_MODE_MASK), 178204e49867SJeff LaBundy IQS269_PWR_MODE_POLL_SLEEP_US, 178304e49867SJeff LaBundy IQS269_PWR_MODE_POLL_TIMEOUT_US); 178404e49867SJeff LaBundy if (error) 178504e49867SJeff LaBundy goto err_irq; 178604e49867SJeff LaBundy 178704e49867SJeff LaBundy error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS, 178804e49867SJeff LaBundy IQS269_SYS_SETTINGS_DIS_AUTO, 0); 178904e49867SJeff LaBundy if (error) 179004e49867SJeff LaBundy goto err_irq; 179104e49867SJeff LaBundy 179204e49867SJeff LaBundy /* 179304e49867SJeff LaBundy * This step reports any events that may have been "swallowed" as a 179404e49867SJeff LaBundy * result of polling PWR_MODE (which automatically acknowledges any 179504e49867SJeff LaBundy * pending interrupts). 179604e49867SJeff LaBundy */ 179704e49867SJeff LaBundy error = iqs269_report(iqs269); 179804e49867SJeff LaBundy 179904e49867SJeff LaBundy err_irq: 180004e49867SJeff LaBundy iqs269_irq_wait(); 180104e49867SJeff LaBundy enable_irq(client->irq); 180204e49867SJeff LaBundy 180304e49867SJeff LaBundy return error; 180404e49867SJeff LaBundy } 180504e49867SJeff LaBundy 180604e49867SJeff LaBundy static SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume); 180704e49867SJeff LaBundy 180804e49867SJeff LaBundy static const struct of_device_id iqs269_of_match[] = { 180904e49867SJeff LaBundy { .compatible = "azoteq,iqs269a" }, 181004e49867SJeff LaBundy { } 181104e49867SJeff LaBundy }; 181204e49867SJeff LaBundy MODULE_DEVICE_TABLE(of, iqs269_of_match); 181304e49867SJeff LaBundy 181404e49867SJeff LaBundy static struct i2c_driver iqs269_i2c_driver = { 181504e49867SJeff LaBundy .driver = { 181604e49867SJeff LaBundy .name = "iqs269a", 181704e49867SJeff LaBundy .of_match_table = iqs269_of_match, 181804e49867SJeff LaBundy .pm = &iqs269_pm, 181904e49867SJeff LaBundy }, 182004e49867SJeff LaBundy .probe_new = iqs269_probe, 182104e49867SJeff LaBundy }; 182204e49867SJeff LaBundy module_i2c_driver(iqs269_i2c_driver); 182304e49867SJeff LaBundy 182404e49867SJeff LaBundy MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); 182504e49867SJeff LaBundy MODULE_DESCRIPTION("Azoteq IQS269A Capacitive Touch Controller"); 182604e49867SJeff LaBundy MODULE_LICENSE("GPL"); 1827