18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Azoteq IQS269A Capacitive Touch Controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Jeff LaBundy <jeff@labundy.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This driver registers up to 3 input devices: one representing capacitive or 88c2ecf20Sopenharmony_ci * inductive keys as well as Hall-effect switches, and one for each of the two 98c2ecf20Sopenharmony_ci * axial sliders presented by the device. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/completion.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/device.h> 158c2ecf20Sopenharmony_ci#include <linux/err.h> 168c2ecf20Sopenharmony_ci#include <linux/i2c.h> 178c2ecf20Sopenharmony_ci#include <linux/input.h> 188c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/mutex.h> 228c2ecf20Sopenharmony_ci#include <linux/of_device.h> 238c2ecf20Sopenharmony_ci#include <linux/property.h> 248c2ecf20Sopenharmony_ci#include <linux/regmap.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define IQS269_VER_INFO 0x00 288c2ecf20Sopenharmony_ci#define IQS269_VER_INFO_PROD_NUM 0x4F 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define IQS269_SYS_FLAGS 0x02 318c2ecf20Sopenharmony_ci#define IQS269_SYS_FLAGS_SHOW_RESET BIT(15) 328c2ecf20Sopenharmony_ci#define IQS269_SYS_FLAGS_PWR_MODE_MASK GENMASK(12, 11) 338c2ecf20Sopenharmony_ci#define IQS269_SYS_FLAGS_PWR_MODE_SHIFT 11 348c2ecf20Sopenharmony_ci#define IQS269_SYS_FLAGS_IN_ATI BIT(10) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define IQS269_CHx_COUNTS 0x08 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define IQS269_SLIDER_X 0x30 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define IQS269_CAL_DATA_A 0x35 418c2ecf20Sopenharmony_ci#define IQS269_CAL_DATA_A_HALL_BIN_L_MASK GENMASK(15, 12) 428c2ecf20Sopenharmony_ci#define IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT 12 438c2ecf20Sopenharmony_ci#define IQS269_CAL_DATA_A_HALL_BIN_R_MASK GENMASK(11, 8) 448c2ecf20Sopenharmony_ci#define IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT 8 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS 0x80 478c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_CLK_DIV BIT(15) 488c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_ULP_AUTO BIT(14) 498c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_DIS_AUTO BIT(13) 508c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_PWR_MODE_MASK GENMASK(12, 11) 518c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_PWR_MODE_SHIFT 11 528c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_PWR_MODE_MAX 3 538c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_ULP_UPDATE_MASK GENMASK(10, 8) 548c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT 8 558c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_ULP_UPDATE_MAX 7 568c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_RESEED_OFFSET BIT(6) 578c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_EVENT_MODE BIT(5) 588c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_EVENT_MODE_LP BIT(4) 598c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_REDO_ATI BIT(2) 608c2ecf20Sopenharmony_ci#define IQS269_SYS_SETTINGS_ACK_RESET BIT(0) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define IQS269_FILT_STR_LP_LTA_MASK GENMASK(7, 6) 638c2ecf20Sopenharmony_ci#define IQS269_FILT_STR_LP_LTA_SHIFT 6 648c2ecf20Sopenharmony_ci#define IQS269_FILT_STR_LP_CNT_MASK GENMASK(5, 4) 658c2ecf20Sopenharmony_ci#define IQS269_FILT_STR_LP_CNT_SHIFT 4 668c2ecf20Sopenharmony_ci#define IQS269_FILT_STR_NP_LTA_MASK GENMASK(3, 2) 678c2ecf20Sopenharmony_ci#define IQS269_FILT_STR_NP_LTA_SHIFT 2 688c2ecf20Sopenharmony_ci#define IQS269_FILT_STR_NP_CNT_MASK GENMASK(1, 0) 698c2ecf20Sopenharmony_ci#define IQS269_FILT_STR_MAX 3 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define IQS269_EVENT_MASK_SYS BIT(6) 728c2ecf20Sopenharmony_ci#define IQS269_EVENT_MASK_DEEP BIT(2) 738c2ecf20Sopenharmony_ci#define IQS269_EVENT_MASK_TOUCH BIT(1) 748c2ecf20Sopenharmony_ci#define IQS269_EVENT_MASK_PROX BIT(0) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define IQS269_RATE_NP_MS_MAX 255 778c2ecf20Sopenharmony_ci#define IQS269_RATE_LP_MS_MAX 255 788c2ecf20Sopenharmony_ci#define IQS269_RATE_ULP_MS_MAX 4080 798c2ecf20Sopenharmony_ci#define IQS269_TIMEOUT_PWR_MS_MAX 130560 808c2ecf20Sopenharmony_ci#define IQS269_TIMEOUT_LTA_MS_MAX 130560 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define IQS269_MISC_A_ATI_BAND_DISABLE BIT(15) 838c2ecf20Sopenharmony_ci#define IQS269_MISC_A_ATI_LP_ONLY BIT(14) 848c2ecf20Sopenharmony_ci#define IQS269_MISC_A_ATI_BAND_TIGHTEN BIT(13) 858c2ecf20Sopenharmony_ci#define IQS269_MISC_A_FILT_DISABLE BIT(12) 868c2ecf20Sopenharmony_ci#define IQS269_MISC_A_GPIO3_SELECT_MASK GENMASK(10, 8) 878c2ecf20Sopenharmony_ci#define IQS269_MISC_A_GPIO3_SELECT_SHIFT 8 888c2ecf20Sopenharmony_ci#define IQS269_MISC_A_DUAL_DIR BIT(6) 898c2ecf20Sopenharmony_ci#define IQS269_MISC_A_TX_FREQ_MASK GENMASK(5, 4) 908c2ecf20Sopenharmony_ci#define IQS269_MISC_A_TX_FREQ_SHIFT 4 918c2ecf20Sopenharmony_ci#define IQS269_MISC_A_TX_FREQ_MAX 3 928c2ecf20Sopenharmony_ci#define IQS269_MISC_A_GLOBAL_CAP_SIZE BIT(0) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define IQS269_MISC_B_RESEED_UI_SEL_MASK GENMASK(7, 6) 958c2ecf20Sopenharmony_ci#define IQS269_MISC_B_RESEED_UI_SEL_SHIFT 6 968c2ecf20Sopenharmony_ci#define IQS269_MISC_B_RESEED_UI_SEL_MAX 3 978c2ecf20Sopenharmony_ci#define IQS269_MISC_B_TRACKING_UI_ENABLE BIT(4) 988c2ecf20Sopenharmony_ci#define IQS269_MISC_B_FILT_STR_SLIDER GENMASK(1, 0) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_MEAS_CAP_SIZE BIT(15) 1018c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_RX_GND_INACTIVE BIT(13) 1028c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE BIT(12) 1038c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_ATI_MODE_MASK GENMASK(9, 8) 1048c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_ATI_MODE_SHIFT 8 1058c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_ATI_MODE_MAX 3 1068c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_INV_LOGIC BIT(7) 1078c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_PROJ_BIAS_MASK GENMASK(6, 5) 1088c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT 5 1098c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_PROJ_BIAS_MAX 3 1108c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_SENSE_MODE_MASK GENMASK(3, 0) 1118c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_A_SENSE_MODE_MAX 15 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE BIT(13) 1148c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_SENSE_FREQ_MASK GENMASK(10, 9) 1158c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT 9 1168c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_SENSE_FREQ_MAX 3 1178c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_STATIC_ENABLE BIT(8) 1188c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_MASK GENMASK(7, 6) 1198c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_75 0x00 1208c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_100 0x40 1218c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_150 0x80 1228c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_BASE_200 0xC0 1238c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_TARGET_MASK GENMASK(5, 0) 1248c2ecf20Sopenharmony_ci#define IQS269_CHx_ENG_B_ATI_TARGET_MAX 2016 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#define IQS269_CHx_WEIGHT_MAX 255 1278c2ecf20Sopenharmony_ci#define IQS269_CHx_THRESH_MAX 255 1288c2ecf20Sopenharmony_ci#define IQS269_CHx_HYST_DEEP_MASK GENMASK(7, 4) 1298c2ecf20Sopenharmony_ci#define IQS269_CHx_HYST_DEEP_SHIFT 4 1308c2ecf20Sopenharmony_ci#define IQS269_CHx_HYST_TOUCH_MASK GENMASK(3, 0) 1318c2ecf20Sopenharmony_ci#define IQS269_CHx_HYST_MAX 15 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define IQS269_CHx_HALL_INACTIVE 6 1348c2ecf20Sopenharmony_ci#define IQS269_CHx_HALL_ACTIVE 7 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#define IQS269_HALL_PAD_R BIT(0) 1378c2ecf20Sopenharmony_ci#define IQS269_HALL_PAD_L BIT(1) 1388c2ecf20Sopenharmony_ci#define IQS269_HALL_PAD_INV BIT(6) 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci#define IQS269_HALL_UI 0xF5 1418c2ecf20Sopenharmony_ci#define IQS269_HALL_UI_ENABLE BIT(15) 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#define IQS269_MAX_REG 0xFF 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define IQS269_NUM_CH 8 1468c2ecf20Sopenharmony_ci#define IQS269_NUM_SL 2 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define iqs269_irq_wait() usleep_range(200, 250) 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cienum iqs269_local_cap_size { 1518c2ecf20Sopenharmony_ci IQS269_LOCAL_CAP_SIZE_0, 1528c2ecf20Sopenharmony_ci IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY, 1538c2ecf20Sopenharmony_ci IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5, 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cienum iqs269_st_offs { 1578c2ecf20Sopenharmony_ci IQS269_ST_OFFS_PROX, 1588c2ecf20Sopenharmony_ci IQS269_ST_OFFS_DIR, 1598c2ecf20Sopenharmony_ci IQS269_ST_OFFS_TOUCH, 1608c2ecf20Sopenharmony_ci IQS269_ST_OFFS_DEEP, 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cienum iqs269_th_offs { 1648c2ecf20Sopenharmony_ci IQS269_TH_OFFS_PROX, 1658c2ecf20Sopenharmony_ci IQS269_TH_OFFS_TOUCH, 1668c2ecf20Sopenharmony_ci IQS269_TH_OFFS_DEEP, 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cienum iqs269_event_id { 1708c2ecf20Sopenharmony_ci IQS269_EVENT_PROX_DN, 1718c2ecf20Sopenharmony_ci IQS269_EVENT_PROX_UP, 1728c2ecf20Sopenharmony_ci IQS269_EVENT_TOUCH_DN, 1738c2ecf20Sopenharmony_ci IQS269_EVENT_TOUCH_UP, 1748c2ecf20Sopenharmony_ci IQS269_EVENT_DEEP_DN, 1758c2ecf20Sopenharmony_ci IQS269_EVENT_DEEP_UP, 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistruct iqs269_switch_desc { 1798c2ecf20Sopenharmony_ci unsigned int code; 1808c2ecf20Sopenharmony_ci bool enabled; 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistruct iqs269_event_desc { 1848c2ecf20Sopenharmony_ci const char *name; 1858c2ecf20Sopenharmony_ci enum iqs269_st_offs st_offs; 1868c2ecf20Sopenharmony_ci enum iqs269_th_offs th_offs; 1878c2ecf20Sopenharmony_ci bool dir_up; 1888c2ecf20Sopenharmony_ci u8 mask; 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic const struct iqs269_event_desc iqs269_events[] = { 1928c2ecf20Sopenharmony_ci [IQS269_EVENT_PROX_DN] = { 1938c2ecf20Sopenharmony_ci .name = "event-prox", 1948c2ecf20Sopenharmony_ci .st_offs = IQS269_ST_OFFS_PROX, 1958c2ecf20Sopenharmony_ci .th_offs = IQS269_TH_OFFS_PROX, 1968c2ecf20Sopenharmony_ci .mask = IQS269_EVENT_MASK_PROX, 1978c2ecf20Sopenharmony_ci }, 1988c2ecf20Sopenharmony_ci [IQS269_EVENT_PROX_UP] = { 1998c2ecf20Sopenharmony_ci .name = "event-prox-alt", 2008c2ecf20Sopenharmony_ci .st_offs = IQS269_ST_OFFS_PROX, 2018c2ecf20Sopenharmony_ci .th_offs = IQS269_TH_OFFS_PROX, 2028c2ecf20Sopenharmony_ci .dir_up = true, 2038c2ecf20Sopenharmony_ci .mask = IQS269_EVENT_MASK_PROX, 2048c2ecf20Sopenharmony_ci }, 2058c2ecf20Sopenharmony_ci [IQS269_EVENT_TOUCH_DN] = { 2068c2ecf20Sopenharmony_ci .name = "event-touch", 2078c2ecf20Sopenharmony_ci .st_offs = IQS269_ST_OFFS_TOUCH, 2088c2ecf20Sopenharmony_ci .th_offs = IQS269_TH_OFFS_TOUCH, 2098c2ecf20Sopenharmony_ci .mask = IQS269_EVENT_MASK_TOUCH, 2108c2ecf20Sopenharmony_ci }, 2118c2ecf20Sopenharmony_ci [IQS269_EVENT_TOUCH_UP] = { 2128c2ecf20Sopenharmony_ci .name = "event-touch-alt", 2138c2ecf20Sopenharmony_ci .st_offs = IQS269_ST_OFFS_TOUCH, 2148c2ecf20Sopenharmony_ci .th_offs = IQS269_TH_OFFS_TOUCH, 2158c2ecf20Sopenharmony_ci .dir_up = true, 2168c2ecf20Sopenharmony_ci .mask = IQS269_EVENT_MASK_TOUCH, 2178c2ecf20Sopenharmony_ci }, 2188c2ecf20Sopenharmony_ci [IQS269_EVENT_DEEP_DN] = { 2198c2ecf20Sopenharmony_ci .name = "event-deep", 2208c2ecf20Sopenharmony_ci .st_offs = IQS269_ST_OFFS_DEEP, 2218c2ecf20Sopenharmony_ci .th_offs = IQS269_TH_OFFS_DEEP, 2228c2ecf20Sopenharmony_ci .mask = IQS269_EVENT_MASK_DEEP, 2238c2ecf20Sopenharmony_ci }, 2248c2ecf20Sopenharmony_ci [IQS269_EVENT_DEEP_UP] = { 2258c2ecf20Sopenharmony_ci .name = "event-deep-alt", 2268c2ecf20Sopenharmony_ci .st_offs = IQS269_ST_OFFS_DEEP, 2278c2ecf20Sopenharmony_ci .th_offs = IQS269_TH_OFFS_DEEP, 2288c2ecf20Sopenharmony_ci .dir_up = true, 2298c2ecf20Sopenharmony_ci .mask = IQS269_EVENT_MASK_DEEP, 2308c2ecf20Sopenharmony_ci }, 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistruct iqs269_ver_info { 2348c2ecf20Sopenharmony_ci u8 prod_num; 2358c2ecf20Sopenharmony_ci u8 sw_num; 2368c2ecf20Sopenharmony_ci u8 hw_num; 2378c2ecf20Sopenharmony_ci u8 padding; 2388c2ecf20Sopenharmony_ci} __packed; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistruct iqs269_ch_reg { 2418c2ecf20Sopenharmony_ci u8 rx_enable; 2428c2ecf20Sopenharmony_ci u8 tx_enable; 2438c2ecf20Sopenharmony_ci __be16 engine_a; 2448c2ecf20Sopenharmony_ci __be16 engine_b; 2458c2ecf20Sopenharmony_ci __be16 ati_comp; 2468c2ecf20Sopenharmony_ci u8 thresh[3]; 2478c2ecf20Sopenharmony_ci u8 hyst; 2488c2ecf20Sopenharmony_ci u8 assoc_select; 2498c2ecf20Sopenharmony_ci u8 assoc_weight; 2508c2ecf20Sopenharmony_ci} __packed; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistruct iqs269_sys_reg { 2538c2ecf20Sopenharmony_ci __be16 general; 2548c2ecf20Sopenharmony_ci u8 active; 2558c2ecf20Sopenharmony_ci u8 filter; 2568c2ecf20Sopenharmony_ci u8 reseed; 2578c2ecf20Sopenharmony_ci u8 event_mask; 2588c2ecf20Sopenharmony_ci u8 rate_np; 2598c2ecf20Sopenharmony_ci u8 rate_lp; 2608c2ecf20Sopenharmony_ci u8 rate_ulp; 2618c2ecf20Sopenharmony_ci u8 timeout_pwr; 2628c2ecf20Sopenharmony_ci u8 timeout_rdy; 2638c2ecf20Sopenharmony_ci u8 timeout_lta; 2648c2ecf20Sopenharmony_ci __be16 misc_a; 2658c2ecf20Sopenharmony_ci __be16 misc_b; 2668c2ecf20Sopenharmony_ci u8 blocking; 2678c2ecf20Sopenharmony_ci u8 padding; 2688c2ecf20Sopenharmony_ci u8 slider_select[IQS269_NUM_SL]; 2698c2ecf20Sopenharmony_ci u8 timeout_tap; 2708c2ecf20Sopenharmony_ci u8 timeout_swipe; 2718c2ecf20Sopenharmony_ci u8 thresh_swipe; 2728c2ecf20Sopenharmony_ci u8 redo_ati; 2738c2ecf20Sopenharmony_ci struct iqs269_ch_reg ch_reg[IQS269_NUM_CH]; 2748c2ecf20Sopenharmony_ci} __packed; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistruct iqs269_flags { 2778c2ecf20Sopenharmony_ci __be16 system; 2788c2ecf20Sopenharmony_ci u8 gesture; 2798c2ecf20Sopenharmony_ci u8 padding; 2808c2ecf20Sopenharmony_ci u8 states[4]; 2818c2ecf20Sopenharmony_ci} __packed; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistruct iqs269_private { 2848c2ecf20Sopenharmony_ci struct i2c_client *client; 2858c2ecf20Sopenharmony_ci struct regmap *regmap; 2868c2ecf20Sopenharmony_ci struct mutex lock; 2878c2ecf20Sopenharmony_ci struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)]; 2888c2ecf20Sopenharmony_ci struct iqs269_sys_reg sys_reg; 2898c2ecf20Sopenharmony_ci struct completion ati_done; 2908c2ecf20Sopenharmony_ci struct input_dev *keypad; 2918c2ecf20Sopenharmony_ci struct input_dev *slider[IQS269_NUM_SL]; 2928c2ecf20Sopenharmony_ci unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH]; 2938c2ecf20Sopenharmony_ci unsigned int ch_num; 2948c2ecf20Sopenharmony_ci bool hall_enable; 2958c2ecf20Sopenharmony_ci bool ati_current; 2968c2ecf20Sopenharmony_ci}; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int iqs269_ati_mode_set(struct iqs269_private *iqs269, 2998c2ecf20Sopenharmony_ci unsigned int ch_num, unsigned int mode) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 3028c2ecf20Sopenharmony_ci u16 engine_a; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (ch_num >= IQS269_NUM_CH) 3058c2ecf20Sopenharmony_ci return -EINVAL; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (mode > IQS269_CHx_ENG_A_ATI_MODE_MAX) 3088c2ecf20Sopenharmony_ci return -EINVAL; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci mutex_lock(&iqs269->lock); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci engine_a = be16_to_cpu(ch_reg[ch_num].engine_a); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci engine_a &= ~IQS269_CHx_ENG_A_ATI_MODE_MASK; 3158c2ecf20Sopenharmony_ci engine_a |= (mode << IQS269_CHx_ENG_A_ATI_MODE_SHIFT); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci ch_reg[ch_num].engine_a = cpu_to_be16(engine_a); 3188c2ecf20Sopenharmony_ci iqs269->ati_current = false; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci mutex_unlock(&iqs269->lock); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return 0; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int iqs269_ati_mode_get(struct iqs269_private *iqs269, 3268c2ecf20Sopenharmony_ci unsigned int ch_num, unsigned int *mode) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 3298c2ecf20Sopenharmony_ci u16 engine_a; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (ch_num >= IQS269_NUM_CH) 3328c2ecf20Sopenharmony_ci return -EINVAL; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci mutex_lock(&iqs269->lock); 3358c2ecf20Sopenharmony_ci engine_a = be16_to_cpu(ch_reg[ch_num].engine_a); 3368c2ecf20Sopenharmony_ci mutex_unlock(&iqs269->lock); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK; 3398c2ecf20Sopenharmony_ci *mode = (engine_a >> IQS269_CHx_ENG_A_ATI_MODE_SHIFT); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int iqs269_ati_base_set(struct iqs269_private *iqs269, 3458c2ecf20Sopenharmony_ci unsigned int ch_num, unsigned int base) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 3488c2ecf20Sopenharmony_ci u16 engine_b; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (ch_num >= IQS269_NUM_CH) 3518c2ecf20Sopenharmony_ci return -EINVAL; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci switch (base) { 3548c2ecf20Sopenharmony_ci case 75: 3558c2ecf20Sopenharmony_ci base = IQS269_CHx_ENG_B_ATI_BASE_75; 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci case 100: 3598c2ecf20Sopenharmony_ci base = IQS269_CHx_ENG_B_ATI_BASE_100; 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci case 150: 3638c2ecf20Sopenharmony_ci base = IQS269_CHx_ENG_B_ATI_BASE_150; 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci case 200: 3678c2ecf20Sopenharmony_ci base = IQS269_CHx_ENG_B_ATI_BASE_200; 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci default: 3718c2ecf20Sopenharmony_ci return -EINVAL; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci mutex_lock(&iqs269->lock); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci engine_b &= ~IQS269_CHx_ENG_B_ATI_BASE_MASK; 3798c2ecf20Sopenharmony_ci engine_b |= base; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ch_reg[ch_num].engine_b = cpu_to_be16(engine_b); 3828c2ecf20Sopenharmony_ci iqs269->ati_current = false; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci mutex_unlock(&iqs269->lock); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return 0; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int iqs269_ati_base_get(struct iqs269_private *iqs269, 3908c2ecf20Sopenharmony_ci unsigned int ch_num, unsigned int *base) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 3938c2ecf20Sopenharmony_ci u16 engine_b; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (ch_num >= IQS269_NUM_CH) 3968c2ecf20Sopenharmony_ci return -EINVAL; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci mutex_lock(&iqs269->lock); 3998c2ecf20Sopenharmony_ci engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); 4008c2ecf20Sopenharmony_ci mutex_unlock(&iqs269->lock); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) { 4038c2ecf20Sopenharmony_ci case IQS269_CHx_ENG_B_ATI_BASE_75: 4048c2ecf20Sopenharmony_ci *base = 75; 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci case IQS269_CHx_ENG_B_ATI_BASE_100: 4088c2ecf20Sopenharmony_ci *base = 100; 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci case IQS269_CHx_ENG_B_ATI_BASE_150: 4128c2ecf20Sopenharmony_ci *base = 150; 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci case IQS269_CHx_ENG_B_ATI_BASE_200: 4168c2ecf20Sopenharmony_ci *base = 200; 4178c2ecf20Sopenharmony_ci return 0; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci default: 4208c2ecf20Sopenharmony_ci return -EINVAL; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int iqs269_ati_target_set(struct iqs269_private *iqs269, 4258c2ecf20Sopenharmony_ci unsigned int ch_num, unsigned int target) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 4288c2ecf20Sopenharmony_ci u16 engine_b; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (ch_num >= IQS269_NUM_CH) 4318c2ecf20Sopenharmony_ci return -EINVAL; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (target > IQS269_CHx_ENG_B_ATI_TARGET_MAX) 4348c2ecf20Sopenharmony_ci return -EINVAL; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci mutex_lock(&iqs269->lock); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci engine_b &= ~IQS269_CHx_ENG_B_ATI_TARGET_MASK; 4418c2ecf20Sopenharmony_ci engine_b |= target / 32; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci ch_reg[ch_num].engine_b = cpu_to_be16(engine_b); 4448c2ecf20Sopenharmony_ci iqs269->ati_current = false; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci mutex_unlock(&iqs269->lock); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int iqs269_ati_target_get(struct iqs269_private *iqs269, 4528c2ecf20Sopenharmony_ci unsigned int ch_num, unsigned int *target) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 4558c2ecf20Sopenharmony_ci u16 engine_b; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (ch_num >= IQS269_NUM_CH) 4588c2ecf20Sopenharmony_ci return -EINVAL; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci mutex_lock(&iqs269->lock); 4618c2ecf20Sopenharmony_ci engine_b = be16_to_cpu(ch_reg[ch_num].engine_b); 4628c2ecf20Sopenharmony_ci mutex_unlock(&iqs269->lock); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci *target = (engine_b & IQS269_CHx_ENG_B_ATI_TARGET_MASK) * 32; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic int iqs269_parse_mask(const struct fwnode_handle *fwnode, 4708c2ecf20Sopenharmony_ci const char *propname, u8 *mask) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci unsigned int val[IQS269_NUM_CH]; 4738c2ecf20Sopenharmony_ci int count, error, i; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci count = fwnode_property_count_u32(fwnode, propname); 4768c2ecf20Sopenharmony_ci if (count < 0) 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (count > IQS269_NUM_CH) 4808c2ecf20Sopenharmony_ci return -EINVAL; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci error = fwnode_property_read_u32_array(fwnode, propname, val, count); 4838c2ecf20Sopenharmony_ci if (error) 4848c2ecf20Sopenharmony_ci return error; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci *mask = 0; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 4898c2ecf20Sopenharmony_ci if (val[i] >= IQS269_NUM_CH) 4908c2ecf20Sopenharmony_ci return -EINVAL; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci *mask |= BIT(val[i]); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic int iqs269_parse_chan(struct iqs269_private *iqs269, 4998c2ecf20Sopenharmony_ci const struct fwnode_handle *ch_node) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct i2c_client *client = iqs269->client; 5028c2ecf20Sopenharmony_ci struct fwnode_handle *ev_node; 5038c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg; 5048c2ecf20Sopenharmony_ci u16 engine_a, engine_b; 5058c2ecf20Sopenharmony_ci unsigned int reg, val; 5068c2ecf20Sopenharmony_ci int error, i; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci error = fwnode_property_read_u32(ch_node, "reg", ®); 5098c2ecf20Sopenharmony_ci if (error) { 5108c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to read channel number: %d\n", 5118c2ecf20Sopenharmony_ci error); 5128c2ecf20Sopenharmony_ci return error; 5138c2ecf20Sopenharmony_ci } else if (reg >= IQS269_NUM_CH) { 5148c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid channel number: %u\n", reg); 5158c2ecf20Sopenharmony_ci return -EINVAL; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci iqs269->sys_reg.active |= BIT(reg); 5198c2ecf20Sopenharmony_ci if (!fwnode_property_present(ch_node, "azoteq,reseed-disable")) 5208c2ecf20Sopenharmony_ci iqs269->sys_reg.reseed |= BIT(reg); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (fwnode_property_present(ch_node, "azoteq,blocking-enable")) 5238c2ecf20Sopenharmony_ci iqs269->sys_reg.blocking |= BIT(reg); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (fwnode_property_present(ch_node, "azoteq,slider0-select")) 5268c2ecf20Sopenharmony_ci iqs269->sys_reg.slider_select[0] |= BIT(reg); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (fwnode_property_present(ch_node, "azoteq,slider1-select")) 5298c2ecf20Sopenharmony_ci iqs269->sys_reg.slider_select[1] |= BIT(reg); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci ch_reg = &iqs269->sys_reg.ch_reg[reg]; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci error = iqs269_parse_mask(ch_node, "azoteq,rx-enable", 5348c2ecf20Sopenharmony_ci &ch_reg->rx_enable); 5358c2ecf20Sopenharmony_ci if (error) { 5368c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid channel %u RX enable mask: %d\n", 5378c2ecf20Sopenharmony_ci reg, error); 5388c2ecf20Sopenharmony_ci return error; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci error = iqs269_parse_mask(ch_node, "azoteq,tx-enable", 5428c2ecf20Sopenharmony_ci &ch_reg->tx_enable); 5438c2ecf20Sopenharmony_ci if (error) { 5448c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid channel %u TX enable mask: %d\n", 5458c2ecf20Sopenharmony_ci reg, error); 5468c2ecf20Sopenharmony_ci return error; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci engine_a = be16_to_cpu(ch_reg->engine_a); 5508c2ecf20Sopenharmony_ci engine_b = be16_to_cpu(ch_reg->engine_b); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci engine_a |= IQS269_CHx_ENG_A_MEAS_CAP_SIZE; 5538c2ecf20Sopenharmony_ci if (fwnode_property_present(ch_node, "azoteq,meas-cap-decrease")) 5548c2ecf20Sopenharmony_ci engine_a &= ~IQS269_CHx_ENG_A_MEAS_CAP_SIZE; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci engine_a |= IQS269_CHx_ENG_A_RX_GND_INACTIVE; 5578c2ecf20Sopenharmony_ci if (fwnode_property_present(ch_node, "azoteq,rx-float-inactive")) 5588c2ecf20Sopenharmony_ci engine_a &= ~IQS269_CHx_ENG_A_RX_GND_INACTIVE; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci engine_a &= ~IQS269_CHx_ENG_A_LOCAL_CAP_SIZE; 5618c2ecf20Sopenharmony_ci engine_b &= ~IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE; 5628c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ch_node, "azoteq,local-cap-size", &val)) { 5638c2ecf20Sopenharmony_ci switch (val) { 5648c2ecf20Sopenharmony_ci case IQS269_LOCAL_CAP_SIZE_0: 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci case IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5: 5688c2ecf20Sopenharmony_ci engine_a |= IQS269_CHx_ENG_A_LOCAL_CAP_SIZE; 5698c2ecf20Sopenharmony_ci fallthrough; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci case IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY: 5728c2ecf20Sopenharmony_ci engine_b |= IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE; 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci default: 5768c2ecf20Sopenharmony_ci dev_err(&client->dev, 5778c2ecf20Sopenharmony_ci "Invalid channel %u local cap. size: %u\n", reg, 5788c2ecf20Sopenharmony_ci val); 5798c2ecf20Sopenharmony_ci return -EINVAL; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci engine_a &= ~IQS269_CHx_ENG_A_INV_LOGIC; 5848c2ecf20Sopenharmony_ci if (fwnode_property_present(ch_node, "azoteq,invert-enable")) 5858c2ecf20Sopenharmony_ci engine_a |= IQS269_CHx_ENG_A_INV_LOGIC; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ch_node, "azoteq,proj-bias", &val)) { 5888c2ecf20Sopenharmony_ci if (val > IQS269_CHx_ENG_A_PROJ_BIAS_MAX) { 5898c2ecf20Sopenharmony_ci dev_err(&client->dev, 5908c2ecf20Sopenharmony_ci "Invalid channel %u bias current: %u\n", reg, 5918c2ecf20Sopenharmony_ci val); 5928c2ecf20Sopenharmony_ci return -EINVAL; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci engine_a &= ~IQS269_CHx_ENG_A_PROJ_BIAS_MASK; 5968c2ecf20Sopenharmony_ci engine_a |= (val << IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT); 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ch_node, "azoteq,sense-mode", &val)) { 6008c2ecf20Sopenharmony_ci if (val > IQS269_CHx_ENG_A_SENSE_MODE_MAX) { 6018c2ecf20Sopenharmony_ci dev_err(&client->dev, 6028c2ecf20Sopenharmony_ci "Invalid channel %u sensing mode: %u\n", reg, 6038c2ecf20Sopenharmony_ci val); 6048c2ecf20Sopenharmony_ci return -EINVAL; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci engine_a &= ~IQS269_CHx_ENG_A_SENSE_MODE_MASK; 6088c2ecf20Sopenharmony_ci engine_a |= val; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ch_node, "azoteq,sense-freq", &val)) { 6128c2ecf20Sopenharmony_ci if (val > IQS269_CHx_ENG_B_SENSE_FREQ_MAX) { 6138c2ecf20Sopenharmony_ci dev_err(&client->dev, 6148c2ecf20Sopenharmony_ci "Invalid channel %u sensing frequency: %u\n", 6158c2ecf20Sopenharmony_ci reg, val); 6168c2ecf20Sopenharmony_ci return -EINVAL; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci engine_b &= ~IQS269_CHx_ENG_B_SENSE_FREQ_MASK; 6208c2ecf20Sopenharmony_ci engine_b |= (val << IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci engine_b &= ~IQS269_CHx_ENG_B_STATIC_ENABLE; 6248c2ecf20Sopenharmony_ci if (fwnode_property_present(ch_node, "azoteq,static-enable")) 6258c2ecf20Sopenharmony_ci engine_b |= IQS269_CHx_ENG_B_STATIC_ENABLE; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci ch_reg->engine_a = cpu_to_be16(engine_a); 6288c2ecf20Sopenharmony_ci ch_reg->engine_b = cpu_to_be16(engine_b); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ch_node, "azoteq,ati-mode", &val)) { 6318c2ecf20Sopenharmony_ci error = iqs269_ati_mode_set(iqs269, reg, val); 6328c2ecf20Sopenharmony_ci if (error) { 6338c2ecf20Sopenharmony_ci dev_err(&client->dev, 6348c2ecf20Sopenharmony_ci "Invalid channel %u ATI mode: %u\n", reg, val); 6358c2ecf20Sopenharmony_ci return error; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ch_node, "azoteq,ati-base", &val)) { 6408c2ecf20Sopenharmony_ci error = iqs269_ati_base_set(iqs269, reg, val); 6418c2ecf20Sopenharmony_ci if (error) { 6428c2ecf20Sopenharmony_ci dev_err(&client->dev, 6438c2ecf20Sopenharmony_ci "Invalid channel %u ATI base: %u\n", reg, val); 6448c2ecf20Sopenharmony_ci return error; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ch_node, "azoteq,ati-target", &val)) { 6498c2ecf20Sopenharmony_ci error = iqs269_ati_target_set(iqs269, reg, val); 6508c2ecf20Sopenharmony_ci if (error) { 6518c2ecf20Sopenharmony_ci dev_err(&client->dev, 6528c2ecf20Sopenharmony_ci "Invalid channel %u ATI target: %u\n", reg, 6538c2ecf20Sopenharmony_ci val); 6548c2ecf20Sopenharmony_ci return error; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci error = iqs269_parse_mask(ch_node, "azoteq,assoc-select", 6598c2ecf20Sopenharmony_ci &ch_reg->assoc_select); 6608c2ecf20Sopenharmony_ci if (error) { 6618c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid channel %u association: %d\n", 6628c2ecf20Sopenharmony_ci reg, error); 6638c2ecf20Sopenharmony_ci return error; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ch_node, "azoteq,assoc-weight", &val)) { 6678c2ecf20Sopenharmony_ci if (val > IQS269_CHx_WEIGHT_MAX) { 6688c2ecf20Sopenharmony_ci dev_err(&client->dev, 6698c2ecf20Sopenharmony_ci "Invalid channel %u associated weight: %u\n", 6708c2ecf20Sopenharmony_ci reg, val); 6718c2ecf20Sopenharmony_ci return -EINVAL; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci ch_reg->assoc_weight = val; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { 6788c2ecf20Sopenharmony_ci ev_node = fwnode_get_named_child_node(ch_node, 6798c2ecf20Sopenharmony_ci iqs269_events[i].name); 6808c2ecf20Sopenharmony_ci if (!ev_node) 6818c2ecf20Sopenharmony_ci continue; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ev_node, "azoteq,thresh", &val)) { 6848c2ecf20Sopenharmony_ci if (val > IQS269_CHx_THRESH_MAX) { 6858c2ecf20Sopenharmony_ci dev_err(&client->dev, 6868c2ecf20Sopenharmony_ci "Invalid channel %u threshold: %u\n", 6878c2ecf20Sopenharmony_ci reg, val); 6888c2ecf20Sopenharmony_ci fwnode_handle_put(ev_node); 6898c2ecf20Sopenharmony_ci return -EINVAL; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci ch_reg->thresh[iqs269_events[i].th_offs] = val; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (!fwnode_property_read_u32(ev_node, "azoteq,hyst", &val)) { 6968c2ecf20Sopenharmony_ci u8 *hyst = &ch_reg->hyst; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (val > IQS269_CHx_HYST_MAX) { 6998c2ecf20Sopenharmony_ci dev_err(&client->dev, 7008c2ecf20Sopenharmony_ci "Invalid channel %u hysteresis: %u\n", 7018c2ecf20Sopenharmony_ci reg, val); 7028c2ecf20Sopenharmony_ci fwnode_handle_put(ev_node); 7038c2ecf20Sopenharmony_ci return -EINVAL; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (i == IQS269_EVENT_DEEP_DN || 7078c2ecf20Sopenharmony_ci i == IQS269_EVENT_DEEP_UP) { 7088c2ecf20Sopenharmony_ci *hyst &= ~IQS269_CHx_HYST_DEEP_MASK; 7098c2ecf20Sopenharmony_ci *hyst |= (val << IQS269_CHx_HYST_DEEP_SHIFT); 7108c2ecf20Sopenharmony_ci } else if (i == IQS269_EVENT_TOUCH_DN || 7118c2ecf20Sopenharmony_ci i == IQS269_EVENT_TOUCH_UP) { 7128c2ecf20Sopenharmony_ci *hyst &= ~IQS269_CHx_HYST_TOUCH_MASK; 7138c2ecf20Sopenharmony_ci *hyst |= val; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci error = fwnode_property_read_u32(ev_node, "linux,code", &val); 7188c2ecf20Sopenharmony_ci fwnode_handle_put(ev_node); 7198c2ecf20Sopenharmony_ci if (error == -EINVAL) { 7208c2ecf20Sopenharmony_ci continue; 7218c2ecf20Sopenharmony_ci } else if (error) { 7228c2ecf20Sopenharmony_ci dev_err(&client->dev, 7238c2ecf20Sopenharmony_ci "Failed to read channel %u code: %d\n", reg, 7248c2ecf20Sopenharmony_ci error); 7258c2ecf20Sopenharmony_ci return error; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci switch (reg) { 7298c2ecf20Sopenharmony_ci case IQS269_CHx_HALL_ACTIVE: 7308c2ecf20Sopenharmony_ci if (iqs269->hall_enable) { 7318c2ecf20Sopenharmony_ci iqs269->switches[i].code = val; 7328c2ecf20Sopenharmony_ci iqs269->switches[i].enabled = true; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci fallthrough; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci case IQS269_CHx_HALL_INACTIVE: 7378c2ecf20Sopenharmony_ci if (iqs269->hall_enable) 7388c2ecf20Sopenharmony_ci break; 7398c2ecf20Sopenharmony_ci fallthrough; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci default: 7428c2ecf20Sopenharmony_ci iqs269->keycode[i * IQS269_NUM_CH + reg] = val; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci iqs269->sys_reg.event_mask &= ~iqs269_events[i].mask; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return 0; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic int iqs269_parse_prop(struct iqs269_private *iqs269) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg; 7548c2ecf20Sopenharmony_ci struct i2c_client *client = iqs269->client; 7558c2ecf20Sopenharmony_ci struct fwnode_handle *ch_node; 7568c2ecf20Sopenharmony_ci u16 general, misc_a, misc_b; 7578c2ecf20Sopenharmony_ci unsigned int val; 7588c2ecf20Sopenharmony_ci int error; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci iqs269->hall_enable = device_property_present(&client->dev, 7618c2ecf20Sopenharmony_ci "azoteq,hall-enable"); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci error = regmap_raw_read(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg, 7648c2ecf20Sopenharmony_ci sizeof(*sys_reg)); 7658c2ecf20Sopenharmony_ci if (error) 7668c2ecf20Sopenharmony_ci return error; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-lta", 7698c2ecf20Sopenharmony_ci &val)) { 7708c2ecf20Sopenharmony_ci if (val > IQS269_FILT_STR_MAX) { 7718c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid filter strength: %u\n", 7728c2ecf20Sopenharmony_ci val); 7738c2ecf20Sopenharmony_ci return -EINVAL; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci sys_reg->filter &= ~IQS269_FILT_STR_LP_LTA_MASK; 7778c2ecf20Sopenharmony_ci sys_reg->filter |= (val << IQS269_FILT_STR_LP_LTA_SHIFT); 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-cnt", 7818c2ecf20Sopenharmony_ci &val)) { 7828c2ecf20Sopenharmony_ci if (val > IQS269_FILT_STR_MAX) { 7838c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid filter strength: %u\n", 7848c2ecf20Sopenharmony_ci val); 7858c2ecf20Sopenharmony_ci return -EINVAL; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci sys_reg->filter &= ~IQS269_FILT_STR_LP_CNT_MASK; 7898c2ecf20Sopenharmony_ci sys_reg->filter |= (val << IQS269_FILT_STR_LP_CNT_SHIFT); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-lta", 7938c2ecf20Sopenharmony_ci &val)) { 7948c2ecf20Sopenharmony_ci if (val > IQS269_FILT_STR_MAX) { 7958c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid filter strength: %u\n", 7968c2ecf20Sopenharmony_ci val); 7978c2ecf20Sopenharmony_ci return -EINVAL; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci sys_reg->filter &= ~IQS269_FILT_STR_NP_LTA_MASK; 8018c2ecf20Sopenharmony_ci sys_reg->filter |= (val << IQS269_FILT_STR_NP_LTA_SHIFT); 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-cnt", 8058c2ecf20Sopenharmony_ci &val)) { 8068c2ecf20Sopenharmony_ci if (val > IQS269_FILT_STR_MAX) { 8078c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid filter strength: %u\n", 8088c2ecf20Sopenharmony_ci val); 8098c2ecf20Sopenharmony_ci return -EINVAL; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci sys_reg->filter &= ~IQS269_FILT_STR_NP_CNT_MASK; 8138c2ecf20Sopenharmony_ci sys_reg->filter |= val; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,rate-np-ms", 8178c2ecf20Sopenharmony_ci &val)) { 8188c2ecf20Sopenharmony_ci if (val > IQS269_RATE_NP_MS_MAX) { 8198c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid report rate: %u\n", val); 8208c2ecf20Sopenharmony_ci return -EINVAL; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci sys_reg->rate_np = val; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,rate-lp-ms", 8278c2ecf20Sopenharmony_ci &val)) { 8288c2ecf20Sopenharmony_ci if (val > IQS269_RATE_LP_MS_MAX) { 8298c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid report rate: %u\n", val); 8308c2ecf20Sopenharmony_ci return -EINVAL; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci sys_reg->rate_lp = val; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,rate-ulp-ms", 8378c2ecf20Sopenharmony_ci &val)) { 8388c2ecf20Sopenharmony_ci if (val > IQS269_RATE_ULP_MS_MAX) { 8398c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid report rate: %u\n", val); 8408c2ecf20Sopenharmony_ci return -EINVAL; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci sys_reg->rate_ulp = val / 16; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,timeout-pwr-ms", 8478c2ecf20Sopenharmony_ci &val)) { 8488c2ecf20Sopenharmony_ci if (val > IQS269_TIMEOUT_PWR_MS_MAX) { 8498c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid timeout: %u\n", val); 8508c2ecf20Sopenharmony_ci return -EINVAL; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci sys_reg->timeout_pwr = val / 512; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,timeout-lta-ms", 8578c2ecf20Sopenharmony_ci &val)) { 8588c2ecf20Sopenharmony_ci if (val > IQS269_TIMEOUT_LTA_MS_MAX) { 8598c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid timeout: %u\n", val); 8608c2ecf20Sopenharmony_ci return -EINVAL; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci sys_reg->timeout_lta = val / 512; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci misc_a = be16_to_cpu(sys_reg->misc_a); 8678c2ecf20Sopenharmony_ci misc_b = be16_to_cpu(sys_reg->misc_b); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci misc_a &= ~IQS269_MISC_A_ATI_BAND_DISABLE; 8708c2ecf20Sopenharmony_ci if (device_property_present(&client->dev, "azoteq,ati-band-disable")) 8718c2ecf20Sopenharmony_ci misc_a |= IQS269_MISC_A_ATI_BAND_DISABLE; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci misc_a &= ~IQS269_MISC_A_ATI_LP_ONLY; 8748c2ecf20Sopenharmony_ci if (device_property_present(&client->dev, "azoteq,ati-lp-only")) 8758c2ecf20Sopenharmony_ci misc_a |= IQS269_MISC_A_ATI_LP_ONLY; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci misc_a &= ~IQS269_MISC_A_ATI_BAND_TIGHTEN; 8788c2ecf20Sopenharmony_ci if (device_property_present(&client->dev, "azoteq,ati-band-tighten")) 8798c2ecf20Sopenharmony_ci misc_a |= IQS269_MISC_A_ATI_BAND_TIGHTEN; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci misc_a &= ~IQS269_MISC_A_FILT_DISABLE; 8828c2ecf20Sopenharmony_ci if (device_property_present(&client->dev, "azoteq,filt-disable")) 8838c2ecf20Sopenharmony_ci misc_a |= IQS269_MISC_A_FILT_DISABLE; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,gpio3-select", 8868c2ecf20Sopenharmony_ci &val)) { 8878c2ecf20Sopenharmony_ci if (val >= IQS269_NUM_CH) { 8888c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid GPIO3 selection: %u\n", 8898c2ecf20Sopenharmony_ci val); 8908c2ecf20Sopenharmony_ci return -EINVAL; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci misc_a &= ~IQS269_MISC_A_GPIO3_SELECT_MASK; 8948c2ecf20Sopenharmony_ci misc_a |= (val << IQS269_MISC_A_GPIO3_SELECT_SHIFT); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci misc_a &= ~IQS269_MISC_A_DUAL_DIR; 8988c2ecf20Sopenharmony_ci if (device_property_present(&client->dev, "azoteq,dual-direction")) 8998c2ecf20Sopenharmony_ci misc_a |= IQS269_MISC_A_DUAL_DIR; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,tx-freq", &val)) { 9028c2ecf20Sopenharmony_ci if (val > IQS269_MISC_A_TX_FREQ_MAX) { 9038c2ecf20Sopenharmony_ci dev_err(&client->dev, 9048c2ecf20Sopenharmony_ci "Invalid excitation frequency: %u\n", val); 9058c2ecf20Sopenharmony_ci return -EINVAL; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci misc_a &= ~IQS269_MISC_A_TX_FREQ_MASK; 9098c2ecf20Sopenharmony_ci misc_a |= (val << IQS269_MISC_A_TX_FREQ_SHIFT); 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci misc_a &= ~IQS269_MISC_A_GLOBAL_CAP_SIZE; 9138c2ecf20Sopenharmony_ci if (device_property_present(&client->dev, "azoteq,global-cap-increase")) 9148c2ecf20Sopenharmony_ci misc_a |= IQS269_MISC_A_GLOBAL_CAP_SIZE; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,reseed-select", 9178c2ecf20Sopenharmony_ci &val)) { 9188c2ecf20Sopenharmony_ci if (val > IQS269_MISC_B_RESEED_UI_SEL_MAX) { 9198c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid reseed selection: %u\n", 9208c2ecf20Sopenharmony_ci val); 9218c2ecf20Sopenharmony_ci return -EINVAL; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci misc_b &= ~IQS269_MISC_B_RESEED_UI_SEL_MASK; 9258c2ecf20Sopenharmony_ci misc_b |= (val << IQS269_MISC_B_RESEED_UI_SEL_SHIFT); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci misc_b &= ~IQS269_MISC_B_TRACKING_UI_ENABLE; 9298c2ecf20Sopenharmony_ci if (device_property_present(&client->dev, "azoteq,tracking-enable")) 9308c2ecf20Sopenharmony_ci misc_b |= IQS269_MISC_B_TRACKING_UI_ENABLE; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,filt-str-slider", 9338c2ecf20Sopenharmony_ci &val)) { 9348c2ecf20Sopenharmony_ci if (val > IQS269_FILT_STR_MAX) { 9358c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid filter strength: %u\n", 9368c2ecf20Sopenharmony_ci val); 9378c2ecf20Sopenharmony_ci return -EINVAL; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci misc_b &= ~IQS269_MISC_B_FILT_STR_SLIDER; 9418c2ecf20Sopenharmony_ci misc_b |= val; 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci sys_reg->misc_a = cpu_to_be16(misc_a); 9458c2ecf20Sopenharmony_ci sys_reg->misc_b = cpu_to_be16(misc_b); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci sys_reg->active = 0; 9488c2ecf20Sopenharmony_ci sys_reg->reseed = 0; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci sys_reg->blocking = 0; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci sys_reg->slider_select[0] = 0; 9538c2ecf20Sopenharmony_ci sys_reg->slider_select[1] = 0; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci device_for_each_child_node(&client->dev, ch_node) { 9588c2ecf20Sopenharmony_ci error = iqs269_parse_chan(iqs269, ch_node); 9598c2ecf20Sopenharmony_ci if (error) { 9608c2ecf20Sopenharmony_ci fwnode_handle_put(ch_node); 9618c2ecf20Sopenharmony_ci return error; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* 9668c2ecf20Sopenharmony_ci * Volunteer all active channels to participate in ATI when REDO-ATI is 9678c2ecf20Sopenharmony_ci * manually triggered. 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_ci sys_reg->redo_ati = sys_reg->active; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci general = be16_to_cpu(sys_reg->general); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (device_property_present(&client->dev, "azoteq,clk-div")) 9748c2ecf20Sopenharmony_ci general |= IQS269_SYS_SETTINGS_CLK_DIV; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci /* 9778c2ecf20Sopenharmony_ci * Configure the device to automatically switch between normal and low- 9788c2ecf20Sopenharmony_ci * power modes as a function of sensing activity. Ultra-low-power mode, 9798c2ecf20Sopenharmony_ci * if enabled, is reserved for suspend. 9808c2ecf20Sopenharmony_ci */ 9818c2ecf20Sopenharmony_ci general &= ~IQS269_SYS_SETTINGS_ULP_AUTO; 9828c2ecf20Sopenharmony_ci general &= ~IQS269_SYS_SETTINGS_DIS_AUTO; 9838c2ecf20Sopenharmony_ci general &= ~IQS269_SYS_SETTINGS_PWR_MODE_MASK; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode", 9868c2ecf20Sopenharmony_ci &val)) { 9878c2ecf20Sopenharmony_ci if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) { 9888c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid suspend mode: %u\n", 9898c2ecf20Sopenharmony_ci val); 9908c2ecf20Sopenharmony_ci return -EINVAL; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci general |= (val << IQS269_SYS_SETTINGS_PWR_MODE_SHIFT); 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (!device_property_read_u32(&client->dev, "azoteq,ulp-update", 9978c2ecf20Sopenharmony_ci &val)) { 9988c2ecf20Sopenharmony_ci if (val > IQS269_SYS_SETTINGS_ULP_UPDATE_MAX) { 9998c2ecf20Sopenharmony_ci dev_err(&client->dev, "Invalid update rate: %u\n", val); 10008c2ecf20Sopenharmony_ci return -EINVAL; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci general &= ~IQS269_SYS_SETTINGS_ULP_UPDATE_MASK; 10048c2ecf20Sopenharmony_ci general |= (val << IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT); 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci general &= ~IQS269_SYS_SETTINGS_RESEED_OFFSET; 10088c2ecf20Sopenharmony_ci if (device_property_present(&client->dev, "azoteq,reseed-offset")) 10098c2ecf20Sopenharmony_ci general |= IQS269_SYS_SETTINGS_RESEED_OFFSET; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci general |= IQS269_SYS_SETTINGS_EVENT_MODE; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* 10148c2ecf20Sopenharmony_ci * As per the datasheet, enable streaming during normal-power mode if 10158c2ecf20Sopenharmony_ci * either slider is in use. In that case, the device returns to event 10168c2ecf20Sopenharmony_ci * mode during low-power mode. 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_ci if (sys_reg->slider_select[0] || sys_reg->slider_select[1]) 10198c2ecf20Sopenharmony_ci general |= IQS269_SYS_SETTINGS_EVENT_MODE_LP; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci general |= IQS269_SYS_SETTINGS_REDO_ATI; 10228c2ecf20Sopenharmony_ci general |= IQS269_SYS_SETTINGS_ACK_RESET; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci sys_reg->general = cpu_to_be16(general); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci return 0; 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic int iqs269_dev_init(struct iqs269_private *iqs269) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci int error; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci mutex_lock(&iqs269->lock); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI, 10368c2ecf20Sopenharmony_ci IQS269_HALL_UI_ENABLE, 10378c2ecf20Sopenharmony_ci iqs269->hall_enable ? ~0 : 0); 10388c2ecf20Sopenharmony_ci if (error) 10398c2ecf20Sopenharmony_ci goto err_mutex; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS, 10428c2ecf20Sopenharmony_ci &iqs269->sys_reg, sizeof(iqs269->sys_reg)); 10438c2ecf20Sopenharmony_ci if (error) 10448c2ecf20Sopenharmony_ci goto err_mutex; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* 10478c2ecf20Sopenharmony_ci * The following delay gives the device time to deassert its RDY output 10488c2ecf20Sopenharmony_ci * so as to prevent an interrupt from being serviced prematurely. 10498c2ecf20Sopenharmony_ci */ 10508c2ecf20Sopenharmony_ci usleep_range(2000, 2100); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci iqs269->ati_current = true; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cierr_mutex: 10558c2ecf20Sopenharmony_ci mutex_unlock(&iqs269->lock); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci return error; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic int iqs269_input_init(struct iqs269_private *iqs269) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct i2c_client *client = iqs269->client; 10638c2ecf20Sopenharmony_ci unsigned int sw_code, keycode; 10648c2ecf20Sopenharmony_ci int error, i, j; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci iqs269->keypad = devm_input_allocate_device(&client->dev); 10678c2ecf20Sopenharmony_ci if (!iqs269->keypad) 10688c2ecf20Sopenharmony_ci return -ENOMEM; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci iqs269->keypad->keycodemax = ARRAY_SIZE(iqs269->keycode); 10718c2ecf20Sopenharmony_ci iqs269->keypad->keycode = iqs269->keycode; 10728c2ecf20Sopenharmony_ci iqs269->keypad->keycodesize = sizeof(*iqs269->keycode); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci iqs269->keypad->name = "iqs269a_keypad"; 10758c2ecf20Sopenharmony_ci iqs269->keypad->id.bustype = BUS_I2C; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { 10788c2ecf20Sopenharmony_ci sw_code = iqs269->switches[i].code; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci for (j = 0; j < IQS269_NUM_CH; j++) { 10818c2ecf20Sopenharmony_ci keycode = iqs269->keycode[i * IQS269_NUM_CH + j]; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* 10848c2ecf20Sopenharmony_ci * Hall-effect sensing repurposes a pair of dedicated 10858c2ecf20Sopenharmony_ci * channels, only one of which reports events. 10868c2ecf20Sopenharmony_ci */ 10878c2ecf20Sopenharmony_ci switch (j) { 10888c2ecf20Sopenharmony_ci case IQS269_CHx_HALL_ACTIVE: 10898c2ecf20Sopenharmony_ci if (iqs269->hall_enable && 10908c2ecf20Sopenharmony_ci iqs269->switches[i].enabled) 10918c2ecf20Sopenharmony_ci input_set_capability(iqs269->keypad, 10928c2ecf20Sopenharmony_ci EV_SW, sw_code); 10938c2ecf20Sopenharmony_ci fallthrough; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci case IQS269_CHx_HALL_INACTIVE: 10968c2ecf20Sopenharmony_ci if (iqs269->hall_enable) 10978c2ecf20Sopenharmony_ci continue; 10988c2ecf20Sopenharmony_ci fallthrough; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci default: 11018c2ecf20Sopenharmony_ci if (keycode != KEY_RESERVED) 11028c2ecf20Sopenharmony_ci input_set_capability(iqs269->keypad, 11038c2ecf20Sopenharmony_ci EV_KEY, keycode); 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci for (i = 0; i < IQS269_NUM_SL; i++) { 11098c2ecf20Sopenharmony_ci if (!iqs269->sys_reg.slider_select[i]) 11108c2ecf20Sopenharmony_ci continue; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci iqs269->slider[i] = devm_input_allocate_device(&client->dev); 11138c2ecf20Sopenharmony_ci if (!iqs269->slider[i]) 11148c2ecf20Sopenharmony_ci return -ENOMEM; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci iqs269->slider[i]->name = i ? "iqs269a_slider_1" 11178c2ecf20Sopenharmony_ci : "iqs269a_slider_0"; 11188c2ecf20Sopenharmony_ci iqs269->slider[i]->id.bustype = BUS_I2C; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci input_set_capability(iqs269->slider[i], EV_KEY, BTN_TOUCH); 11218c2ecf20Sopenharmony_ci input_set_abs_params(iqs269->slider[i], ABS_X, 0, 255, 0, 0); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci error = input_register_device(iqs269->slider[i]); 11248c2ecf20Sopenharmony_ci if (error) { 11258c2ecf20Sopenharmony_ci dev_err(&client->dev, 11268c2ecf20Sopenharmony_ci "Failed to register slider %d: %d\n", i, error); 11278c2ecf20Sopenharmony_ci return error; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci return 0; 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic int iqs269_report(struct iqs269_private *iqs269) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci struct i2c_client *client = iqs269->client; 11378c2ecf20Sopenharmony_ci struct iqs269_flags flags; 11388c2ecf20Sopenharmony_ci unsigned int sw_code, keycode; 11398c2ecf20Sopenharmony_ci int error, i, j; 11408c2ecf20Sopenharmony_ci u8 slider_x[IQS269_NUM_SL]; 11418c2ecf20Sopenharmony_ci u8 dir_mask, state; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS, &flags, 11448c2ecf20Sopenharmony_ci sizeof(flags)); 11458c2ecf20Sopenharmony_ci if (error) { 11468c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to read device status: %d\n", 11478c2ecf20Sopenharmony_ci error); 11488c2ecf20Sopenharmony_ci return error; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci /* 11528c2ecf20Sopenharmony_ci * The device resets itself if its own watchdog bites, which can happen 11538c2ecf20Sopenharmony_ci * in the event of an I2C communication error. In this case, the device 11548c2ecf20Sopenharmony_ci * asserts a SHOW_RESET interrupt and all registers must be restored. 11558c2ecf20Sopenharmony_ci */ 11568c2ecf20Sopenharmony_ci if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_SHOW_RESET) { 11578c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unexpected device reset\n"); 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci error = iqs269_dev_init(iqs269); 11608c2ecf20Sopenharmony_ci if (error) 11618c2ecf20Sopenharmony_ci dev_err(&client->dev, 11628c2ecf20Sopenharmony_ci "Failed to re-initialize device: %d\n", error); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci return error; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_IN_ATI) 11688c2ecf20Sopenharmony_ci return 0; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X, slider_x, 11718c2ecf20Sopenharmony_ci sizeof(slider_x)); 11728c2ecf20Sopenharmony_ci if (error) { 11738c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to read slider position: %d\n", 11748c2ecf20Sopenharmony_ci error); 11758c2ecf20Sopenharmony_ci return error; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci for (i = 0; i < IQS269_NUM_SL; i++) { 11798c2ecf20Sopenharmony_ci if (!iqs269->sys_reg.slider_select[i]) 11808c2ecf20Sopenharmony_ci continue; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* 11838c2ecf20Sopenharmony_ci * Report BTN_TOUCH if any channel that participates in the 11848c2ecf20Sopenharmony_ci * slider is in a state of touch. 11858c2ecf20Sopenharmony_ci */ 11868c2ecf20Sopenharmony_ci if (flags.states[IQS269_ST_OFFS_TOUCH] & 11878c2ecf20Sopenharmony_ci iqs269->sys_reg.slider_select[i]) { 11888c2ecf20Sopenharmony_ci input_report_key(iqs269->slider[i], BTN_TOUCH, 1); 11898c2ecf20Sopenharmony_ci input_report_abs(iqs269->slider[i], ABS_X, slider_x[i]); 11908c2ecf20Sopenharmony_ci } else { 11918c2ecf20Sopenharmony_ci input_report_key(iqs269->slider[i], BTN_TOUCH, 0); 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci input_sync(iqs269->slider[i]); 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) { 11988c2ecf20Sopenharmony_ci dir_mask = flags.states[IQS269_ST_OFFS_DIR]; 11998c2ecf20Sopenharmony_ci if (!iqs269_events[i].dir_up) 12008c2ecf20Sopenharmony_ci dir_mask = ~dir_mask; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci state = flags.states[iqs269_events[i].st_offs] & dir_mask; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci sw_code = iqs269->switches[i].code; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci for (j = 0; j < IQS269_NUM_CH; j++) { 12078c2ecf20Sopenharmony_ci keycode = iqs269->keycode[i * IQS269_NUM_CH + j]; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci switch (j) { 12108c2ecf20Sopenharmony_ci case IQS269_CHx_HALL_ACTIVE: 12118c2ecf20Sopenharmony_ci if (iqs269->hall_enable && 12128c2ecf20Sopenharmony_ci iqs269->switches[i].enabled) 12138c2ecf20Sopenharmony_ci input_report_switch(iqs269->keypad, 12148c2ecf20Sopenharmony_ci sw_code, 12158c2ecf20Sopenharmony_ci state & BIT(j)); 12168c2ecf20Sopenharmony_ci fallthrough; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci case IQS269_CHx_HALL_INACTIVE: 12198c2ecf20Sopenharmony_ci if (iqs269->hall_enable) 12208c2ecf20Sopenharmony_ci continue; 12218c2ecf20Sopenharmony_ci fallthrough; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci default: 12248c2ecf20Sopenharmony_ci input_report_key(iqs269->keypad, keycode, 12258c2ecf20Sopenharmony_ci state & BIT(j)); 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci input_sync(iqs269->keypad); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci /* 12338c2ecf20Sopenharmony_ci * The following completion signals that ATI has finished, any initial 12348c2ecf20Sopenharmony_ci * switch states have been reported and the keypad can be registered. 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_ci complete_all(&iqs269->ati_done); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci return 0; 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cistatic irqreturn_t iqs269_irq(int irq, void *context) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = context; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci if (iqs269_report(iqs269)) 12468c2ecf20Sopenharmony_ci return IRQ_NONE; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci /* 12498c2ecf20Sopenharmony_ci * The device does not deassert its interrupt (RDY) pin until shortly 12508c2ecf20Sopenharmony_ci * after receiving an I2C stop condition; the following delay ensures 12518c2ecf20Sopenharmony_ci * the interrupt handler does not return before this time. 12528c2ecf20Sopenharmony_ci */ 12538c2ecf20Sopenharmony_ci iqs269_irq_wait(); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistatic ssize_t counts_show(struct device *dev, 12598c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 12628c2ecf20Sopenharmony_ci struct i2c_client *client = iqs269->client; 12638c2ecf20Sopenharmony_ci __le16 counts; 12648c2ecf20Sopenharmony_ci int error; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (!iqs269->ati_current || iqs269->hall_enable) 12678c2ecf20Sopenharmony_ci return -EPERM; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci if (!completion_done(&iqs269->ati_done)) 12708c2ecf20Sopenharmony_ci return -EBUSY; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci /* 12738c2ecf20Sopenharmony_ci * Unsolicited I2C communication prompts the device to assert its RDY 12748c2ecf20Sopenharmony_ci * pin, so disable the interrupt line until the operation is finished 12758c2ecf20Sopenharmony_ci * and RDY has been deasserted. 12768c2ecf20Sopenharmony_ci */ 12778c2ecf20Sopenharmony_ci disable_irq(client->irq); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci error = regmap_raw_read(iqs269->regmap, 12808c2ecf20Sopenharmony_ci IQS269_CHx_COUNTS + iqs269->ch_num * 2, 12818c2ecf20Sopenharmony_ci &counts, sizeof(counts)); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci iqs269_irq_wait(); 12848c2ecf20Sopenharmony_ci enable_irq(client->irq); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci if (error) 12878c2ecf20Sopenharmony_ci return error; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", le16_to_cpu(counts)); 12908c2ecf20Sopenharmony_ci} 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_cistatic ssize_t hall_bin_show(struct device *dev, 12938c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 12948c2ecf20Sopenharmony_ci{ 12958c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 12968c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 12978c2ecf20Sopenharmony_ci struct i2c_client *client = iqs269->client; 12988c2ecf20Sopenharmony_ci unsigned int val; 12998c2ecf20Sopenharmony_ci int error; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci disable_irq(client->irq); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci error = regmap_read(iqs269->regmap, IQS269_CAL_DATA_A, &val); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci iqs269_irq_wait(); 13068c2ecf20Sopenharmony_ci enable_irq(client->irq); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (error) 13098c2ecf20Sopenharmony_ci return error; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci switch (ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable & 13128c2ecf20Sopenharmony_ci ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) { 13138c2ecf20Sopenharmony_ci case IQS269_HALL_PAD_R: 13148c2ecf20Sopenharmony_ci val &= IQS269_CAL_DATA_A_HALL_BIN_R_MASK; 13158c2ecf20Sopenharmony_ci val >>= IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT; 13168c2ecf20Sopenharmony_ci break; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci case IQS269_HALL_PAD_L: 13198c2ecf20Sopenharmony_ci val &= IQS269_CAL_DATA_A_HALL_BIN_L_MASK; 13208c2ecf20Sopenharmony_ci val >>= IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT; 13218c2ecf20Sopenharmony_ci break; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci default: 13248c2ecf20Sopenharmony_ci return -EINVAL; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", val); 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_cistatic ssize_t hall_enable_show(struct device *dev, 13318c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->hall_enable); 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_cistatic ssize_t hall_enable_store(struct device *dev, 13398c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 13408c2ecf20Sopenharmony_ci size_t count) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 13438c2ecf20Sopenharmony_ci unsigned int val; 13448c2ecf20Sopenharmony_ci int error; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci error = kstrtouint(buf, 10, &val); 13478c2ecf20Sopenharmony_ci if (error) 13488c2ecf20Sopenharmony_ci return error; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci mutex_lock(&iqs269->lock); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci iqs269->hall_enable = val; 13538c2ecf20Sopenharmony_ci iqs269->ati_current = false; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci mutex_unlock(&iqs269->lock); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci return count; 13588c2ecf20Sopenharmony_ci} 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_cistatic ssize_t ch_number_show(struct device *dev, 13618c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ch_num); 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cistatic ssize_t ch_number_store(struct device *dev, 13698c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 13708c2ecf20Sopenharmony_ci size_t count) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 13738c2ecf20Sopenharmony_ci unsigned int val; 13748c2ecf20Sopenharmony_ci int error; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci error = kstrtouint(buf, 10, &val); 13778c2ecf20Sopenharmony_ci if (error) 13788c2ecf20Sopenharmony_ci return error; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (val >= IQS269_NUM_CH) 13818c2ecf20Sopenharmony_ci return -EINVAL; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci iqs269->ch_num = val; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci return count; 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_cistatic ssize_t rx_enable_show(struct device *dev, 13898c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 13928c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", 13958c2ecf20Sopenharmony_ci ch_reg[iqs269->ch_num].rx_enable); 13968c2ecf20Sopenharmony_ci} 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cistatic ssize_t rx_enable_store(struct device *dev, 13998c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 14008c2ecf20Sopenharmony_ci size_t count) 14018c2ecf20Sopenharmony_ci{ 14028c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 14038c2ecf20Sopenharmony_ci struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg; 14048c2ecf20Sopenharmony_ci unsigned int val; 14058c2ecf20Sopenharmony_ci int error; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci error = kstrtouint(buf, 10, &val); 14088c2ecf20Sopenharmony_ci if (error) 14098c2ecf20Sopenharmony_ci return error; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (val > 0xFF) 14128c2ecf20Sopenharmony_ci return -EINVAL; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci mutex_lock(&iqs269->lock); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci ch_reg[iqs269->ch_num].rx_enable = val; 14178c2ecf20Sopenharmony_ci iqs269->ati_current = false; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci mutex_unlock(&iqs269->lock); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci return count; 14228c2ecf20Sopenharmony_ci} 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_cistatic ssize_t ati_mode_show(struct device *dev, 14258c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 14288c2ecf20Sopenharmony_ci unsigned int val; 14298c2ecf20Sopenharmony_ci int error; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci error = iqs269_ati_mode_get(iqs269, iqs269->ch_num, &val); 14328c2ecf20Sopenharmony_ci if (error) 14338c2ecf20Sopenharmony_ci return error; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", val); 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic ssize_t ati_mode_store(struct device *dev, 14398c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 14408c2ecf20Sopenharmony_ci size_t count) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 14438c2ecf20Sopenharmony_ci unsigned int val; 14448c2ecf20Sopenharmony_ci int error; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci error = kstrtouint(buf, 10, &val); 14478c2ecf20Sopenharmony_ci if (error) 14488c2ecf20Sopenharmony_ci return error; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci error = iqs269_ati_mode_set(iqs269, iqs269->ch_num, val); 14518c2ecf20Sopenharmony_ci if (error) 14528c2ecf20Sopenharmony_ci return error; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci return count; 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic ssize_t ati_base_show(struct device *dev, 14588c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 14618c2ecf20Sopenharmony_ci unsigned int val; 14628c2ecf20Sopenharmony_ci int error; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci error = iqs269_ati_base_get(iqs269, iqs269->ch_num, &val); 14658c2ecf20Sopenharmony_ci if (error) 14668c2ecf20Sopenharmony_ci return error; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", val); 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_cistatic ssize_t ati_base_store(struct device *dev, 14728c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 14738c2ecf20Sopenharmony_ci size_t count) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 14768c2ecf20Sopenharmony_ci unsigned int val; 14778c2ecf20Sopenharmony_ci int error; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci error = kstrtouint(buf, 10, &val); 14808c2ecf20Sopenharmony_ci if (error) 14818c2ecf20Sopenharmony_ci return error; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci error = iqs269_ati_base_set(iqs269, iqs269->ch_num, val); 14848c2ecf20Sopenharmony_ci if (error) 14858c2ecf20Sopenharmony_ci return error; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci return count; 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cistatic ssize_t ati_target_show(struct device *dev, 14918c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 14948c2ecf20Sopenharmony_ci unsigned int val; 14958c2ecf20Sopenharmony_ci int error; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci error = iqs269_ati_target_get(iqs269, iqs269->ch_num, &val); 14988c2ecf20Sopenharmony_ci if (error) 14998c2ecf20Sopenharmony_ci return error; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", val); 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic ssize_t ati_target_store(struct device *dev, 15058c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 15068c2ecf20Sopenharmony_ci size_t count) 15078c2ecf20Sopenharmony_ci{ 15088c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 15098c2ecf20Sopenharmony_ci unsigned int val; 15108c2ecf20Sopenharmony_ci int error; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci error = kstrtouint(buf, 10, &val); 15138c2ecf20Sopenharmony_ci if (error) 15148c2ecf20Sopenharmony_ci return error; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci error = iqs269_ati_target_set(iqs269, iqs269->ch_num, val); 15178c2ecf20Sopenharmony_ci if (error) 15188c2ecf20Sopenharmony_ci return error; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci return count; 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_cistatic ssize_t ati_trigger_show(struct device *dev, 15248c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", 15298c2ecf20Sopenharmony_ci iqs269->ati_current && 15308c2ecf20Sopenharmony_ci completion_done(&iqs269->ati_done)); 15318c2ecf20Sopenharmony_ci} 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic ssize_t ati_trigger_store(struct device *dev, 15348c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 15358c2ecf20Sopenharmony_ci size_t count) 15368c2ecf20Sopenharmony_ci{ 15378c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 15388c2ecf20Sopenharmony_ci struct i2c_client *client = iqs269->client; 15398c2ecf20Sopenharmony_ci unsigned int val; 15408c2ecf20Sopenharmony_ci int error; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci error = kstrtouint(buf, 10, &val); 15438c2ecf20Sopenharmony_ci if (error) 15448c2ecf20Sopenharmony_ci return error; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci if (!val) 15478c2ecf20Sopenharmony_ci return count; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci disable_irq(client->irq); 15508c2ecf20Sopenharmony_ci reinit_completion(&iqs269->ati_done); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci error = iqs269_dev_init(iqs269); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci iqs269_irq_wait(); 15558c2ecf20Sopenharmony_ci enable_irq(client->irq); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci if (error) 15588c2ecf20Sopenharmony_ci return error; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&iqs269->ati_done, 15618c2ecf20Sopenharmony_ci msecs_to_jiffies(2000))) 15628c2ecf20Sopenharmony_ci return -ETIMEDOUT; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci return count; 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(counts); 15688c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(hall_bin); 15698c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(hall_enable); 15708c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(ch_number); 15718c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(rx_enable); 15728c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(ati_mode); 15738c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(ati_base); 15748c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(ati_target); 15758c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(ati_trigger); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic struct attribute *iqs269_attrs[] = { 15788c2ecf20Sopenharmony_ci &dev_attr_counts.attr, 15798c2ecf20Sopenharmony_ci &dev_attr_hall_bin.attr, 15808c2ecf20Sopenharmony_ci &dev_attr_hall_enable.attr, 15818c2ecf20Sopenharmony_ci &dev_attr_ch_number.attr, 15828c2ecf20Sopenharmony_ci &dev_attr_rx_enable.attr, 15838c2ecf20Sopenharmony_ci &dev_attr_ati_mode.attr, 15848c2ecf20Sopenharmony_ci &dev_attr_ati_base.attr, 15858c2ecf20Sopenharmony_ci &dev_attr_ati_target.attr, 15868c2ecf20Sopenharmony_ci &dev_attr_ati_trigger.attr, 15878c2ecf20Sopenharmony_ci NULL, 15888c2ecf20Sopenharmony_ci}; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_cistatic const struct attribute_group iqs269_attr_group = { 15918c2ecf20Sopenharmony_ci .attrs = iqs269_attrs, 15928c2ecf20Sopenharmony_ci}; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic const struct regmap_config iqs269_regmap_config = { 15958c2ecf20Sopenharmony_ci .reg_bits = 8, 15968c2ecf20Sopenharmony_ci .val_bits = 16, 15978c2ecf20Sopenharmony_ci .max_register = IQS269_MAX_REG, 15988c2ecf20Sopenharmony_ci}; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic int iqs269_probe(struct i2c_client *client) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci struct iqs269_ver_info ver_info; 16038c2ecf20Sopenharmony_ci struct iqs269_private *iqs269; 16048c2ecf20Sopenharmony_ci int error; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci iqs269 = devm_kzalloc(&client->dev, sizeof(*iqs269), GFP_KERNEL); 16078c2ecf20Sopenharmony_ci if (!iqs269) 16088c2ecf20Sopenharmony_ci return -ENOMEM; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci i2c_set_clientdata(client, iqs269); 16118c2ecf20Sopenharmony_ci iqs269->client = client; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci iqs269->regmap = devm_regmap_init_i2c(client, &iqs269_regmap_config); 16148c2ecf20Sopenharmony_ci if (IS_ERR(iqs269->regmap)) { 16158c2ecf20Sopenharmony_ci error = PTR_ERR(iqs269->regmap); 16168c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to initialize register map: %d\n", 16178c2ecf20Sopenharmony_ci error); 16188c2ecf20Sopenharmony_ci return error; 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci mutex_init(&iqs269->lock); 16228c2ecf20Sopenharmony_ci init_completion(&iqs269->ati_done); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO, &ver_info, 16258c2ecf20Sopenharmony_ci sizeof(ver_info)); 16268c2ecf20Sopenharmony_ci if (error) 16278c2ecf20Sopenharmony_ci return error; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci if (ver_info.prod_num != IQS269_VER_INFO_PROD_NUM) { 16308c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unrecognized product number: 0x%02X\n", 16318c2ecf20Sopenharmony_ci ver_info.prod_num); 16328c2ecf20Sopenharmony_ci return -EINVAL; 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci error = iqs269_parse_prop(iqs269); 16368c2ecf20Sopenharmony_ci if (error) 16378c2ecf20Sopenharmony_ci return error; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci error = iqs269_dev_init(iqs269); 16408c2ecf20Sopenharmony_ci if (error) { 16418c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to initialize device: %d\n", 16428c2ecf20Sopenharmony_ci error); 16438c2ecf20Sopenharmony_ci return error; 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci error = iqs269_input_init(iqs269); 16478c2ecf20Sopenharmony_ci if (error) 16488c2ecf20Sopenharmony_ci return error; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci error = devm_request_threaded_irq(&client->dev, client->irq, 16518c2ecf20Sopenharmony_ci NULL, iqs269_irq, IRQF_ONESHOT, 16528c2ecf20Sopenharmony_ci client->name, iqs269); 16538c2ecf20Sopenharmony_ci if (error) { 16548c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to request IRQ: %d\n", error); 16558c2ecf20Sopenharmony_ci return error; 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&iqs269->ati_done, 16598c2ecf20Sopenharmony_ci msecs_to_jiffies(2000))) { 16608c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to complete ATI\n"); 16618c2ecf20Sopenharmony_ci return -ETIMEDOUT; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci /* 16658c2ecf20Sopenharmony_ci * The keypad may include one or more switches and is not registered 16668c2ecf20Sopenharmony_ci * until ATI is complete and the initial switch states are read. 16678c2ecf20Sopenharmony_ci */ 16688c2ecf20Sopenharmony_ci error = input_register_device(iqs269->keypad); 16698c2ecf20Sopenharmony_ci if (error) { 16708c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to register keypad: %d\n", error); 16718c2ecf20Sopenharmony_ci return error; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci error = devm_device_add_group(&client->dev, &iqs269_attr_group); 16758c2ecf20Sopenharmony_ci if (error) 16768c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to add attributes: %d\n", error); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci return error; 16798c2ecf20Sopenharmony_ci} 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_cistatic u16 iqs269_general_get(struct iqs269_private *iqs269) 16828c2ecf20Sopenharmony_ci{ 16838c2ecf20Sopenharmony_ci u16 general = be16_to_cpu(iqs269->sys_reg.general); 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci general &= ~IQS269_SYS_SETTINGS_REDO_ATI; 16868c2ecf20Sopenharmony_ci general &= ~IQS269_SYS_SETTINGS_ACK_RESET; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci return general | IQS269_SYS_SETTINGS_DIS_AUTO; 16898c2ecf20Sopenharmony_ci} 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_cistatic int __maybe_unused iqs269_suspend(struct device *dev) 16928c2ecf20Sopenharmony_ci{ 16938c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 16948c2ecf20Sopenharmony_ci struct i2c_client *client = iqs269->client; 16958c2ecf20Sopenharmony_ci int error; 16968c2ecf20Sopenharmony_ci u16 general = iqs269_general_get(iqs269); 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK)) 16998c2ecf20Sopenharmony_ci return 0; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci disable_irq(client->irq); 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS, general); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci iqs269_irq_wait(); 17068c2ecf20Sopenharmony_ci enable_irq(client->irq); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci return error; 17098c2ecf20Sopenharmony_ci} 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_cistatic int __maybe_unused iqs269_resume(struct device *dev) 17128c2ecf20Sopenharmony_ci{ 17138c2ecf20Sopenharmony_ci struct iqs269_private *iqs269 = dev_get_drvdata(dev); 17148c2ecf20Sopenharmony_ci struct i2c_client *client = iqs269->client; 17158c2ecf20Sopenharmony_ci int error; 17168c2ecf20Sopenharmony_ci u16 general = iqs269_general_get(iqs269); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK)) 17198c2ecf20Sopenharmony_ci return 0; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci disable_irq(client->irq); 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS, 17248c2ecf20Sopenharmony_ci general & ~IQS269_SYS_SETTINGS_PWR_MODE_MASK); 17258c2ecf20Sopenharmony_ci if (!error) 17268c2ecf20Sopenharmony_ci error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS, 17278c2ecf20Sopenharmony_ci general & ~IQS269_SYS_SETTINGS_DIS_AUTO); 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci iqs269_irq_wait(); 17308c2ecf20Sopenharmony_ci enable_irq(client->irq); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci return error; 17338c2ecf20Sopenharmony_ci} 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume); 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_cistatic const struct of_device_id iqs269_of_match[] = { 17388c2ecf20Sopenharmony_ci { .compatible = "azoteq,iqs269a" }, 17398c2ecf20Sopenharmony_ci { } 17408c2ecf20Sopenharmony_ci}; 17418c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, iqs269_of_match); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_cistatic struct i2c_driver iqs269_i2c_driver = { 17448c2ecf20Sopenharmony_ci .driver = { 17458c2ecf20Sopenharmony_ci .name = "iqs269a", 17468c2ecf20Sopenharmony_ci .of_match_table = iqs269_of_match, 17478c2ecf20Sopenharmony_ci .pm = &iqs269_pm, 17488c2ecf20Sopenharmony_ci }, 17498c2ecf20Sopenharmony_ci .probe_new = iqs269_probe, 17508c2ecf20Sopenharmony_ci}; 17518c2ecf20Sopenharmony_cimodule_i2c_driver(iqs269_i2c_driver); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); 17548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Azoteq IQS269A Capacitive Touch Controller"); 17558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1756