2023-05-29 19:34:00 -05:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Azoteq IQS7210A / 7211 A / 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.7 k 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 = & reg ,
} ,
{
. 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 ( & reg_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 " ,
2023-07-13 13:12:02 -05:00
. data = & iqs7211_devs [ IQS7210A ] ,
2023-05-29 19:34:00 -05:00
} ,
{
. compatible = " azoteq,iqs7211a " ,
2023-07-13 13:12:02 -05:00
. data = & iqs7211_devs [ IQS7211A ] ,
2023-05-29 19:34:00 -05:00
} ,
{
. compatible = " azoteq,iqs7211e " ,
2023-07-13 13:12:02 -05:00
. data = & iqs7211_devs [ IQS7211E ] ,
2023-05-29 19:34:00 -05:00
} ,
{ }
} ;
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 ) ;
2023-07-13 13:12:02 -05:00
iqs7211 - > dev_desc = device_get_match_data ( & client - > dev ) ;
if ( ! iqs7211 - > dev_desc )
return - ENODEV ;
2023-05-29 19:34:00 -05:00
2023-07-13 13:12:02 -05:00
shared_irq = iqs7211 - > dev_desc - > num_ctx = = IQS7211_MAX_CTX ;
2023-05-29 19:34:00 -05:00
/*
* 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 " ) ;