Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Jeff LaBundy | 11450 | 100.00% | 2 | 100.00% |
Total | 11450 | 2 |
// SPDX-License-Identifier: GPL-2.0-or-later /* * Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller * * Copyright (C) 2023 Jeff LaBundy <jeff@labundy.com> */ #include <linux/bits.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/input.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> #include <linux/interrupt.h> #include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/property.h> #include <linux/slab.h> #include <asm/unaligned.h> #define IQS7211_PROD_NUM 0x00 #define IQS7211_EVENT_MASK_ALL GENMASK(14, 8) #define IQS7211_EVENT_MASK_ALP BIT(13) #define IQS7211_EVENT_MASK_BTN BIT(12) #define IQS7211_EVENT_MASK_ATI BIT(11) #define IQS7211_EVENT_MASK_MOVE BIT(10) #define IQS7211_EVENT_MASK_GSTR BIT(9) #define IQS7211_EVENT_MODE BIT(8) #define IQS7211_COMMS_ERROR 0xEEEE #define IQS7211_COMMS_RETRY_MS 50 #define IQS7211_COMMS_SLEEP_US 100 #define IQS7211_COMMS_TIMEOUT_US (100 * USEC_PER_MSEC) #define IQS7211_RESET_TIMEOUT_MS 150 #define IQS7211_START_TIMEOUT_US (1 * USEC_PER_SEC) #define IQS7211_NUM_RETRIES 5 #define IQS7211_NUM_CRX 8 #define IQS7211_MAX_CTX 13 #define IQS7211_MAX_CONTACTS 2 #define IQS7211_MAX_CYCLES 21 /* * The following delay is used during instances that must wait for the open- * drain RDY pin to settle. Its value is calculated as 5*R*C, where R and C * represent typical datasheet values of 4.7k and 100 nF, respectively. */ #define iqs7211_irq_wait() usleep_range(2500, 2600) enum iqs7211_dev_id { IQS7210A, IQS7211A, IQS7211E, }; enum iqs7211_comms_mode { IQS7211_COMMS_MODE_WAIT, IQS7211_COMMS_MODE_FREE, IQS7211_COMMS_MODE_FORCE, }; struct iqs7211_reg_field_desc { struct list_head list; u8 addr; u16 mask; u16 val; }; enum iqs7211_reg_key_id { IQS7211_REG_KEY_NONE, IQS7211_REG_KEY_PROX, IQS7211_REG_KEY_TOUCH, IQS7211_REG_KEY_TAP, IQS7211_REG_KEY_HOLD, IQS7211_REG_KEY_PALM, IQS7211_REG_KEY_AXIAL_X, IQS7211_REG_KEY_AXIAL_Y, IQS7211_REG_KEY_RESERVED }; enum iqs7211_reg_grp_id { IQS7211_REG_GRP_TP, IQS7211_REG_GRP_BTN, IQS7211_REG_GRP_ALP, IQS7211_REG_GRP_SYS, IQS7211_NUM_REG_GRPS }; static const char * const iqs7211_reg_grp_names[IQS7211_NUM_REG_GRPS] = { [IQS7211_REG_GRP_TP] = "trackpad", [IQS7211_REG_GRP_BTN] = "button", [IQS7211_REG_GRP_ALP] = "alp", }; static const u16 iqs7211_reg_grp_masks[IQS7211_NUM_REG_GRPS] = { [IQS7211_REG_GRP_TP] = IQS7211_EVENT_MASK_GSTR, [IQS7211_REG_GRP_BTN] = IQS7211_EVENT_MASK_BTN, [IQS7211_REG_GRP_ALP] = IQS7211_EVENT_MASK_ALP, }; struct iqs7211_event_desc { const char *name; u16 mask; u16 enable; enum iqs7211_reg_grp_id reg_grp; enum iqs7211_reg_key_id reg_key; }; static const struct iqs7211_event_desc iqs7210a_kp_events[] = { { .mask = BIT(10), .enable = BIT(13) | BIT(12), .reg_grp = IQS7211_REG_GRP_ALP, }, { .name = "event-prox", .mask = BIT(2), .enable = BIT(5) | BIT(4), .reg_grp = IQS7211_REG_GRP_BTN, .reg_key = IQS7211_REG_KEY_PROX, }, { .name = "event-touch", .mask = BIT(3), .enable = BIT(5) | BIT(4), .reg_grp = IQS7211_REG_GRP_BTN, .reg_key = IQS7211_REG_KEY_TOUCH, }, { .name = "event-tap", .mask = BIT(0), .enable = BIT(0), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_TAP, }, { .name = "event-hold", .mask = BIT(1), .enable = BIT(1), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_HOLD, }, { .name = "event-swipe-x-neg", .mask = BIT(2), .enable = BIT(2), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_X, }, { .name = "event-swipe-x-pos", .mask = BIT(3), .enable = BIT(3), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_X, }, { .name = "event-swipe-y-pos", .mask = BIT(4), .enable = BIT(4), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_Y, }, { .name = "event-swipe-y-neg", .mask = BIT(5), .enable = BIT(5), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_Y, }, }; static const struct iqs7211_event_desc iqs7211a_kp_events[] = { { .mask = BIT(14), .reg_grp = IQS7211_REG_GRP_ALP, }, { .name = "event-tap", .mask = BIT(0), .enable = BIT(0), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_TAP, }, { .name = "event-hold", .mask = BIT(1), .enable = BIT(1), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_HOLD, }, { .name = "event-swipe-x-neg", .mask = BIT(2), .enable = BIT(2), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_X, }, { .name = "event-swipe-x-pos", .mask = BIT(3), .enable = BIT(3), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_X, }, { .name = "event-swipe-y-pos", .mask = BIT(4), .enable = BIT(4), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_Y, }, { .name = "event-swipe-y-neg", .mask = BIT(5), .enable = BIT(5), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_Y, }, }; static const struct iqs7211_event_desc iqs7211e_kp_events[] = { { .mask = BIT(14), .reg_grp = IQS7211_REG_GRP_ALP, }, { .name = "event-tap", .mask = BIT(0), .enable = BIT(0), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_TAP, }, { .name = "event-tap-double", .mask = BIT(1), .enable = BIT(1), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_TAP, }, { .name = "event-tap-triple", .mask = BIT(2), .enable = BIT(2), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_TAP, }, { .name = "event-hold", .mask = BIT(3), .enable = BIT(3), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_HOLD, }, { .name = "event-palm", .mask = BIT(4), .enable = BIT(4), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_PALM, }, { .name = "event-swipe-x-pos", .mask = BIT(8), .enable = BIT(8), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_X, }, { .name = "event-swipe-x-neg", .mask = BIT(9), .enable = BIT(9), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_X, }, { .name = "event-swipe-y-pos", .mask = BIT(10), .enable = BIT(10), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_Y, }, { .name = "event-swipe-y-neg", .mask = BIT(11), .enable = BIT(11), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_AXIAL_Y, }, { .name = "event-swipe-x-pos-hold", .mask = BIT(12), .enable = BIT(12), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_HOLD, }, { .name = "event-swipe-x-neg-hold", .mask = BIT(13), .enable = BIT(13), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_HOLD, }, { .name = "event-swipe-y-pos-hold", .mask = BIT(14), .enable = BIT(14), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_HOLD, }, { .name = "event-swipe-y-neg-hold", .mask = BIT(15), .enable = BIT(15), .reg_grp = IQS7211_REG_GRP_TP, .reg_key = IQS7211_REG_KEY_HOLD, }, }; struct iqs7211_dev_desc { const char *tp_name; const char *kp_name; u16 prod_num; u16 show_reset; u16 ati_error[IQS7211_NUM_REG_GRPS]; u16 ati_start[IQS7211_NUM_REG_GRPS]; u16 suspend; u16 ack_reset; u16 comms_end; u16 comms_req; int charge_shift; int info_offs; int gesture_offs; int contact_offs; u8 sys_stat; u8 sys_ctrl; u8 alp_config; u8 tp_config; u8 exp_file; u8 kp_enable[IQS7211_NUM_REG_GRPS]; u8 gesture_angle; u8 rx_tx_map; u8 cycle_alloc[2]; u8 cycle_limit[2]; const struct iqs7211_event_desc *kp_events; int num_kp_events; int min_crx_alp; int num_ctx; }; static const struct iqs7211_dev_desc iqs7211_devs[] = { [IQS7210A] = { .tp_name = "iqs7210a_trackpad", .kp_name = "iqs7210a_keys", .prod_num = 944, .show_reset = BIT(15), .ati_error = { [IQS7211_REG_GRP_TP] = BIT(12), [IQS7211_REG_GRP_BTN] = BIT(0), [IQS7211_REG_GRP_ALP] = BIT(8), }, .ati_start = { [IQS7211_REG_GRP_TP] = BIT(13), [IQS7211_REG_GRP_BTN] = BIT(1), [IQS7211_REG_GRP_ALP] = BIT(9), }, .suspend = BIT(11), .ack_reset = BIT(7), .comms_end = BIT(2), .comms_req = BIT(1), .charge_shift = 4, .info_offs = 0, .gesture_offs = 1, .contact_offs = 4, .sys_stat = 0x0A, .sys_ctrl = 0x35, .alp_config = 0x39, .tp_config = 0x4E, .exp_file = 0x57, .kp_enable = { [IQS7211_REG_GRP_TP] = 0x58, [IQS7211_REG_GRP_BTN] = 0x37, [IQS7211_REG_GRP_ALP] = 0x37, }, .gesture_angle = 0x5F, .rx_tx_map = 0x60, .cycle_alloc = { 0x66, 0x75, }, .cycle_limit = { 10, 6, }, .kp_events = iqs7210a_kp_events, .num_kp_events = ARRAY_SIZE(iqs7210a_kp_events), .min_crx_alp = 4, .num_ctx = IQS7211_MAX_CTX - 1, }, [IQS7211A] = { .tp_name = "iqs7211a_trackpad", .kp_name = "iqs7211a_keys", .prod_num = 763, .show_reset = BIT(7), .ati_error = { [IQS7211_REG_GRP_TP] = BIT(3), [IQS7211_REG_GRP_ALP] = BIT(5), }, .ati_start = { [IQS7211_REG_GRP_TP] = BIT(5), [IQS7211_REG_GRP_ALP] = BIT(6), }, .ack_reset = BIT(7), .comms_req = BIT(4), .charge_shift = 0, .info_offs = 0, .gesture_offs = 1, .contact_offs = 4, .sys_stat = 0x10, .sys_ctrl = 0x50, .tp_config = 0x60, .alp_config = 0x72, .exp_file = 0x74, .kp_enable = { [IQS7211_REG_GRP_TP] = 0x80, }, .gesture_angle = 0x87, .rx_tx_map = 0x90, .cycle_alloc = { 0xA0, 0xB0, }, .cycle_limit = { 10, 8, }, .kp_events = iqs7211a_kp_events, .num_kp_events = ARRAY_SIZE(iqs7211a_kp_events), .num_ctx = IQS7211_MAX_CTX - 1, }, [IQS7211E] = { .tp_name = "iqs7211e_trackpad", .kp_name = "iqs7211e_keys", .prod_num = 1112, .show_reset = BIT(7), .ati_error = { [IQS7211_REG_GRP_TP] = BIT(3), [IQS7211_REG_GRP_ALP] = BIT(5), }, .ati_start = { [IQS7211_REG_GRP_TP] = BIT(5), [IQS7211_REG_GRP_ALP] = BIT(6), }, .suspend = BIT(11), .ack_reset = BIT(7), .comms_end = BIT(6), .comms_req = BIT(4), .charge_shift = 0, .info_offs = 1, .gesture_offs = 0, .contact_offs = 2, .sys_stat = 0x0E, .sys_ctrl = 0x33, .tp_config = 0x41, .alp_config = 0x36, .exp_file = 0x4A, .kp_enable = { [IQS7211_REG_GRP_TP] = 0x4B, }, .gesture_angle = 0x55, .rx_tx_map = 0x56, .cycle_alloc = { 0x5D, 0x6C, }, .cycle_limit = { 10, 11, }, .kp_events = iqs7211e_kp_events, .num_kp_events = ARRAY_SIZE(iqs7211e_kp_events), .num_ctx = IQS7211_MAX_CTX, }, }; struct iqs7211_prop_desc { const char *name; enum iqs7211_reg_key_id reg_key; u8 reg_addr[IQS7211_NUM_REG_GRPS][ARRAY_SIZE(iqs7211_devs)]; int reg_shift; int reg_width; int val_pitch; int val_min; int val_max; const char *label; }; static const struct iqs7211_prop_desc iqs7211_props[] = { { .name = "azoteq,ati-frac-div-fine", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x1E, [IQS7211A] = 0x30, [IQS7211E] = 0x21, }, [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x22, }, [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x23, [IQS7211A] = 0x36, [IQS7211E] = 0x25, }, }, .reg_shift = 9, .reg_width = 5, .label = "ATI fine fractional divider", }, { .name = "azoteq,ati-frac-mult-coarse", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x1E, [IQS7211A] = 0x30, [IQS7211E] = 0x21, }, [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x22, }, [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x23, [IQS7211A] = 0x36, [IQS7211E] = 0x25, }, }, .reg_shift = 5, .reg_width = 4, .label = "ATI coarse fractional multiplier", }, { .name = "azoteq,ati-frac-div-coarse", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x1E, [IQS7211A] = 0x30, [IQS7211E] = 0x21, }, [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x22, }, [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x23, [IQS7211A] = 0x36, [IQS7211E] = 0x25, }, }, .reg_shift = 0, .reg_width = 5, .label = "ATI coarse fractional divider", }, { .name = "azoteq,ati-comp-div", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x1F, [IQS7211E] = 0x22, }, [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x24, }, [IQS7211_REG_GRP_ALP] = { [IQS7211E] = 0x26, }, }, .reg_shift = 0, .reg_width = 8, .val_max = 31, .label = "ATI compensation divider", }, { .name = "azoteq,ati-comp-div", .reg_addr = { [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x24, }, }, .reg_shift = 8, .reg_width = 8, .val_max = 31, .label = "ATI compensation divider", }, { .name = "azoteq,ati-comp-div", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7211A] = 0x31, }, [IQS7211_REG_GRP_ALP] = { [IQS7211A] = 0x37, }, }, .val_max = 31, .label = "ATI compensation divider", }, { .name = "azoteq,ati-target", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x20, [IQS7211A] = 0x32, [IQS7211E] = 0x23, }, [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x27, }, [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x28, [IQS7211A] = 0x38, [IQS7211E] = 0x27, }, }, .label = "ATI target", }, { .name = "azoteq,ati-base", .reg_addr[IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x26, }, .reg_shift = 8, .reg_width = 8, .val_pitch = 8, .label = "ATI base", }, { .name = "azoteq,ati-base", .reg_addr[IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x26, }, .reg_shift = 0, .reg_width = 8, .val_pitch = 8, .label = "ATI base", }, { .name = "azoteq,rate-active-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x29, [IQS7211A] = 0x40, [IQS7211E] = 0x28, }, .label = "active mode report rate", }, { .name = "azoteq,rate-touch-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x2A, [IQS7211A] = 0x41, [IQS7211E] = 0x29, }, .label = "idle-touch mode report rate", }, { .name = "azoteq,rate-idle-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x2B, [IQS7211A] = 0x42, [IQS7211E] = 0x2A, }, .label = "idle mode report rate", }, { .name = "azoteq,rate-lp1-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x2C, [IQS7211A] = 0x43, [IQS7211E] = 0x2B, }, .label = "low-power mode 1 report rate", }, { .name = "azoteq,rate-lp2-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x2D, [IQS7211A] = 0x44, [IQS7211E] = 0x2C, }, .label = "low-power mode 2 report rate", }, { .name = "azoteq,timeout-active-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x2E, [IQS7211A] = 0x45, [IQS7211E] = 0x2D, }, .val_pitch = 1000, .label = "active mode timeout", }, { .name = "azoteq,timeout-touch-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x2F, [IQS7211A] = 0x46, [IQS7211E] = 0x2E, }, .val_pitch = 1000, .label = "idle-touch mode timeout", }, { .name = "azoteq,timeout-idle-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x30, [IQS7211A] = 0x47, [IQS7211E] = 0x2F, }, .val_pitch = 1000, .label = "idle mode timeout", }, { .name = "azoteq,timeout-lp1-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x31, [IQS7211A] = 0x48, [IQS7211E] = 0x30, }, .val_pitch = 1000, .label = "low-power mode 1 timeout", }, { .name = "azoteq,timeout-lp2-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x32, [IQS7211E] = 0x31, }, .reg_shift = 8, .reg_width = 8, .val_pitch = 1000, .val_max = 60000, .label = "trackpad reference value update rate", }, { .name = "azoteq,timeout-lp2-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7211A] = 0x49, }, .val_pitch = 1000, .val_max = 60000, .label = "trackpad reference value update rate", }, { .name = "azoteq,timeout-ati-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x32, [IQS7211E] = 0x31, }, .reg_width = 8, .val_pitch = 1000, .val_max = 60000, .label = "ATI error timeout", }, { .name = "azoteq,timeout-ati-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7211A] = 0x35, }, .val_pitch = 1000, .val_max = 60000, .label = "ATI error timeout", }, { .name = "azoteq,timeout-comms-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x33, [IQS7211A] = 0x4A, [IQS7211E] = 0x32, }, .label = "communication timeout", }, { .name = "azoteq,timeout-press-ms", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x34, }, .reg_width = 8, .val_pitch = 1000, .val_max = 60000, .label = "press timeout", }, { .name = "azoteq,ati-mode", .reg_addr[IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x37, }, .reg_shift = 15, .reg_width = 1, .label = "ATI mode", }, { .name = "azoteq,ati-mode", .reg_addr[IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x37, }, .reg_shift = 7, .reg_width = 1, .label = "ATI mode", }, { .name = "azoteq,sense-mode", .reg_addr[IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x37, [IQS7211A] = 0x72, [IQS7211E] = 0x36, }, .reg_shift = 8, .reg_width = 1, .label = "sensing mode", }, { .name = "azoteq,sense-mode", .reg_addr[IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x37, }, .reg_shift = 0, .reg_width = 2, .val_max = 2, .label = "sensing mode", }, { .name = "azoteq,fosc-freq", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x38, [IQS7211A] = 0x52, [IQS7211E] = 0x35, }, .reg_shift = 4, .reg_width = 1, .label = "core clock frequency selection", }, { .name = "azoteq,fosc-trim", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x38, [IQS7211A] = 0x52, [IQS7211E] = 0x35, }, .reg_shift = 0, .reg_width = 4, .label = "core clock frequency trim", }, { .name = "azoteq,touch-exit", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x3B, [IQS7211A] = 0x53, [IQS7211E] = 0x38, }, [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x3E, }, }, .reg_shift = 8, .reg_width = 8, .label = "touch exit factor", }, { .name = "azoteq,touch-enter", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x3B, [IQS7211A] = 0x53, [IQS7211E] = 0x38, }, [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x3E, }, }, .reg_shift = 0, .reg_width = 8, .label = "touch entrance factor", }, { .name = "azoteq,thresh", .reg_addr = { [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x3C, }, [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x3D, [IQS7211A] = 0x54, [IQS7211E] = 0x39, }, }, .label = "threshold", }, { .name = "azoteq,debounce-exit", .reg_addr = { [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x3F, }, [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x40, [IQS7211A] = 0x56, [IQS7211E] = 0x3A, }, }, .reg_shift = 8, .reg_width = 8, .label = "debounce exit factor", }, { .name = "azoteq,debounce-enter", .reg_addr = { [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x3F, }, [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x40, [IQS7211A] = 0x56, [IQS7211E] = 0x3A, }, }, .reg_shift = 0, .reg_width = 8, .label = "debounce entrance factor", }, { .name = "azoteq,conv-frac", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x48, [IQS7211A] = 0x58, [IQS7211E] = 0x3D, }, [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x49, }, [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x4A, [IQS7211A] = 0x59, [IQS7211E] = 0x3E, }, }, .reg_shift = 8, .reg_width = 8, .label = "conversion frequency fractional divider", }, { .name = "azoteq,conv-period", .reg_addr = { [IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x48, [IQS7211A] = 0x58, [IQS7211E] = 0x3D, }, [IQS7211_REG_GRP_BTN] = { [IQS7210A] = 0x49, }, [IQS7211_REG_GRP_ALP] = { [IQS7210A] = 0x4A, [IQS7211A] = 0x59, [IQS7211E] = 0x3E, }, }, .reg_shift = 0, .reg_width = 8, .label = "conversion period", }, { .name = "azoteq,thresh", .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x55, [IQS7211A] = 0x67, [IQS7211E] = 0x48, }, .reg_shift = 0, .reg_width = 8, .label = "threshold", }, { .name = "azoteq,contact-split", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x55, [IQS7211A] = 0x67, [IQS7211E] = 0x48, }, .reg_shift = 8, .reg_width = 8, .label = "contact split factor", }, { .name = "azoteq,trim-x", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x56, [IQS7211E] = 0x49, }, .reg_shift = 0, .reg_width = 8, .label = "horizontal trim width", }, { .name = "azoteq,trim-x", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7211A] = 0x68, }, .label = "horizontal trim width", }, { .name = "azoteq,trim-y", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7210A] = 0x56, [IQS7211E] = 0x49, }, .reg_shift = 8, .reg_width = 8, .label = "vertical trim height", }, { .name = "azoteq,trim-y", .reg_addr[IQS7211_REG_GRP_SYS] = { [IQS7211A] = 0x69, }, .label = "vertical trim height", }, { .name = "azoteq,gesture-max-ms", .reg_key = IQS7211_REG_KEY_TAP, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x59, [IQS7211A] = 0x81, [IQS7211E] = 0x4C, }, .label = "maximum gesture time", }, { .name = "azoteq,gesture-mid-ms", .reg_key = IQS7211_REG_KEY_TAP, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7211E] = 0x4D, }, .label = "repeated gesture time", }, { .name = "azoteq,gesture-dist", .reg_key = IQS7211_REG_KEY_TAP, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x5A, [IQS7211A] = 0x82, [IQS7211E] = 0x4E, }, .label = "gesture distance", }, { .name = "azoteq,gesture-dist", .reg_key = IQS7211_REG_KEY_HOLD, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x5A, [IQS7211A] = 0x82, [IQS7211E] = 0x4E, }, .label = "gesture distance", }, { .name = "azoteq,gesture-min-ms", .reg_key = IQS7211_REG_KEY_HOLD, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x5B, [IQS7211A] = 0x83, [IQS7211E] = 0x4F, }, .label = "minimum gesture time", }, { .name = "azoteq,gesture-max-ms", .reg_key = IQS7211_REG_KEY_AXIAL_X, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x5C, [IQS7211A] = 0x84, [IQS7211E] = 0x50, }, .label = "maximum gesture time", }, { .name = "azoteq,gesture-max-ms", .reg_key = IQS7211_REG_KEY_AXIAL_Y, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x5C, [IQS7211A] = 0x84, [IQS7211E] = 0x50, }, .label = "maximum gesture time", }, { .name = "azoteq,gesture-dist", .reg_key = IQS7211_REG_KEY_AXIAL_X, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x5D, [IQS7211A] = 0x85, [IQS7211E] = 0x51, }, .label = "gesture distance", }, { .name = "azoteq,gesture-dist", .reg_key = IQS7211_REG_KEY_AXIAL_Y, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7210A] = 0x5E, [IQS7211A] = 0x86, [IQS7211E] = 0x52, }, .label = "gesture distance", }, { .name = "azoteq,gesture-dist-rep", .reg_key = IQS7211_REG_KEY_AXIAL_X, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7211E] = 0x53, }, .label = "repeated gesture distance", }, { .name = "azoteq,gesture-dist-rep", .reg_key = IQS7211_REG_KEY_AXIAL_Y, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7211E] = 0x54, }, .label = "repeated gesture distance", }, { .name = "azoteq,thresh", .reg_key = IQS7211_REG_KEY_PALM, .reg_addr[IQS7211_REG_GRP_TP] = { [IQS7211E] = 0x55, }, .reg_shift = 8, .reg_width = 8, .val_max = 42, .label = "threshold", }, }; static const u8 iqs7211_gesture_angle[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x14, 0x15, 0x16, 0x17, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x21, 0x22, 0x23, 0x25, 0x26, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, 0x40, 0x42, 0x45, 0x47, 0x4A, 0x4C, 0x4F, 0x52, 0x55, 0x58, 0x5B, 0x5F, 0x63, 0x66, 0x6B, 0x6F, 0x73, 0x78, 0x7E, 0x83, 0x89, 0x90, 0x97, 0x9E, 0xA7, 0xB0, 0xBA, 0xC5, 0xD1, 0xDF, 0xEF, }; struct iqs7211_ver_info { __le16 prod_num; __le16 major; __le16 minor; __le32 patch; } __packed; struct iqs7211_touch_data { __le16 abs_x; __le16 abs_y; __le16 pressure; __le16 area; } __packed; struct iqs7211_tp_config { u8 tp_settings; u8 total_rx; u8 total_tx; u8 num_contacts; __le16 max_x; __le16 max_y; } __packed; struct iqs7211_private { const struct iqs7211_dev_desc *dev_desc; struct gpio_desc *reset_gpio; struct gpio_desc *irq_gpio; struct i2c_client *client; struct input_dev *tp_idev; struct input_dev *kp_idev; struct iqs7211_ver_info ver_info; struct iqs7211_tp_config tp_config; struct touchscreen_properties prop; struct list_head reg_field_head; enum iqs7211_comms_mode comms_init; enum iqs7211_comms_mode comms_mode; unsigned int num_contacts; unsigned int kp_code[ARRAY_SIZE(iqs7211e_kp_events)]; u8 rx_tx_map[IQS7211_MAX_CTX + 1]; u8 cycle_alloc[2][33]; u8 exp_file[2]; u16 event_mask; u16 ati_start; u16 gesture_cache; }; static int iqs7211_irq_poll(struct iqs7211_private *iqs7211, u64 timeout_us) { int error, val; error = readx_poll_timeout(gpiod_get_value_cansleep, iqs7211->irq_gpio, val, val, IQS7211_COMMS_SLEEP_US, timeout_us); return val < 0 ? val : error; } static int iqs7211_hard_reset(struct iqs7211_private *iqs7211) { if (!iqs7211->reset_gpio) return 0; gpiod_set_value_cansleep(iqs7211->reset_gpio, 1); /* * The following delay ensures the shared RDY/MCLR pin is sampled in * between periodic assertions by the device and assumes the default * communication timeout has not been overwritten in OTP memory. */ if (iqs7211->reset_gpio == iqs7211->irq_gpio) msleep(IQS7211_RESET_TIMEOUT_MS); else usleep_range(1000, 1100); gpiod_set_value_cansleep(iqs7211->reset_gpio, 0); if (iqs7211->reset_gpio == iqs7211->irq_gpio) iqs7211_irq_wait(); return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US); } static int iqs7211_force_comms(struct iqs7211_private *iqs7211) { u8 msg_buf[] = { 0xFF, }; int ret; switch (iqs7211->comms_mode) { case IQS7211_COMMS_MODE_WAIT: return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US); case IQS7211_COMMS_MODE_FREE: return 0; case IQS7211_COMMS_MODE_FORCE: break; default: return -EINVAL; } /* * The device cannot communicate until it asserts its interrupt (RDY) * pin. Attempts to do so while RDY is deasserted return an ACK; how- * ever all write data is ignored, and all read data returns 0xEE. * * Unsolicited communication must be preceded by a special force com- * munication command, after which the device eventually asserts its * RDY pin and agrees to communicate. * * Regardless of whether communication is forced or the result of an * interrupt, the device automatically deasserts its RDY pin once it * detects an I2C stop condition, or a timeout expires. */ ret = gpiod_get_value_cansleep(iqs7211->irq_gpio); if (ret < 0) return ret; else if (ret > 0) return 0; ret = i2c_master_send(iqs7211->client, msg_buf, sizeof(msg_buf)); if (ret < (int)sizeof(msg_buf)) { if (ret >= 0) ret = -EIO; msleep(IQS7211_COMMS_RETRY_MS); return ret; } iqs7211_irq_wait(); return iqs7211_irq_poll(iqs7211, IQS7211_COMMS_TIMEOUT_US); } static int iqs7211_read_burst(struct iqs7211_private *iqs7211, u8 reg, void *val, u16 val_len) { int ret, i; struct i2c_client *client = iqs7211->client; struct i2c_msg msg[] = { { .addr = client->addr, .flags = 0, .len = sizeof(reg), .buf = ®, }, { .addr = client->addr, .flags = I2C_M_RD, .len = val_len, .buf = (u8 *)val, }, }; /* * The following loop protects against an edge case in which the RDY * pin is automatically deasserted just as the read is initiated. In * that case, the read must be retried using forced communication. */ for (i = 0; i < IQS7211_NUM_RETRIES; i++) { ret = iqs7211_force_comms(iqs7211); if (ret < 0) continue; ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); if (ret < (int)ARRAY_SIZE(msg)) { if (ret >= 0) ret = -EIO; msleep(IQS7211_COMMS_RETRY_MS); continue; } if (get_unaligned_le16(msg[1].buf) == IQS7211_COMMS_ERROR) { ret = -ENODATA; continue; } ret = 0; break; } iqs7211_irq_wait(); if (ret < 0) dev_err(&client->dev, "Failed to read from address 0x%02X: %d\n", reg, ret); return ret; } static int iqs7211_read_word(struct iqs7211_private *iqs7211, u8 reg, u16 *val) { __le16 val_buf; int error; error = iqs7211_read_burst(iqs7211, reg, &val_buf, sizeof(val_buf)); if (error) return error; *val = le16_to_cpu(val_buf); return 0; } static int iqs7211_write_burst(struct iqs7211_private *iqs7211, u8 reg, const void *val, u16 val_len) { int msg_len = sizeof(reg) + val_len; int ret, i; struct i2c_client *client = iqs7211->client; u8 *msg_buf; msg_buf = kzalloc(msg_len, GFP_KERNEL); if (!msg_buf) return -ENOMEM; *msg_buf = reg; memcpy(msg_buf + sizeof(reg), val, val_len); /* * The following loop protects against an edge case in which the RDY * pin is automatically asserted just before the force communication * command is sent. * * In that case, the subsequent I2C stop condition tricks the device * into preemptively deasserting the RDY pin and the command must be * sent again. */ for (i = 0; i < IQS7211_NUM_RETRIES; i++) { ret = iqs7211_force_comms(iqs7211); if (ret < 0) continue; ret = i2c_master_send(client, msg_buf, msg_len); if (ret < msg_len) { if (ret >= 0) ret = -EIO; msleep(IQS7211_COMMS_RETRY_MS); continue; } ret = 0; break; } kfree(msg_buf); iqs7211_irq_wait(); if (ret < 0) dev_err(&client->dev, "Failed to write to address 0x%02X: %d\n", reg, ret); return ret; } static int iqs7211_write_word(struct iqs7211_private *iqs7211, u8 reg, u16 val) { __le16 val_buf = cpu_to_le16(val); return iqs7211_write_burst(iqs7211, reg, &val_buf, sizeof(val_buf)); } static int iqs7211_start_comms(struct iqs7211_private *iqs7211) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct i2c_client *client = iqs7211->client; bool forced_comms; unsigned int val; u16 comms_setup; int error; /* * Until forced communication can be enabled, the host must wait for a * communication window each time it intends to elicit a response from * the device. * * Forced communication is not necessary, however, if the host adapter * can support clock stretching. In that case, the device freely clock * stretches until all pending conversions are complete. */ forced_comms = device_property_present(&client->dev, "azoteq,forced-comms"); error = device_property_read_u32(&client->dev, "azoteq,forced-comms-default", &val); if (error == -EINVAL) { iqs7211->comms_init = IQS7211_COMMS_MODE_WAIT; } else if (error) { dev_err(&client->dev, "Failed to read default communication mode: %d\n", error); return error; } else if (val) { iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_FORCE : IQS7211_COMMS_MODE_WAIT; } else { iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_WAIT : IQS7211_COMMS_MODE_FREE; } iqs7211->comms_mode = iqs7211->comms_init; error = iqs7211_hard_reset(iqs7211); if (error) { dev_err(&client->dev, "Failed to reset device: %d\n", error); return error; } error = iqs7211_read_burst(iqs7211, IQS7211_PROD_NUM, &iqs7211->ver_info, sizeof(iqs7211->ver_info)); if (error) return error; if (le16_to_cpu(iqs7211->ver_info.prod_num) != dev_desc->prod_num) { dev_err(&client->dev, "Invalid product number: %u\n", le16_to_cpu(iqs7211->ver_info.prod_num)); return -EINVAL; } error = iqs7211_read_word(iqs7211, dev_desc->sys_ctrl + 1, &comms_setup); if (error) return error; if (forced_comms) comms_setup |= dev_desc->comms_req; else comms_setup &= ~dev_desc->comms_req; error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, comms_setup | dev_desc->comms_end); if (error) return error; if (forced_comms) iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE; else iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE; error = iqs7211_read_burst(iqs7211, dev_desc->exp_file, iqs7211->exp_file, sizeof(iqs7211->exp_file)); if (error) return error; error = iqs7211_read_burst(iqs7211, dev_desc->tp_config, &iqs7211->tp_config, sizeof(iqs7211->tp_config)); if (error) return error; error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, comms_setup); if (error) return error; iqs7211->event_mask = comms_setup & ~IQS7211_EVENT_MASK_ALL; iqs7211->event_mask |= (IQS7211_EVENT_MASK_ATI | IQS7211_EVENT_MODE); return 0; } static int iqs7211_init_device(struct iqs7211_private *iqs7211) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct iqs7211_reg_field_desc *reg_field; __le16 sys_ctrl[] = { cpu_to_le16(dev_desc->ack_reset), cpu_to_le16(iqs7211->event_mask), }; int error, i; /* * Acknowledge reset before writing any registers in case the device * suffers a spurious reset during initialization. The communication * mode is configured at this time as well. */ error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, sizeof(sys_ctrl)); if (error) return error; if (iqs7211->event_mask & dev_desc->comms_req) iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE; else iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE; /* * Take advantage of the stop-bit disable function, if available, to * save the trouble of having to reopen a communication window after * each read or write. */ error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, iqs7211->event_mask | dev_desc->comms_end); if (error) return error; list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) { u16 new_val = reg_field->val; if (reg_field->mask < U16_MAX) { u16 old_val; error = iqs7211_read_word(iqs7211, reg_field->addr, &old_val); if (error) return error; new_val = old_val & ~reg_field->mask; new_val |= reg_field->val; if (new_val == old_val) continue; } error = iqs7211_write_word(iqs7211, reg_field->addr, new_val); if (error) return error; } error = iqs7211_write_burst(iqs7211, dev_desc->tp_config, &iqs7211->tp_config, sizeof(iqs7211->tp_config)); if (error) return error; if (**iqs7211->cycle_alloc) { error = iqs7211_write_burst(iqs7211, dev_desc->rx_tx_map, &iqs7211->rx_tx_map, dev_desc->num_ctx); if (error) return error; for (i = 0; i < sizeof(dev_desc->cycle_limit); i++) { error = iqs7211_write_burst(iqs7211, dev_desc->cycle_alloc[i], iqs7211->cycle_alloc[i], dev_desc->cycle_limit[i] * 3); if (error) return error; } } *sys_ctrl = cpu_to_le16(iqs7211->ati_start); return iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, sizeof(sys_ctrl)); } static int iqs7211_add_field(struct iqs7211_private *iqs7211, struct iqs7211_reg_field_desc new_field) { struct i2c_client *client = iqs7211->client; struct iqs7211_reg_field_desc *reg_field; if (!new_field.addr) return 0; list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) { if (reg_field->addr != new_field.addr) continue; reg_field->mask |= new_field.mask; reg_field->val |= new_field.val; return 0; } reg_field = devm_kzalloc(&client->dev, sizeof(*reg_field), GFP_KERNEL); if (!reg_field) return -ENOMEM; reg_field->addr = new_field.addr; reg_field->mask = new_field.mask; reg_field->val = new_field.val; list_add(®_field->list, &iqs7211->reg_field_head); return 0; } static int iqs7211_parse_props(struct iqs7211_private *iqs7211, struct fwnode_handle *reg_grp_node, enum iqs7211_reg_grp_id reg_grp, enum iqs7211_reg_key_id reg_key) { struct i2c_client *client = iqs7211->client; int i; for (i = 0; i < ARRAY_SIZE(iqs7211_props); i++) { const char *name = iqs7211_props[i].name; u8 reg_addr = iqs7211_props[i].reg_addr[reg_grp] [iqs7211->dev_desc - iqs7211_devs]; int reg_shift = iqs7211_props[i].reg_shift; int reg_width = iqs7211_props[i].reg_width ? : 16; int val_pitch = iqs7211_props[i].val_pitch ? : 1; int val_min = iqs7211_props[i].val_min; int val_max = iqs7211_props[i].val_max; const char *label = iqs7211_props[i].label ? : name; struct iqs7211_reg_field_desc reg_field; unsigned int val; int error; if (iqs7211_props[i].reg_key != reg_key) continue; if (!reg_addr) continue; error = fwnode_property_read_u32(reg_grp_node, name, &val); if (error == -EINVAL) { continue; } else if (error) { dev_err(&client->dev, "Failed to read %s %s: %d\n", fwnode_get_name(reg_grp_node), label, error); return error; } if (!val_max) val_max = GENMASK(reg_width - 1, 0) * val_pitch; if (val < val_min || val > val_max) { dev_err(&client->dev, "Invalid %s: %u\n", label, val); return -EINVAL; } reg_field.addr = reg_addr; reg_field.mask = GENMASK(reg_shift + reg_width - 1, reg_shift); reg_field.val = val / val_pitch << reg_shift; error = iqs7211_add_field(iqs7211, reg_field); if (error) return error; } return 0; } static int iqs7211_parse_event(struct iqs7211_private *iqs7211, struct fwnode_handle *event_node, enum iqs7211_reg_grp_id reg_grp, enum iqs7211_reg_key_id reg_key, unsigned int *event_code) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct i2c_client *client = iqs7211->client; struct iqs7211_reg_field_desc reg_field; unsigned int val; int error; error = iqs7211_parse_props(iqs7211, event_node, reg_grp, reg_key); if (error) return error; if (reg_key == IQS7211_REG_KEY_AXIAL_X || reg_key == IQS7211_REG_KEY_AXIAL_Y) { error = fwnode_property_read_u32(event_node, "azoteq,gesture-angle", &val); if (!error) { if (val >= ARRAY_SIZE(iqs7211_gesture_angle)) { dev_err(&client->dev, "Invalid %s gesture angle: %u\n", fwnode_get_name(event_node), val); return -EINVAL; } reg_field.addr = dev_desc->gesture_angle; reg_field.mask = U8_MAX; reg_field.val = iqs7211_gesture_angle[val]; error = iqs7211_add_field(iqs7211, reg_field); if (error) return error; } else if (error != -EINVAL) { dev_err(&client->dev, "Failed to read %s gesture angle: %d\n", fwnode_get_name(event_node), error); return error; } } error = fwnode_property_read_u32(event_node, "linux,code", event_code); if (error == -EINVAL) error = 0; else if (error) dev_err(&client->dev, "Failed to read %s code: %d\n", fwnode_get_name(event_node), error); return error; } static int iqs7211_parse_cycles(struct iqs7211_private *iqs7211, struct fwnode_handle *tp_node) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct i2c_client *client = iqs7211->client; int num_cycles = dev_desc->cycle_limit[0] + dev_desc->cycle_limit[1]; int error, count, i, j, k, cycle_start; unsigned int cycle_alloc[IQS7211_MAX_CYCLES][2]; u8 total_rx = iqs7211->tp_config.total_rx; u8 total_tx = iqs7211->tp_config.total_tx; for (i = 0; i < IQS7211_MAX_CYCLES * 2; i++) *(cycle_alloc[0] + i) = U8_MAX; count = fwnode_property_count_u32(tp_node, "azoteq,channel-select"); if (count == -EINVAL) { /* * Assign each sensing cycle's slots (0 and 1) to a channel, * defined as the intersection between two CRx and CTx pins. * A channel assignment of 255 means the slot is unused. */ for (i = 0, cycle_start = 0; i < total_tx; i++) { int cycle_stop = 0; for (j = 0; j < total_rx; j++) { /* * Channels formed by CRx0-3 and CRx4-7 are * bound to slots 0 and 1, respectively. */ int slot = iqs7211->rx_tx_map[j] < 4 ? 0 : 1; int chan = i * total_rx + j; for (k = cycle_start; k < num_cycles; k++) { if (cycle_alloc[k][slot] < U8_MAX) continue; cycle_alloc[k][slot] = chan; break; } if (k < num_cycles) { cycle_stop = max(k, cycle_stop); continue; } dev_err(&client->dev, "Insufficient number of cycles\n"); return -EINVAL; } /* * Sensing cycles cannot straddle more than one CTx * pin. As such, the next row's starting cycle must * be greater than the previous row's highest cycle. */ cycle_start = cycle_stop + 1; } } else if (count < 0) { dev_err(&client->dev, "Failed to count channels: %d\n", count); return count; } else if (count > num_cycles * 2) { dev_err(&client->dev, "Insufficient number of cycles\n"); return -EINVAL; } else if (count > 0) { error = fwnode_property_read_u32_array(tp_node, "azoteq,channel-select", cycle_alloc[0], count); if (error) { dev_err(&client->dev, "Failed to read channels: %d\n", error); return error; } for (i = 0; i < count; i++) { int chan = *(cycle_alloc[0] + i); if (chan == U8_MAX) continue; if (chan >= total_rx * total_tx) { dev_err(&client->dev, "Invalid channel: %d\n", chan); return -EINVAL; } for (j = 0; j < count; j++) { if (j == i || *(cycle_alloc[0] + j) != chan) continue; dev_err(&client->dev, "Duplicate channel: %d\n", chan); return -EINVAL; } } } /* * Once the raw channel assignments have been derived, they must be * packed according to the device's register map. */ for (i = 0, cycle_start = 0; i < sizeof(dev_desc->cycle_limit); i++) { int offs = 0; for (j = cycle_start; j < cycle_start + dev_desc->cycle_limit[i]; j++) { iqs7211->cycle_alloc[i][offs++] = 0x05; iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][0]; iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][1]; } cycle_start += dev_desc->cycle_limit[i]; } return 0; } static int iqs7211_parse_tp(struct iqs7211_private *iqs7211, struct fwnode_handle *tp_node) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct i2c_client *client = iqs7211->client; unsigned int pins[IQS7211_MAX_CTX]; int error, count, i, j; count = fwnode_property_count_u32(tp_node, "azoteq,rx-enable"); if (count == -EINVAL) { return 0; } else if (count < 0) { dev_err(&client->dev, "Failed to count CRx pins: %d\n", count); return count; } else if (count > IQS7211_NUM_CRX) { dev_err(&client->dev, "Invalid number of CRx pins\n"); return -EINVAL; } error = fwnode_property_read_u32_array(tp_node, "azoteq,rx-enable", pins, count); if (error) { dev_err(&client->dev, "Failed to read CRx pins: %d\n", error); return error; } for (i = 0; i < count; i++) { if (pins[i] >= IQS7211_NUM_CRX) { dev_err(&client->dev, "Invalid CRx pin: %u\n", pins[i]); return -EINVAL; } iqs7211->rx_tx_map[i] = pins[i]; } iqs7211->tp_config.total_rx = count; count = fwnode_property_count_u32(tp_node, "azoteq,tx-enable"); if (count < 0) { dev_err(&client->dev, "Failed to count CTx pins: %d\n", count); return count; } else if (count > dev_desc->num_ctx) { dev_err(&client->dev, "Invalid number of CTx pins\n"); return -EINVAL; } error = fwnode_property_read_u32_array(tp_node, "azoteq,tx-enable", pins, count); if (error) { dev_err(&client->dev, "Failed to read CTx pins: %d\n", error); return error; } for (i = 0; i < count; i++) { if (pins[i] >= dev_desc->num_ctx) { dev_err(&client->dev, "Invalid CTx pin: %u\n", pins[i]); return -EINVAL; } for (j = 0; j < iqs7211->tp_config.total_rx; j++) { if (iqs7211->rx_tx_map[j] != pins[i]) continue; dev_err(&client->dev, "Conflicting CTx pin: %u\n", pins[i]); return -EINVAL; } iqs7211->rx_tx_map[iqs7211->tp_config.total_rx + i] = pins[i]; } iqs7211->tp_config.total_tx = count; return iqs7211_parse_cycles(iqs7211, tp_node); } static int iqs7211_parse_alp(struct iqs7211_private *iqs7211, struct fwnode_handle *alp_node) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct i2c_client *client = iqs7211->client; struct iqs7211_reg_field_desc reg_field; int error, count, i; count = fwnode_property_count_u32(alp_node, "azoteq,rx-enable"); if (count < 0 && count != -EINVAL) { dev_err(&client->dev, "Failed to count CRx pins: %d\n", count); return count; } else if (count > IQS7211_NUM_CRX) { dev_err(&client->dev, "Invalid number of CRx pins\n"); return -EINVAL; } else if (count >= 0) { unsigned int pins[IQS7211_NUM_CRX]; error = fwnode_property_read_u32_array(alp_node, "azoteq,rx-enable", pins, count); if (error) { dev_err(&client->dev, "Failed to read CRx pins: %d\n", error); return error; } reg_field.addr = dev_desc->alp_config; reg_field.mask = GENMASK(IQS7211_NUM_CRX - 1, 0); reg_field.val = 0; for (i = 0; i < count; i++) { if (pins[i] < dev_desc->min_crx_alp || pins[i] >= IQS7211_NUM_CRX) { dev_err(&client->dev, "Invalid CRx pin: %u\n", pins[i]); return -EINVAL; } reg_field.val |= BIT(pins[i]); } error = iqs7211_add_field(iqs7211, reg_field); if (error) return error; } count = fwnode_property_count_u32(alp_node, "azoteq,tx-enable"); if (count < 0 && count != -EINVAL) { dev_err(&client->dev, "Failed to count CTx pins: %d\n", count); return count; } else if (count > dev_desc->num_ctx) { dev_err(&client->dev, "Invalid number of CTx pins\n"); return -EINVAL; } else if (count >= 0) { unsigned int pins[IQS7211_MAX_CTX]; error = fwnode_property_read_u32_array(alp_node, "azoteq,tx-enable", pins, count); if (error) { dev_err(&client->dev, "Failed to read CTx pins: %d\n", error); return error; } reg_field.addr = dev_desc->alp_config + 1; reg_field.mask = GENMASK(dev_desc->num_ctx - 1, 0); reg_field.val = 0; for (i = 0; i < count; i++) { if (pins[i] >= dev_desc->num_ctx) { dev_err(&client->dev, "Invalid CTx pin: %u\n", pins[i]); return -EINVAL; } reg_field.val |= BIT(pins[i]); } error = iqs7211_add_field(iqs7211, reg_field); if (error) return error; } return 0; } static int (*iqs7211_parse_extra[IQS7211_NUM_REG_GRPS]) (struct iqs7211_private *iqs7211, struct fwnode_handle *reg_grp_node) = { [IQS7211_REG_GRP_TP] = iqs7211_parse_tp, [IQS7211_REG_GRP_ALP] = iqs7211_parse_alp, }; static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211, struct fwnode_handle *reg_grp_node, enum iqs7211_reg_grp_id reg_grp) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct iqs7211_reg_field_desc reg_field; int error, i; error = iqs7211_parse_props(iqs7211, reg_grp_node, reg_grp, IQS7211_REG_KEY_NONE); if (error) return error; if (iqs7211_parse_extra[reg_grp]) { error = iqs7211_parse_extra[reg_grp](iqs7211, reg_grp_node); if (error) return error; } iqs7211->ati_start |= dev_desc->ati_start[reg_grp]; reg_field.addr = dev_desc->kp_enable[reg_grp]; reg_field.mask = 0; reg_field.val = 0; for (i = 0; i < dev_desc->num_kp_events; i++) { const char *event_name = dev_desc->kp_events[i].name; struct fwnode_handle *event_node; if (dev_desc->kp_events[i].reg_grp != reg_grp) continue; reg_field.mask |= dev_desc->kp_events[i].enable; if (event_name) event_node = fwnode_get_named_child_node(reg_grp_node, event_name); else event_node = fwnode_handle_get(reg_grp_node); if (!event_node) continue; error = iqs7211_parse_event(iqs7211, event_node, dev_desc->kp_events[i].reg_grp, dev_desc->kp_events[i].reg_key, &iqs7211->kp_code[i]); fwnode_handle_put(event_node); if (error) return error; reg_field.val |= dev_desc->kp_events[i].enable; iqs7211->event_mask |= iqs7211_reg_grp_masks[reg_grp]; } return iqs7211_add_field(iqs7211, reg_field); } static int iqs7211_register_kp(struct iqs7211_private *iqs7211) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct input_dev *kp_idev = iqs7211->kp_idev; struct i2c_client *client = iqs7211->client; int error, i; for (i = 0; i < dev_desc->num_kp_events; i++) if (iqs7211->kp_code[i]) break; if (i == dev_desc->num_kp_events) return 0; kp_idev = devm_input_allocate_device(&client->dev); if (!kp_idev) return -ENOMEM; iqs7211->kp_idev = kp_idev; kp_idev->name = dev_desc->kp_name; kp_idev->id.bustype = BUS_I2C; for (i = 0; i < dev_desc->num_kp_events; i++) if (iqs7211->kp_code[i]) input_set_capability(iqs7211->kp_idev, EV_KEY, iqs7211->kp_code[i]); error = input_register_device(kp_idev); if (error) dev_err(&client->dev, "Failed to register %s: %d\n", kp_idev->name, error); return error; } static int iqs7211_register_tp(struct iqs7211_private *iqs7211) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct touchscreen_properties *prop = &iqs7211->prop; struct input_dev *tp_idev = iqs7211->tp_idev; struct i2c_client *client = iqs7211->client; int error; error = device_property_read_u32(&client->dev, "azoteq,num-contacts", &iqs7211->num_contacts); if (error == -EINVAL) { return 0; } else if (error) { dev_err(&client->dev, "Failed to read number of contacts: %d\n", error); return error; } else if (iqs7211->num_contacts > IQS7211_MAX_CONTACTS) { dev_err(&client->dev, "Invalid number of contacts: %u\n", iqs7211->num_contacts); return -EINVAL; } iqs7211->tp_config.num_contacts = iqs7211->num_contacts ? : 1; if (!iqs7211->num_contacts) return 0; iqs7211->event_mask |= IQS7211_EVENT_MASK_MOVE; tp_idev = devm_input_allocate_device(&client->dev); if (!tp_idev) return -ENOMEM; iqs7211->tp_idev = tp_idev; tp_idev->name = dev_desc->tp_name; tp_idev->id.bustype = BUS_I2C; input_set_abs_params(tp_idev, ABS_MT_POSITION_X, 0, le16_to_cpu(iqs7211->tp_config.max_x), 0, 0); input_set_abs_params(tp_idev, ABS_MT_POSITION_Y, 0, le16_to_cpu(iqs7211->tp_config.max_y), 0, 0); input_set_abs_params(tp_idev, ABS_MT_PRESSURE, 0, U16_MAX, 0, 0); touchscreen_parse_properties(tp_idev, true, prop); /* * The device reserves 0xFFFF for coordinates that correspond to slots * which are not in a state of touch. */ if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) { dev_err(&client->dev, "Invalid trackpad size: %u*%u\n", prop->max_x, prop->max_y); return -EINVAL; } iqs7211->tp_config.max_x = cpu_to_le16(prop->max_x); iqs7211->tp_config.max_y = cpu_to_le16(prop->max_y); error = input_mt_init_slots(tp_idev, iqs7211->num_contacts, INPUT_MT_DIRECT); if (error) { dev_err(&client->dev, "Failed to initialize slots: %d\n", error); return error; } error = input_register_device(tp_idev); if (error) dev_err(&client->dev, "Failed to register %s: %d\n", tp_idev->name, error); return error; } static int iqs7211_report(struct iqs7211_private *iqs7211) { const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; struct i2c_client *client = iqs7211->client; struct iqs7211_touch_data *touch_data; u16 info_flags, charge_mode, gesture_flags; __le16 status[12]; int error, i; error = iqs7211_read_burst(iqs7211, dev_desc->sys_stat, status, dev_desc->contact_offs * sizeof(__le16) + iqs7211->num_contacts * sizeof(*touch_data)); if (error) return error; info_flags = le16_to_cpu(status[dev_desc->info_offs]); if (info_flags & dev_desc->show_reset) { dev_err(&client->dev, "Unexpected device reset\n"); /* * The device may or may not expect forced communication after * it exits hardware reset, so the corresponding state machine * must be reset as well. */ iqs7211->comms_mode = iqs7211->comms_init; return iqs7211_init_device(iqs7211); } for (i = 0; i < ARRAY_SIZE(dev_desc->ati_error); i++) { if (!(info_flags & dev_desc->ati_error[i])) continue; dev_err(&client->dev, "Unexpected %s ATI error\n", iqs7211_reg_grp_names[i]); return 0; } for (i = 0; i < iqs7211->num_contacts; i++) { u16 pressure; touch_data = (struct iqs7211_touch_data *) &status[dev_desc->contact_offs] + i; pressure = le16_to_cpu(touch_data->pressure); input_mt_slot(iqs7211->tp_idev, i); if (input_mt_report_slot_state(iqs7211->tp_idev, MT_TOOL_FINGER, pressure != 0)) { touchscreen_report_pos(iqs7211->tp_idev, &iqs7211->prop, le16_to_cpu(touch_data->abs_x), le16_to_cpu(touch_data->abs_y), true); input_report_abs(iqs7211->tp_idev, ABS_MT_PRESSURE, pressure); } } if (iqs7211->num_contacts) { input_mt_sync_frame(iqs7211->tp_idev); input_sync(iqs7211->tp_idev); } if (!iqs7211->kp_idev) return 0; charge_mode = info_flags & GENMASK(dev_desc->charge_shift + 2, dev_desc->charge_shift); charge_mode >>= dev_desc->charge_shift; /* * A charging mode higher than 2 (idle mode) indicates the device last * operated in low-power mode and intends to express an ALP event. */ if (info_flags & dev_desc->kp_events->mask && charge_mode > 2) { input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 1); input_sync(iqs7211->kp_idev); input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 0); } for (i = 0; i < dev_desc->num_kp_events; i++) { if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_BTN) continue; input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i], info_flags & dev_desc->kp_events[i].mask); } gesture_flags = le16_to_cpu(status[dev_desc->gesture_offs]); for (i = 0; i < dev_desc->num_kp_events; i++) { enum iqs7211_reg_key_id reg_key = dev_desc->kp_events[i].reg_key; u16 mask = dev_desc->kp_events[i].mask; if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_TP) continue; if ((gesture_flags ^ iqs7211->gesture_cache) & mask) input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i], gesture_flags & mask); iqs7211->gesture_cache &= ~mask; /* * Hold and palm gestures persist while the contact remains in * place; all others are momentary and hence are followed by a * complementary release event. */ if (reg_key == IQS7211_REG_KEY_HOLD || reg_key == IQS7211_REG_KEY_PALM) { iqs7211->gesture_cache |= gesture_flags & mask; gesture_flags &= ~mask; } } if (gesture_flags) { input_sync(iqs7211->kp_idev); for (i = 0; i < dev_desc->num_kp_events; i++) if (dev_desc->kp_events[i].reg_grp == IQS7211_REG_GRP_TP && gesture_flags & dev_desc->kp_events[i].mask) input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i], 0); } input_sync(iqs7211->kp_idev); return 0; } static irqreturn_t iqs7211_irq(int irq, void *context) { struct iqs7211_private *iqs7211 = context; return iqs7211_report(iqs7211) ? IRQ_NONE : IRQ_HANDLED; } static int iqs7211_suspend(struct device *dev) { struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; int error; if (!dev_desc->suspend || device_may_wakeup(dev)) return 0; /* * I2C communication prompts the device to assert its RDY pin if it is * not already asserted. As such, the interrupt must be disabled so as * to prevent reentrant interrupts. */ disable_irq(gpiod_to_irq(iqs7211->irq_gpio)); error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl, dev_desc->suspend); enable_irq(gpiod_to_irq(iqs7211->irq_gpio)); return error; } static int iqs7211_resume(struct device *dev) { struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; __le16 sys_ctrl[] = { 0, cpu_to_le16(iqs7211->event_mask), }; int error; if (!dev_desc->suspend || device_may_wakeup(dev)) return 0; disable_irq(gpiod_to_irq(iqs7211->irq_gpio)); /* * Forced communication, if in use, must be explicitly enabled as part * of the wake-up command. */ error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, sizeof(sys_ctrl)); enable_irq(gpiod_to_irq(iqs7211->irq_gpio)); return error; } static DEFINE_SIMPLE_DEV_PM_OPS(iqs7211_pm, iqs7211_suspend, iqs7211_resume); static ssize_t fw_info_show(struct device *dev, struct device_attribute *attr, char *buf) { struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u:%u.%u\n", le16_to_cpu(iqs7211->ver_info.prod_num), le32_to_cpu(iqs7211->ver_info.patch), le16_to_cpu(iqs7211->ver_info.major), le16_to_cpu(iqs7211->ver_info.minor), iqs7211->exp_file[1], iqs7211->exp_file[0]); } static DEVICE_ATTR_RO(fw_info); static struct attribute *iqs7211_attrs[] = { &dev_attr_fw_info.attr, NULL }; ATTRIBUTE_GROUPS(iqs7211); static const struct of_device_id iqs7211_of_match[] = { { .compatible = "azoteq,iqs7210a", .data = &iqs7211_devs[IQS7210A], }, { .compatible = "azoteq,iqs7211a", .data = &iqs7211_devs[IQS7211A], }, { .compatible = "azoteq,iqs7211e", .data = &iqs7211_devs[IQS7211E], }, { } }; MODULE_DEVICE_TABLE(of, iqs7211_of_match); static int iqs7211_probe(struct i2c_client *client) { struct iqs7211_private *iqs7211; enum iqs7211_reg_grp_id reg_grp; unsigned long irq_flags; bool shared_irq; int error, irq; iqs7211 = devm_kzalloc(&client->dev, sizeof(*iqs7211), GFP_KERNEL); if (!iqs7211) return -ENOMEM; i2c_set_clientdata(client, iqs7211); iqs7211->client = client; INIT_LIST_HEAD(&iqs7211->reg_field_head); iqs7211->dev_desc = device_get_match_data(&client->dev); if (!iqs7211->dev_desc) return -ENODEV; shared_irq = iqs7211->dev_desc->num_ctx == IQS7211_MAX_CTX; /* * The RDY pin behaves as an interrupt, but must also be polled ahead * of unsolicited I2C communication. As such, it is first opened as a * GPIO and then passed to gpiod_to_irq() to register the interrupt. * * If an extra CTx pin is present, the RDY and MCLR pins are combined * into a single bidirectional pin. In that case, the platform's GPIO * must be configured as an open-drain output. */ iqs7211->irq_gpio = devm_gpiod_get(&client->dev, "irq", shared_irq ? GPIOD_OUT_LOW : GPIOD_IN); if (IS_ERR(iqs7211->irq_gpio)) { error = PTR_ERR(iqs7211->irq_gpio); dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n", error); return error; } if (shared_irq) { iqs7211->reset_gpio = iqs7211->irq_gpio; } else { iqs7211->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(iqs7211->reset_gpio)) { error = PTR_ERR(iqs7211->reset_gpio); dev_err(&client->dev, "Failed to request reset GPIO: %d\n", error); return error; } } error = iqs7211_start_comms(iqs7211); if (error) return error; for (reg_grp = 0; reg_grp < IQS7211_NUM_REG_GRPS; reg_grp++) { const char *reg_grp_name = iqs7211_reg_grp_names[reg_grp]; struct fwnode_handle *reg_grp_node; if (reg_grp_name) reg_grp_node = device_get_named_child_node(&client->dev, reg_grp_name); else reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev)); if (!reg_grp_node) continue; error = iqs7211_parse_reg_grp(iqs7211, reg_grp_node, reg_grp); fwnode_handle_put(reg_grp_node); if (error) return error; } error = iqs7211_register_kp(iqs7211); if (error) return error; error = iqs7211_register_tp(iqs7211); if (error) return error; error = iqs7211_init_device(iqs7211); if (error) return error; irq = gpiod_to_irq(iqs7211->irq_gpio); if (irq < 0) return irq; irq_flags = gpiod_is_active_low(iqs7211->irq_gpio) ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; irq_flags |= IRQF_ONESHOT; error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7211_irq, irq_flags, client->name, iqs7211); if (error) dev_err(&client->dev, "Failed to request IRQ: %d\n", error); return error; } static struct i2c_driver iqs7211_i2c_driver = { .probe = iqs7211_probe, .driver = { .name = "iqs7211", .of_match_table = iqs7211_of_match, .dev_groups = iqs7211_groups, .pm = pm_sleep_ptr(&iqs7211_pm), }, }; module_i2c_driver(iqs7211_i2c_driver); MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); MODULE_DESCRIPTION("Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller"); MODULE_LICENSE("GPL");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1