tegrakernel/kernel/nvidia/drivers/iio/proximity/nvs_iqs2x3.c

2906 lines
74 KiB
C

/* Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* The NVS = NVidia Sensor framework */
/* See nvs_iio.c and nvs.h for documentation */
/* See nvs_proximity.c and nvs_proximity.h for documentation */
/* !!!!!!!!!!!!!TODO: add IQS253 support */
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/nvs.h>
#include <linux/nvs_proximity.h>
#include <linux/nvs_iqs2x3.h>
#include <asm/atomic.h>
#define IQS_DRIVER_VERSION (22)
#define IQS_VENDOR "Azoteq"
#define IQS_NAME "iqs2x3"
#define IQS_NAME_IQS253 "iqs253"
#define IQS_NAME_IQS263 "iqs263"
#define IQS_NAME_SAR_PROXIMITY "SAR_proximity"
#define IQS_NAME_SAR_TOUCH "SAR_touch"
#define IQS_NAME_SAR_DELTA "SAR_delta"
#define IQS_NAME_SAR_DELTA_CH0 "SAR_delta_ch0"
#define IQS_NAME_SAR_DELTA_CH1 "SAR_delta_ch1"
#define IQS_NAME_SAR_DELTA_CH2 "SAR_delta_ch2"
#define IQS_NAME_SAR_DELTA_CH3 "SAR_delta_ch3"
#define IQS_GPIO_SAR_DBG_I2C_STR "debug_i2c"
#define IQS_DEVID_IQS253 (0x29)
#define IQS_DEVID_IQS263 (0x3C)
#define IQS_PART_253 (0)
#define IQS_PART_263 (1)
#define IQS_PART_N (2)
#define IQS_HW_DELAY_MS (10)
#define IQS_START_DELAY_MS (100)
#define IQS_PROX_MILLIAMP_MICRO (180000)
#define IQS_PROX_THRESHOLD (10)
#define IQS_MULTI_THRESHOLD (5)
/* configuration */
#define IQS_POLL_DLY_MS_MIN (1000)
#define IQS_POLL_DLY_MS_MAX (1000)
#define IQS_POLL_DLY_MS_WATCHDOG (30000)
#define IQS_I2C_STOP_DLY_NS (1000000) /* must be >= 1ms */
#define IQS_I2C_RETRY_N (10)
#define IQS_RDY_RETRY_N (25)
#define IQS_RDY_DELAY_N (2000)
#define IQS_RDY_DELAY_US_MIN (100)
#define IQS_RDY_DELAY_US_MAX (110)
/* proximity defines */
#define IQS_PROX_VERSION (1)
/* binary proximity when max_range and resolution are 1.0 */
#define IQS_PROX_MAX_RANGE_IVAL (1)
#define IQS_PROX_MAX_RANGE_MICRO (0)
#define IQS_PROX_RESOLUTION_IVAL (1)
#define IQS_PROX_RESOLUTION_MICRO (0)
#define IQS_PROX_MILLIAMP_IVAL (0)
/* devices */
#define IQS_DEV_PROX (0)
#define IQS_DEV_TOUCH (1)
#define IQS_DEV_HW_N (2)
#define IQS_DEV_DELTA (2)
#define IQS_DEV_DELTA0 (3)
#define IQS_DEV_DELTA1 (4)
#define IQS_DEV_DELTA2 (5)
#define IQS_DEV_DELTA3 (6)
#define IQS_DEV_N (7)
#define IQS_CH_N (4)
/* to allow code style rules */
#define IQS_FS_NANO NVS_FLOAT_SIGNIFICANCE_NANO
#define IQS_FS_MICRO NVS_FLOAT_SIGNIFICANCE_MICRO
/* delta test conditions */
#define IQS_DELTA_TEST0_N (3)
#define IQS_DELTA_TEST1_N (4)
/* debug message spew flags */
#define IQS_STS_GPIO_SAR (1 << NVS_STS_EXT_N)
#define IQS_STS_EXT_STATE (1 << (NVS_STS_EXT_N + 1))
/* regulator names in order of powering on */
static char *iqs_vregs[] = {
"vddhi",
};
static unsigned short iqs_i2c_addrs[] = {
0x44,
0x45,
0x46,
0x47,
};
static const struct i2c_device_id iqs_i2c_device_id[] = {
{ IQS_NAME_IQS253, 0 },
{ IQS_NAME_IQS263, 0 },
{ IQS_NAME, 0 },
{}
};
static char * const iqs_snsr_names[] = {
IQS_NAME_SAR_PROXIMITY,
IQS_NAME_SAR_TOUCH,
IQS_NAME_SAR_DELTA,
IQS_NAME_SAR_DELTA_CH0,
IQS_NAME_SAR_DELTA_CH1,
IQS_NAME_SAR_DELTA_CH2,
IQS_NAME_SAR_DELTA_CH3,
IQS_GPIO_SAR_DBG_I2C_STR,
};
enum IQS_GPIO_SAR_DBG {
IQS_GPIO_SAR_DBG_I2C = IQS_DEV_N, /* IQS_GPIO_SAR_DBG_I2C_STR align */
/* Additional debug uses for the SAR GPIO can be added here. Be sure
* to add the gpio_sar_dev_asrt enable string to iqs_snsr_names.
*/
IQS_GPIO_SAR_DBG_N,
};
enum IQS_OS {
IQS_OS_NONE = 0,
IQS_OS_VISIBLE, /* OS sees sensors */
IQS_OS_CONTROL, /* OS has control of sensors */
};
enum IQS_INFO {
IQS_INFO_STS = 0,
IQS_INFO_EXT_STATE_SPEW = 14,
IQS_INFO_GPIO_SAR_SPEW,
IQS_INFO_GPIO_RDY_INPUT,
IQS_INFO_GPIO_RDY_OUTPUT,
IQS_INFO_GPIO_SAR_OUTPUT,
IQS_INFO_REG_WR,
IQS_INFO_DBG,
};
enum IQS_DB_CMD {
IQS_DB_CMD_INIT = 1,
IQS_DB_CMD_EN,
IQS_DB_CMD_DIS,
IQS_DB_CMD_EVNT,
IQS_DB_CMD_SUSPND,
IQS_DB_CMD_DELTA,
IQS_DB_CMD_EXT_LO,
IQS_DB_CMD_EXT_HI,
IQS_DB_CMD_N,
};
enum IQS_STREAM {
IQS_STREAM_OFF = 0,
IQS_STREAM_ALWAYS,
IQS_STREAM_AUTO,
IQS_STREAM_N,
};
struct iqs_delta_tst {
int ch;
int lt;
int gt;
};
static const char * const iqs_delta_tst_dt[] = {
"SAR_delta_test",
"SAR_delta_test_true",
"SAR_delta_test_false",
};
static unsigned char iqs263_wr_stream[] = {
2, 0x09, 0x00, 0x00, /* data */
0x18, 0x40, /* mask */
0 /* end - done - exit */
};
static unsigned char iqs253_wr_stream[] = {
16, 0xC4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x04, /* data */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x04, /* mask */
0, /* end - done - exit */
};
static unsigned char iqs263_wr_events[] = {
2, 0x09, 0x00, 0x40, /* data */
0x18, 0x40, /* mask */
0 /* end - done - exit */
};
static unsigned char iqs253_wr_events[] = {
16, 0xC4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x00, /* data */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x04, /* mask */
0 /* end - done - exit */
};
static unsigned char iqs263_wr_ati_redo[] = {
1, 0x09, 0x10, /* data */
0x18, /* mask */
0 /* end - done - exit */
};
static unsigned char iqs253_wr_ati_redo[] = {
14, 0xC4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, /* data */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x18, /* mask */
0 /* end - done - exit */
};
static unsigned char iqs263_wr_reseed[] = {
1, 0x09, 0x08, /* data */
0x18, /* mask */
0 /* end - done - exit */
};
static unsigned char iqs253_wr_reseed[] = {
14, 0xC4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, /* data */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x18, /* mask */
0 /* end - done - exit */
};
static unsigned char iqs263_wr_disable[] = {
3, 0x09, 0x00, 0x00, 0xC0, /* data */
0xFF, 0xFF, 0xFF, /* mask */
0 /* end - done - exit */
};
static unsigned char iqs253_wr_disable[] = {
/* TODO */
0 /* end - done - exit */
};
struct iqs_hal {
u8 reg;
u16 len;
u8 ndx;
bool wr;
};
/* RI = Register Init */
/* RL = Register Length */
/* BI = Buffer Index */
#define IQS_BI_DEVINF (0)
#define IQS_RL_DEVINF (2)
/* IQS263 */
#define IQS263_BI_SYSFLAGS (IQS_BI_DEVINF + \
IQS_RL_DEVINF + 1)
#define IQS263_RL_SYSFLAGS (2)
#define IQS263_BI_COORDINATES (IQS263_BI_SYSFLAGS + \
IQS263_RL_SYSFLAGS + 1)
#define IQS263_RL_COORDINATES (3)
#define IQS263_BI_TOUCH (IQS263_BI_COORDINATES + \
IQS263_RL_COORDINATES + 1)
#define IQS263_RL_TOUCH (2)
#define IQS263_BI_COUNTS (IQS263_BI_TOUCH + \
IQS263_RL_TOUCH + 1)
#define IQS263_RL_COUNTS (10)
#define IQS263_BI_LTA (IQS263_BI_COUNTS + \
IQS263_RL_COUNTS + 1)
#define IQS263_RL_LTA (10)
#define IQS263_BI_DELTAS (IQS263_BI_LTA + \
IQS263_RL_LTA + 1)
#define IQS263_RL_DELTAS (8)
#define IQS263_BI_MULTIPLIERS (IQS263_BI_DELTAS + \
IQS263_RL_DELTAS + 1)
#define IQS263_RL_MULTIPLIERS (5)
#define IQS263_BI_COMPENSATION (IQS263_BI_MULTIPLIERS + \
IQS263_RL_MULTIPLIERS + 1)
#define IQS263_RL_COMPENSATION (4)
#define IQS263_BI_PROXSETTINGS (IQS263_BI_COMPENSATION + \
IQS263_RL_COMPENSATION + 1)
#define IQS263_RL_PROXSETTINGS (5)
#define IQS263_BI_THRESHOLDS (IQS263_BI_PROXSETTINGS + \
IQS263_RL_PROXSETTINGS + 1)
#define IQS263_RL_THRESHOLDS (8)
#define IQS263_BI_TIMINGS (IQS263_BI_THRESHOLDS + \
IQS263_RL_THRESHOLDS + 1)
#define IQS263_RL_TIMINGS (3)
#define IQS263_BI_GESTURE_TIMERS (IQS263_BI_TIMINGS + \
IQS263_RL_TIMINGS + 1)
#define IQS263_RL_GESTURE_TIMERS (3)
#define IQS263_BI_ACTIVE_CH (IQS263_BI_GESTURE_TIMERS + \
IQS263_RL_GESTURE_TIMERS + 1)
#define IQS263_RL_ACTIVE_CH (1)
#define IQS263_BI_ENG (IQS263_BI_ACTIVE_CH + \
IQS263_RL_ACTIVE_CH + 1)
#define IQS263_RL_ENG (1)
#define IQS263_BI_N (IQS263_BI_ENG + \
IQS263_RL_ENG + 1)
/* IQS253 */
#define IQS253_BI_SYSFLAGS (IQS_BI_DEVINF + \
IQS_RL_DEVINF + 1)
#define IQS253_RL_SYSFLAGS (1)
#define IQS253_BI_PROXSTS (IQS253_BI_SYSFLAGS + \
IQS253_RL_SYSFLAGS + 1)
#define IQS253_RL_PROXSTS (1)
#define IQS253_BI_TOUCHSTS (IQS253_BI_PROXSTS + \
IQS253_RL_PROXSTS + 1)
#define IQS253_RL_TOUCHSTS (3)
#define IQS253_BI_HALT (IQS253_BI_TOUCHSTS + \
IQS253_RL_TOUCHSTS + 1)
#define IQS253_RL_HALT (1)
#define IQS253_BI_ACTIVE_CH (IQS253_BI_HALT + \
IQS253_RL_HALT + 1)
#define IQS253_RL_ACTIVE_CH (1)
#define IQS253_BI_COUNTS (IQS253_BI_ACTIVE_CH + \
IQS253_RL_ACTIVE_CH + 1)
#define IQS253_RL_COUNTS (2)
#define IQS253_BI_LTA (IQS253_BI_COUNTS + \
IQS253_RL_COUNTS + 1)
#define IQS253_RL_LTA (2)
#define IQS253_BI_SETTINGS (IQS253_BI_LTA + \
IQS253_RL_LTA + 1)
#define IQS253_RL_SETTINGS (26)
#define IQS253_BI_N (IQS253_BI_SETTINGS + \
IQS253_RL_SETTINGS + 1)
#if IQS263_BI_N < IQS253_BI_N
#define IQS_BI_N (IQS253_BI_N)
#else
#define IQS_BI_N (IQS263_BI_N)
#endif /* IQS263_BI_N < IQS253_BI_N */
static const struct iqs_hal const iqs263_hal_tbl[] = {
{ 0x00, IQS_RL_DEVINF, IQS_BI_DEVINF, false, },
{ 0x01, IQS263_RL_SYSFLAGS, IQS263_BI_SYSFLAGS, true, },
{ 0x02, IQS263_RL_COORDINATES, IQS263_BI_COORDINATES, false, },
{ 0x03, IQS263_RL_TOUCH, IQS263_BI_TOUCH, false, },
{ 0x04, IQS263_RL_COUNTS, IQS263_BI_COUNTS, false, },
{ 0x05, IQS263_RL_LTA, IQS263_BI_LTA, false, },
{ 0x06, IQS263_RL_DELTAS, IQS263_BI_DELTAS, false, },
{ 0x07, IQS263_RL_MULTIPLIERS, IQS263_BI_MULTIPLIERS, true, },
{ 0x08, IQS263_RL_COMPENSATION, IQS263_BI_COMPENSATION, true, },
{ 0x09, IQS263_RL_PROXSETTINGS, IQS263_BI_PROXSETTINGS, true, },
{ 0x0A, IQS263_RL_THRESHOLDS, IQS263_BI_THRESHOLDS, true, },
{ 0x0B, IQS263_RL_TIMINGS, IQS263_BI_TIMINGS, true, },
{ 0x0C, IQS263_RL_GESTURE_TIMERS, IQS263_BI_GESTURE_TIMERS, true, },
{ 0x0D, IQS263_RL_ACTIVE_CH, IQS263_BI_ACTIVE_CH, true, },
{ 0x48, IQS263_RL_ENG, IQS263_BI_ENG, true, },
};
static const struct iqs_hal const iqs253_hal_tbl[] = {
{ 0x00, IQS_RL_DEVINF, IQS_BI_DEVINF, false, },
{ 0x10, IQS253_RL_SYSFLAGS, IQS253_BI_SYSFLAGS, false, },
{ 0x31, IQS253_RL_PROXSTS, IQS253_BI_PROXSTS, false, },
{ 0x35, IQS253_RL_TOUCHSTS, IQS253_BI_TOUCHSTS, false, },
{ 0x39, IQS253_RL_HALT, IQS253_BI_HALT, false, },
{ 0x3D, IQS253_RL_ACTIVE_CH, IQS253_BI_ACTIVE_CH, false, },
{ 0x42, IQS253_RL_COUNTS, IQS253_BI_COUNTS, false, },
{ 0x83, IQS253_RL_LTA, IQS253_BI_LTA, true, },
{ 0xC4, IQS253_RL_SETTINGS, IQS253_BI_SETTINGS, true, },
};
#define IQS_DT_INIT_N (96) /* max DT init bytes */
#define IQS_DT_ABLE_N (32) /* max DT en/dis-able bytes */
#define IQS_DT_EVNT_N (32) /* max DT event bytes */
#define IQS_DT_EXT_N (32) /* max DT external state bytes */
#define IQS_DT_SUSPND_N (64) /* max DT suspend bytes */
#define IQS263_MSG_N (15)
#define IQS253_MSG_N (9)
#if IQS263_MSG_N < IQS253_MSG_N
#define IQS_MSG_N (IQS253_MSG_N * 2)
#else
#define IQS_MSG_N (IQS263_MSG_N * 2)
#endif /* IQS263_MSG_N < IQS253_MSG_N */
struct iqs_hal_iom {
u8 hal_i;
u8 offset;
u8 mask;
};
struct iqs_hal_bit {
struct iqs_hal_iom devinf_id;
struct iqs_hal_iom sysflag_reset;
struct iqs_hal_iom ati_err;
struct iqs_hal_iom ati_busy;
struct iqs_hal_iom event_mode;
struct iqs_hal_iom ati_partial;
struct iqs_hal_iom active_ch;
struct iqs_hal_iom lta;
struct iqs_hal_iom delta;
struct iqs_hal_iom multi_comp;
struct iqs_hal_iom multi_sens;
struct iqs_hal_iom touch_prx;
struct iqs_hal_iom touch_tch;
struct iqs_hal_iom count_prx;
struct iqs_hal_iom count_tch;
struct iqs_hal_iom thresh_prx;
struct iqs_hal_iom thresh_tch;
};
static const struct iqs_hal_bit iqs263_hal_bit = {
.devinf_id = {
.hal_i = 0,
.offset = 0,
.mask = 0xFF,
},
.sysflag_reset = {
.hal_i = 1,
.offset = 0,
.mask = 0x80,
},
.ati_err = {
.hal_i = 1,
.offset = 0,
.mask = 0x20,
},
.ati_busy = {
.hal_i = 1,
.offset = 0,
.mask = 0x04,
},
.event_mode = {
.hal_i = 9,
.offset = 1,
.mask = 0x40,
},
.ati_partial = {
.hal_i = 9,
.offset = 0,
.mask = 0x40,
},
.active_ch = {
.hal_i = 0x0D,
.offset = 0,
.mask = 0x0F,
},
.lta = {
.hal_i = 5,
.offset = 0,
.mask = 0xFF,
},
.delta = {
.hal_i = 6,
.offset = 0,
.mask = 0xFF,
},
.multi_comp = {
.hal_i = 7,
.offset = 0,
.mask = 0x0F,
},
.multi_sens = {
.hal_i = 7,
.offset = 0,
.mask = 0x30,
},
.touch_prx = {
.hal_i = 3,
.offset = 0,
.mask = 0x01,
},
.touch_tch = {
.hal_i = 3,
.offset = 0,
.mask = 0x0E,
},
.count_prx = {
.hal_i = 4,
.offset = 0,
.mask = 1,
},
.count_tch = {
.hal_i = 4,
.offset = 4,
.mask = 3,
},
.thresh_prx = {
.hal_i = 10,
.offset = 0,
.mask = 1,
},
.thresh_tch = {
.hal_i = 10,
.offset = 1,
.mask = 3,
},
};
static const struct iqs_hal_bit iqs253_hal_bit = {
.devinf_id = {
.hal_i = 0,
.offset = 0,
.mask = 0xFF,
},
.sysflag_reset = {
.hal_i = 1,
.offset = 0,
.mask = 0x20,
},
.thresh_prx = {
.hal_i = 10,
.offset = 0,
.mask = 1,
},
.thresh_tch = {
.hal_i = 10,
.offset = 1,
.mask = 3,
},
.count_prx = {
.hal_i = 4,
.offset = 0,
.mask = 1,
},
.count_tch = {
.hal_i = 4,
.offset = 4,
.mask = 3,
},
};
struct iqs_state {
struct i2c_client *i2c;
struct nvs_fn_if *nvs;
struct sensor_cfg cfg[IQS_DEV_N];
struct delayed_work dw;
struct regulator_bulk_data vreg[ARRAY_SIZE(iqs_vregs)];
struct nvs_proximity prox[IQS_DEV_N];
unsigned int sts; /* status flags */
unsigned int errs; /* error count */
unsigned int enabled; /* enable status */
unsigned int susrsm_en; /* suspend/resume enable status */
unsigned int dfr_rsm_ms; /* ms to wait before resuming */
u16 i2c_addr; /* I2C address */
u8 dev_id; /* device ID */
bool irq_dis; /* interrupt disable flag */
bool irq_set_irq_wake; /* if irq_set_irq_wake is enabled */
bool irq_trigger_edge; /* if irq set for edge trigger */
bool suspend_dis; /* active during suspend */
bool susrsm; /* suspend/resume - exit I2C early */
bool resume; /* resume action needed */
int op_i; /* operational index */
int op_read_n; /* operational register read count */
int op_read_reg[IQS_DEV_N + 2]; /* operational registers to read */
unsigned int part_i; /* part index */
unsigned int dbg; /* nvs debug interface */
unsigned int os; /* OS options */
unsigned int stream; /* configured for stream mode only */
unsigned int delta_ch_msk; /* delta sensors enable channel mask */
unsigned int delta_avg_n; /* delta sensors moving average cnt */
unsigned int dbnc_lo[IQS_DEV_HW_N]; /* binary low debounce */
unsigned int dbnc_hi[IQS_DEV_HW_N]; /* binary high debounce */
unsigned int dbnc_lo_n[IQS_DEV_HW_N]; /* binary low debounce count */
unsigned int dbnc_hi_n[IQS_DEV_HW_N]; /* binary high debounce count */
unsigned int ati_redo_n; /* ATI redo count */
unsigned int wd_to_ms; /* watchdog timeout ms */
unsigned int gpio_rdy_dly_n; /* GPIO RDY delay loop count */
unsigned int gpio_rdy_dly_min; /* GPIO RDY delay us min */
unsigned int gpio_rdy_dly_max; /* GPIO RDY delay us max */
unsigned int gpio_rdy_retry; /* GPIO RDY assert loop limit */
unsigned int i2c_retry; /* I2C transaction loop limit */
s64 i2c_ss_war_ns; /* I2C stop/start delay WAR */
s64 i2c_stop_ts; /* see IQS_I2C_STOP_DLY_NS */
int gpio_rdy; /* GPIO */
int gpio_sar; /* GPIO */
int gpio_sar_val; /* current GPIO state */
int gpio_sar_sus_asrt; /* GPIO assertion when suspending */
unsigned int gpio_sar_asrt_pol; /* GPIO SAR assert polarity */
unsigned int gpio_sar_dev_asrt; /* device that asserts SAR GPIO */
unsigned int gpio_sar_dev_dasrt; /* device that deasserts SAR GPIO */
unsigned int msg_n; /* I2C transaction count */
struct i2c_msg msg[IQS_MSG_N]; /* max possible I2C transactions */
const struct iqs_hal *hal_tbl; /* HAL register table */
unsigned int hal_tbl_n; /* HAL register table count */
const struct iqs_hal_bit *hal_bit; /* HAL for specific bits */
unsigned char *wr_disable; /* byte stream to disable device */
unsigned char *wr_stream; /* byte stream for stream mode */
unsigned char *wr_events; /* byte stream for event mode */
unsigned char *wr_ati_redo; /* byte stream to do ATI redo */
unsigned char *wr_reseed; /* byte stream to do reseed */
unsigned char dt_init[IQS_PART_N][IQS_DT_INIT_N]; /* DT byte stream */
unsigned char dt_en[IQS_PART_N][IQS_DEV_HW_N][IQS_DT_ABLE_N]; /* " */
unsigned char dt_dis[IQS_PART_N][IQS_DEV_HW_N][IQS_DT_ABLE_N]; /* " */
unsigned char dt_evnt[IQS_PART_N][IQS_DT_EVNT_N]; /* DT byte stream */
unsigned char dt_suspnd[IQS_PART_N][IQS_DT_SUSPND_N]; /* " */
unsigned char dt_ext_lo[IQS_PART_N][IQS_DT_EXT_N]; /* DT byte stream */
unsigned char dt_ext_hi[IQS_PART_N][IQS_DT_EXT_N]; /* DT byte stream */
u8 rc[IQS_BI_N]; /* register cache */
u16 *delta_avg[IQS_CH_N]; /* delta moving average data */
struct iqs_delta_tst delta_tst[IQS_DELTA_TEST0_N][IQS_DELTA_TEST1_N];
};
static int iqs_ext_sts;
static atomic_t iqs_ext_sts_chg = ATOMIC_INIT(0);
static void iqs_err(struct iqs_state *st)
{
st->errs++;
if (!st->errs)
st->errs--;
}
static void iqs_mutex_lock(struct iqs_state *st)
{
unsigned int i;
if (st->nvs) {
for (i = 0; i < IQS_DEV_N; i++) {
if (st->prox[i].nvs_st)
st->nvs->nvs_mutex_lock(st->prox[i].nvs_st);
}
}
}
static void iqs_mutex_unlock(struct iqs_state *st)
{
unsigned int i;
if (st->nvs) {
for (i = 0; i < IQS_DEV_N; i++) {
if (st->prox[i].nvs_st)
st->nvs->nvs_mutex_unlock(st->prox[i].nvs_st);
}
}
}
static unsigned int iqs_i2c_stop_ms(struct iqs_state *st)
{
s64 i2c_stop_t;
unsigned int ms = 0;
i2c_stop_t = nvs_timestamp() - st->i2c_stop_ts;
if (i2c_stop_t < st->i2c_ss_war_ns) {
i2c_stop_t = st->i2c_ss_war_ns - i2c_stop_t;
do_div(i2c_stop_t, 1000000); /* ns => ms */
ms = i2c_stop_t;
if (!ms)
ms = 1;
}
return ms;
}
static void iqs_enable_irq(struct iqs_state *st)
{
unsigned int ms;
unsigned int i;
if (st->irq_dis && st->i2c->irq) {
/* ensure IRQ is high after I2C STOP when enabling */
ms = iqs_i2c_stop_ms(st);
if (ms) {
ms <<= 1; /* *2 */
for (i = 0; i < ms; i++) {
if (gpio_get_value_cansleep(st->gpio_rdy))
break;
usleep_range(500, 1000);
}
}
enable_irq(st->i2c->irq);
st->irq_dis = false;
if (st->sts & NVS_STS_SPEW_IRQ)
dev_info(&st->i2c->dev, "%s delay=%ums\n",
__func__, ms >> 1);
}
}
static void iqs_irq_restore(struct iqs_state *st, bool disable)
{
if (!disable)
iqs_enable_irq(st);
}
static void iqs_disable_irq(struct iqs_state *st)
{
if ((!st->irq_dis) && st->i2c->irq) {
disable_irq_nosync(st->i2c->irq);
st->irq_dis = true;
if (st->sts & NVS_STS_SPEW_IRQ)
dev_info(&st->i2c->dev, "%s\n", __func__);
}
}
static int iqs_gpio_sar(struct iqs_state *st, int assert)
{
int gpio_sar_val;
int ret = 0;
if (st->gpio_sar >= 0) {
/* polarity assertion GPIO
* 0 0 1
* 0 1 0
* 1 0 0
* 1 1 1
*/
assert = !!assert;
gpio_sar_val = !(st->gpio_sar_asrt_pol ^ assert);
if (st->gpio_sar_val != gpio_sar_val) {
ret = gpio_direction_output(st->gpio_sar,
gpio_sar_val);
if (ret) {
dev_err(&st->i2c->dev,
"%s assert=%d gpio_sar %d=%d err=%d\n",
__func__, assert, st->gpio_sar,
gpio_sar_val, ret);
} else {
st->gpio_sar_val = gpio_sar_val;
if (st->sts & (NVS_STS_SPEW_MSG |
IQS_STS_GPIO_SAR))
dev_info(&st->i2c->dev,
"%s assert=%d gpio_sar %d=%d\n",
__func__, assert,
st->gpio_sar, gpio_sar_val);
}
}
} else {
ret = -EINVAL;
}
return ret;
}
static int iqs_gpio_rdy_poll(struct iqs_state *st)
{
unsigned int i;
int ret = 0;
for (i = 0; i < st->gpio_rdy_dly_n; i++) {
ret = gpio_get_value_cansleep(st->gpio_rdy);
if (st->susrsm || !ret)
break;
usleep_range((unsigned long)st->gpio_rdy_dly_min,
(unsigned long)st->gpio_rdy_dly_max);
}
return ret;
}
static int iqs_gpio_rdy(struct iqs_state *st, bool poll)
{
bool force = false;
unsigned int i = 0;
int ret;
if (poll)
ret = iqs_gpio_rdy_poll(st);
else
ret = gpio_get_value_cansleep(st->gpio_rdy);
if (ret && !st->susrsm) {
force = true;
iqs_disable_irq(st);
for (; i < st->gpio_rdy_retry; i++) {
gpio_direction_output(st->gpio_rdy, 0);
usleep_range(10000, 12000);
/* put to tristate */
gpio_direction_input(st->gpio_rdy);
ret = iqs_gpio_rdy_poll(st);
if (st->susrsm || !ret)
break;
}
}
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&st->i2c->dev,
"%s gpio_rdy=%d poll=%x force=%x retry=%u exit=%x\n",
__func__, ret, poll, force, i, st->susrsm);
return ret;
}
static unsigned int iqs_rc_i(struct iqs_state *st,
const struct iqs_hal_iom *iom)
{
unsigned int rc_i;
rc_i = st->hal_tbl[iom->hal_i].ndx + 1;
rc_i += iom->offset;
return rc_i;
}
static unsigned int iqs_bits_rd(struct iqs_state *st,
const struct iqs_hal_iom *iom,
unsigned int additional_offset)
{
return st->rc[iqs_rc_i(st, iom) + additional_offset] & iom->mask;
}
static int iqs_i2c(struct iqs_state *st, bool poll)
{
ssize_t t;
char spew[128];
unsigned int i;
unsigned int ms;
unsigned int n = 0;
int ret = -ENODEV;
if (st->i2c_addr && st->msg_n) {
#ifdef IQS_I2C_M_NO_RD_ACK
/* This IQS device mangles the I2C protocol for read restarts.
* In order to do I2C message stacking to avoid an I2C STOP
* that would end the communication window, the last read
* byte must not be acknowledged, and instead the restart done.
* Probably no normal I2C HW supports this thus requiring the
* I2C bus to be bit-banged.
* I2C_M_NO_RD_ACK probably wouldn't work (if supported)
* because it's just the last read byte that requires this,
* not all of them.
*/
for (i = 0; i < st->msg_n - 1; i++) {
if (st->msg[i].flags & I2C_M_RD)
st->msg[i].flags |= I2C_M_NO_RD_ACK;
}
#endif /* IQS_I2C_M_NO_RD_ACK */
for (i = 0; i < st->i2c_retry; i++) {
/* I2C transactions must be separated by a delay after
* the STOP is issued. Here we just ensure that the
* delay time has passed before issueing another
* transaction.
*/
ms = iqs_i2c_stop_ms(st);
if (ms)
msleep(ms);
if (iqs_gpio_rdy(st, poll)) {
ret = -EIO;
break;
}
/* Since this device has so many I2C issues, a debug
* feature is to use the SAR GPIO as a signal for when
* I2C transactions are actually done.
*/
if (st->gpio_sar_dev_asrt == IQS_GPIO_SAR_DBG_I2C)
iqs_gpio_sar(st, 1);
ret = i2c_transfer(st->i2c->adapter,
&st->msg[n], st->msg_n);
if (st->gpio_sar_dev_asrt == IQS_GPIO_SAR_DBG_I2C)
iqs_gpio_sar(st, 0);
st->i2c_stop_ts = nvs_timestamp();
if (ret == st->msg_n) {
ret = 0;
break;
} else {
if (ret < 0)
continue;
/* skip the successful messages */
n = ret;
while (n && st->msg[n].flags & I2C_M_RD)
n--;
st->msg_n -= n;
ret = -EIO;
}
}
if (ret && !st->susrsm)
iqs_err(st);
if (st->sts & NVS_STS_SPEW_MSG) {
st->msg_n += n;
if (i || ret)
dev_info(&st->i2c->dev,
"%s retry=%u poll=%x err=%d exit=%x\n",
__func__, i, poll, ret, st->susrsm);
for (i = 0; i < st->msg_n; i++) {
n = 0;
if (st->msg[i].flags & I2C_M_RD) {
t = snprintf(spew, PAGE_SIZE, "read=");
} else {
if (st->msg[i].len == 1) {
/* part of read transaction */
t = snprintf(spew, PAGE_SIZE,
"read %#2x=",
st->msg[i].buf[0]);
i++;
} else {
t = snprintf(spew, PAGE_SIZE,
"write %#2x=",
st->msg[i].buf[0]);
n = 1;
}
}
for (; n < st->msg[i].len; n++)
t += snprintf(spew + t, PAGE_SIZE - t,
"%#2x ",
st->msg[i].buf[n]);
dev_info(&st->i2c->dev, "%s %s\n",
__func__, spew);
}
}
} else {
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&st->i2c->dev,
"%s NO OP: i2c_addr=%hx msg_n=%u\n",
__func__, st->i2c_addr, st->msg_n);
}
st->msg_n = 0;
return ret;
}
static int iqs_i2c_rd(struct iqs_state *st, int hal_i, u16 len)
{
if (st->msg_n + 1 < ARRAY_SIZE(st->msg)) {
st->msg[st->msg_n].flags = 0;
st->msg[st->msg_n].len = 1;
st->msg[st->msg_n].buf = &st->rc[st->hal_tbl[hal_i].ndx];
st->msg_n++;
st->msg[st->msg_n].flags = I2C_M_RD;
if (len)
st->msg[st->msg_n].len = len;
else
st->msg[st->msg_n].len = st->hal_tbl[hal_i].len;
st->msg[st->msg_n].buf = &st->rc[st->hal_tbl[hal_i].ndx + 1];
st->msg_n++;
return 0;
}
return -EINVAL;
};
static int iqs_i2c_read(struct iqs_state *st, int hal_i, u16 len, bool poll)
{
iqs_i2c_rd(st, hal_i, len);
return iqs_i2c(st, poll);
};
static int iqs_i2c_wr(struct iqs_state *st, int hal_i, u16 len)
{
if (st->msg_n < ARRAY_SIZE(st->msg)) {
st->msg[st->msg_n].flags = 0;
if (len)
st->msg[st->msg_n].len = len + 1;
else
st->msg[st->msg_n].len = st->hal_tbl[hal_i].len + 1;
st->msg[st->msg_n].buf = &st->rc[st->hal_tbl[hal_i].ndx];
st->msg_n++;
return 0;
}
return -EINVAL;
};
static int iqs_i2c_write(struct iqs_state *st, int hal_i, u16 len,
bool poll, bool irq_restore)
{
bool irq_dis = st->irq_dis;
int ret;
iqs_i2c_wr(st, hal_i, len);
ret = iqs_i2c(st, poll);
if (irq_restore)
iqs_irq_restore(st, irq_dis);
return ret;
};
static int iqs_wr(struct iqs_state *st, unsigned char *wr)
{
u8 ndx = 0;
unsigned int msg_n = st->msg_n;
bool irq_dis;
unsigned int i;
unsigned int j;
unsigned int k;
unsigned char len;
unsigned char reg;
int hal_i;
int ret = 0;
if (!st->hal_tbl_n)
/* exit if HAL not initialized */
return -EINVAL;
i = 0;
while (wr[i] != 0) { /* while a length */
len = wr[i];
i++;
if (len == 0xFF) {
/* if length == FF then do an I2C write now */
if (st->msg_n) {
irq_dis = st->irq_dis;
ret |= iqs_i2c(st, false);
iqs_irq_restore(st, irq_dis);
}
if (wr[i])
msleep(wr[i]);
i++;
continue;
}
/* get the register */
reg = wr[i];
i++;
/* find the register and reg cache index in the hal table */
for (hal_i = st->hal_tbl_n - 1; hal_i > 0; hal_i--) {
if (st->hal_tbl[hal_i].reg == reg) {
if (st->hal_tbl[hal_i].len >= len) {
ndx = st->hal_tbl[hal_i].ndx + 1;
break;
} else {
dev_err(&st->i2c->dev,
"%s reg=%hhx ERR: len=%hhu\n",
__func__, reg, len);
/* length too long and need to exit */
return -EFAULT;
}
}
}
if (hal_i) {
/* if register and index found, mask data to cache */
for (j = 0; j < len; j++) {
k = ndx + j;
st->rc[k] &= ~wr[i + len];
st->rc[k] |= wr[i];
i++;
}
ret |= iqs_i2c_wr(st, hal_i, len);
i += len;
} else {
/* if register not found we're lost and need to exit */
dev_err(&st->i2c->dev,
"%s ERR: reg=%hhx not found. FYI: len=%hhu\n",
__func__, reg, len);
st->msg_n = msg_n;
return -EFAULT;
}
}
return ret;
};
static int iqs_write(struct iqs_state *st, unsigned char *wr,
bool poll, bool irq_restore)
{
bool irq_dis = st->irq_dis;
int ret;
ret = iqs_wr(st, wr);
if (st->msg_n) {
ret |= iqs_i2c(st, poll);
if (irq_restore)
iqs_irq_restore(st, irq_dis);
}
return ret;
}
static void iqs_op_rd(struct iqs_state *st)
{
bool prox_binary = false;
bool prox_full = false;
unsigned int i;
st->op_read_n = 0;
/* add multi_comp if ATI partial is enabled */
if (iqs_bits_rd(st, &st->hal_bit->ati_partial, 0)) {
st->op_read_reg[st->op_read_n] = st->hal_bit->multi_comp.hal_i;
st->op_read_n++;
}
/* always test for device reset */
st->op_read_reg[st->op_read_n] = st->hal_bit->sysflag_reset.hal_i;
st->op_read_n++;
/* read either binary data or full counts */
for (i = 0; i < IQS_DEV_HW_N; i++) {
if (st->enabled & (1 << i)) {
if (st->prox[i].proximity_binary_hw) {
if (!prox_binary) {
st->op_read_reg[st->op_read_n] =
st->hal_bit->touch_prx.hal_i;
prox_binary = true;
st->op_read_n++;
}
} else if (!prox_full) {
st->op_read_reg[st->op_read_n] =
st->hal_bit->count_prx.hal_i;
prox_full = true;
st->op_read_n++;
}
}
}
if (st->enabled & (st->delta_ch_msk << IQS_DEV_DELTA0)) {
st->op_read_reg[st->op_read_n] = st->hal_bit->lta.hal_i;
st->op_read_n++;
st->op_read_reg[st->op_read_n] = st->hal_bit->delta.hal_i;
st->op_read_n++;
}
st->op_i = st->op_read_n; /* force new read cycle */
}
static int iqs_stream(struct iqs_state *st, bool stream)
{
unsigned int event_mode = iqs_bits_rd(st, &st->hal_bit->event_mode, 0);
int ret = 0;
if (stream && event_mode)
ret = iqs_wr(st, st->wr_stream);
else if ((!stream) && (!event_mode))
ret = iqs_wr(st, st->wr_events);
else
ret = 1; /* no op */
return ret;
}
static int iqs_init(struct iqs_state *st)
{
bool stream = (st->stream == IQS_STREAM_ALWAYS) ? true : false;
int ret = 0;
if (st->hal_tbl_n) {
/* only if HAL initialized */
ret = iqs_wr(st, st->dt_init[st->part_i]);
ret |= iqs_stream(st, stream);
if (ret < 0) {
/* if an error then write separately */
ret = iqs_write(st, st->dt_init[st->part_i],
false, false);
if (!ret) {
ret = iqs_stream(st, stream);
if (!ret)
ret = iqs_i2c(st, false);
}
} else {
ret = iqs_i2c(st, false);
}
}
return ret;
}
static int iqs_en(struct iqs_state *st, int snsr_id)
{
int ret = 0;
if (snsr_id >= IQS_DEV_N)
return -EINVAL;
if (snsr_id < IQS_DEV_HW_N) {
st->dbnc_lo_n[snsr_id] = st->dbnc_lo[snsr_id];
st->dbnc_hi_n[snsr_id] = 0;
ret = iqs_write(st, st->dt_en[st->part_i][snsr_id],
false, false);
}
if (!ret)
ret = nvs_proximity_enable(&st->prox[snsr_id]);
return ret;
}
static int iqs_dis(struct iqs_state *st, int snsr_id)
{
unsigned char *wr = NULL;
int ret = 0;
if (snsr_id >= IQS_DEV_N)
return -EINVAL;
if (snsr_id < 0)
wr = st->wr_disable;
else if (snsr_id < IQS_DEV_HW_N)
wr = st->dt_dis[st->part_i][snsr_id];
if (st->hal_tbl_n && wr)
/* only if HAL initialized */
ret = iqs_write(st, wr, false, true);
return ret;
}
static int iqs_reenable(struct iqs_state *st)
{
unsigned int i;
int ret;
ret = iqs_init(st);
for (i = 0; i < IQS_DEV_N; i++) {
if (st->enabled & (1 << i))
ret |= iqs_en(st, i);
}
iqs_op_rd(st);
return ret;
}
static int iqs_reenable_err(struct iqs_state *st)
{
iqs_err(st);
iqs_reenable(st);
return RET_POLL_NEXT;
}
static int iqs_pm(struct iqs_state *st, bool enable)
{
int ret = 0;
if (enable) {
ret = nvs_vregs_enable(&st->i2c->dev, st->vreg,
ARRAY_SIZE(iqs_vregs));
if (ret > 0)
mdelay(IQS_HW_DELAY_MS);
} else {
ret = nvs_vregs_sts(st->vreg, ARRAY_SIZE(iqs_vregs));
if ((ret < 0) || (ret == ARRAY_SIZE(iqs_vregs))) {
ret = iqs_dis(st, -1);
} else if (ret > 0) {
nvs_vregs_enable(&st->i2c->dev, st->vreg,
ARRAY_SIZE(iqs_vregs));
mdelay(IQS_HW_DELAY_MS);
ret = iqs_dis(st, -1);
}
ret |= nvs_vregs_disable(&st->i2c->dev, st->vreg,
ARRAY_SIZE(iqs_vregs));
}
if (ret > 0)
ret = 0;
if (ret) {
dev_err(&st->i2c->dev, "%s pwr=%x ERR=%d\n",
__func__, enable, ret);
} else {
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&st->i2c->dev, "%s pwr=%x\n",
__func__, enable);
}
return ret;
}
static void iqs_pm_exit(struct iqs_state *st)
{
iqs_pm(st, false);
nvs_vregs_exit(&st->i2c->dev, st->vreg, ARRAY_SIZE(iqs_vregs));
}
static int iqs_pm_init(struct iqs_state *st)
{
int ret;
st->enabled = 0;
nvs_vregs_init(&st->i2c->dev,
st->vreg, ARRAY_SIZE(iqs_vregs), iqs_vregs);
ret = iqs_pm(st, true);
return ret;
}
static int iqs_delta_tst(struct iqs_state *st, int ch, int lt, int gt)
{
if (lt < 0 && gt < 0)
return -1;
ch += IQS_DEV_DELTA0;
if (lt >= 0 && gt >= 0) {
if (lt > gt) {
if (st->prox[ch].proximity < lt &&
st->prox[ch].proximity > gt)
return 1;
else
return 0;
} else {
if (st->prox[ch].proximity < lt ||
st->prox[ch].proximity > gt)
return 1;
else
return 0;
}
}
if (lt >= 0) {
if (st->prox[ch].proximity < lt)
return 1;
}
if (gt >= 0) {
if (st->prox[ch].proximity > gt)
return 1;
}
return 0;
}
static int iqs_rd_delta(struct iqs_state *st, s64 ts)
{
u16 hw;
u64 calc_i;
u64 calc_f;
s64 calc;
unsigned int ch;
unsigned int i;
unsigned int j;
int ret;
for (ch = 0; ch < IQS_CH_N; ch++) {
if (st->enabled & ((1 << ch) << IQS_DEV_DELTA0)) {
i = iqs_rc_i(st, &st->hal_bit->delta) + (ch << 1);
hw = (u16)st->rc[i];
st->prox[i].hw = hw;
if (st->delta_avg_n) {
memcpy(&st->delta_avg[ch][0],
&st->delta_avg[ch][1],
st->delta_avg_n - 1);
st->delta_avg[ch][st->delta_avg_n - 1] = hw;
calc_i = 0;
for (i = 0; i < st->delta_avg_n; i++)
calc_i += st->delta_avg[ch][i];
do_div(calc_i, st->delta_avg_n);
hw = (u16)calc_i;
}
calc_i = hw;
calc_f = 0;
if (st->cfg[i].scale.fval) {
i = IQS_DEV_DELTA0 + ch;
if (st->cfg[i].resolution.fval) {
calc_f = (u64)hw *
st->cfg[i].resolution.fval;
do_div(calc_f, st->cfg[i].scale.fval);
}
if (st->cfg[i].resolution.ival) {
if (st->cfg[i].float_significance)
calc_i = IQS_FS_NANO;
else
calc_i = IQS_FS_MICRO;
do_div(calc_i, st->cfg[i].scale.fval);
calc_i *= (u64)(hw *
st->cfg[i].resolution.ival);
}
}
calc = (s64)(calc_i + calc_f);
if (st->sts & NVS_STS_SPEW_DATA)
dev_info(&st->i2c->dev,
"%s ch%u=%lld avg=%u hw=%hu %lld\n",
__func__, ch, calc, hw,
st->prox[i].hw, ts);
st->prox[i].timestamp = ts;
st->prox[i].proximity = (u32)calc;
st->nvs->handler(st->prox[i].nvs_st,
&st->prox[i].proximity,
st->prox[i].timestamp);
}
}
for (i = 0; i < IQS_DELTA_TEST0_N; i++) {
hw = 0;
for (j = 0; j < IQS_DELTA_TEST1_N; j++) {
if (st->delta_tst[i][j].ch < 0) {
break;
} else if (st->delta_tst[i][j].ch >= IQS_CH_N) {
break;
} else {
ret = iqs_delta_tst(st, st->delta_tst[i][j].ch,
st->delta_tst[i][j].lt,
st->delta_tst[i][j].gt);
if (ret < 0)
break;
hw = ret;
if (!ret)
break;
}
}
if (!hw)
i++;
}
st->prox[IQS_DEV_DELTA].timestamp = ts;
st->prox[IQS_DEV_DELTA].hw = hw;
st->prox[IQS_DEV_DELTA].proximity = (u32)hw;
st->nvs->handler(st->prox[IQS_DEV_DELTA].nvs_st,
&st->prox[IQS_DEV_DELTA].proximity,
st->prox[IQS_DEV_DELTA].timestamp);
return 0;
}
static int iqs_rd_snsr(struct iqs_state *st, s64 ts, int dev,
const struct iqs_hal_iom *tch,
const struct iqs_hal_iom *cnt)
{
u16 hw;
u16 rp; /* reported proximity */
int ret;
if (st->prox[dev].proximity_binary_hw) {
hw = (iqs_bits_rd(st, tch, 0));
rp = hw;
if (rp) {
st->dbnc_lo_n[dev] = 0;
if (st->dbnc_hi[dev]) {
if (st->dbnc_hi_n[dev] < st->dbnc_hi[dev]) {
st->dbnc_hi_n[dev]++;
rp = 0;
}
}
} else {
st->dbnc_hi_n[dev] = 0;
if (st->dbnc_lo[dev]) {
if (st->dbnc_lo_n[dev] < st->dbnc_lo[dev]) {
st->dbnc_lo_n[dev]++;
rp = 1;
}
}
}
/* reverse polarity for Android (0=close 1=far) */
rp = !rp;
} else {
hw = (u16)st->rc[iqs_rc_i(st, cnt)];
rp = hw;
}
st->prox[dev].hw = rp;
st->prox[dev].timestamp = ts;
ret = nvs_proximity_read(&st->prox[dev]);
if (st->sts & NVS_STS_SPEW_DATA)
dev_info(&st->i2c->dev,
"%s: hw=%hu rp=%hu %lld lo_n=%u hi_n=%u %lldns\n",
iqs_snsr_names[dev], hw, rp, ts,
st->dbnc_lo_n[dev], st->dbnc_hi_n[dev],
ts - st->prox[IQS_DEV_PROX].timestamp);
return ret;
}
static int iqs_ati_redo(struct iqs_state *st)
{
iqs_wr(st, st->wr_ati_redo);
st->ati_redo_n++;
if (!st->ati_redo_n)
st->ati_redo_n--;
/* restart read cycle to get status */
st->op_i = st->op_read_n;
return RET_NO_CHANGE;
}
static int iqs_rd(struct iqs_state *st, bool poll)
{
s64 ts;
unsigned int i;
unsigned int k;
unsigned int ch;
int mc;
int ret = 0;
#ifdef IQS_I2C_M_NO_RD_ACK
/* I2C message stacking */
for (i = 0; i < st->op_read_n; i++)
iqs_i2c_rd(st, st->op_read_reg[i], 0);
ret = iqs_i2c(st, true);
#else /* IQS_I2C_M_NO_RD_ACK */
if (atomic_xchg(&iqs_ext_sts_chg, 0)) {
/* DT WAR action based on external state */
if (iqs_ext_sts)
iqs_wr(st, st->dt_ext_hi[st->part_i]);
else
iqs_wr(st, st->dt_ext_lo[st->part_i]);
st->op_i = st->op_read_n; /* restart cycle */
}
st->op_i++;
if (st->op_i >= st->op_read_n) {
st->op_i = 0; /* restart read cycle */
/* when slider is enabled then device automatically goes into
* and stays in stream mode during the slider event. The DT
* stream_mode should be set to (IQS_STREAM_AUTO) for this.
*/
if ((st->stream == IQS_STREAM_OFF) || !poll) {
/* enter stream mode on first I2C transaction if DT
* stream_mode IQS_STREAM_OFF OR not polling
*/
ret = iqs_stream(st, true);
if (!ret)
/* was in event mode */
poll = false; /* need to force mode switch */
}
} else if (st->op_i == 1) {
iqs_wr(st, st->dt_evnt[st->part_i]); /* DT additional action */
}
if (st->op_i == st->op_read_n - 1) {
/* at the end of read cycle */
if (st->stream != IQS_STREAM_ALWAYS)
iqs_stream(st, false); /* event mode at end of reads */
}
iqs_i2c_rd(st, st->op_read_reg[st->op_i], 0);
ret = iqs_i2c(st, poll);
#endif /* IQS_I2C_M_NO_RD_ACK */
if (ret) {
#if 0
/* device needs to be power cycled */
iqs_pm(st, false);
iqs_pm(st, true);
return iqs_reenable_err(st);
#endif /* 0 */
} else {
/* test for device reset */
if (st->op_read_reg[st->op_i] ==
st->hal_bit->sysflag_reset.hal_i) {
if (iqs_bits_rd(st, &st->hal_bit->sysflag_reset, 0))
/* an error occurred so reinitialization */
return iqs_reenable_err(st);
if (iqs_bits_rd(st, &st->hal_bit->ati_busy, 0)) {
/* restart read cycle to get status */
st->op_i = st->op_read_n;
return RET_NO_CHANGE;
}
if (iqs_bits_rd(st, &st->hal_bit->ati_err, 0))
/* ATI redo on next I2C access */
return iqs_ati_redo(st);
}
/* test for partial ATI */
if (st->op_read_reg[st->op_i] ==
st->hal_bit->multi_comp.hal_i) {
/* check if reseed needed */
ch = iqs_bits_rd(st, &st->hal_bit->active_ch, 0);
for (i = 0; i < IQS_CH_N; i++) {
if (ch & (1 << i)) {
mc = iqs_bits_rd(st,
&st->hal_bit->multi_comp, i);
if (i)
k = IQS_DEV_TOUCH;
else
k = IQS_DEV_PROX;
if (mc > st->cfg[k].thresh_hi) {
/* reseed on next I2C access */
iqs_wr(st, st->wr_reseed);
/* restart cycle for status */
st->op_i = st->op_read_n;
break;
}
}
}
}
/* read data */
ts = nvs_timestamp();
if (st->enabled & (1 << IQS_DEV_PROX))
ret |= iqs_rd_snsr(st, ts, IQS_DEV_PROX,
&st->hal_bit->touch_prx,
&st->hal_bit->count_prx);
if (st->enabled & (1 << IQS_DEV_TOUCH))
ret |= iqs_rd_snsr(st, ts, IQS_DEV_TOUCH,
&st->hal_bit->touch_tch,
&st->hal_bit->count_tch);
if (st->enabled & (st->delta_ch_msk << IQS_DEV_DELTA0))
ret |= iqs_rd_delta(st, ts);
/* TODO: Expect the PO pin used for proximity_binary_hw.
* Use a proximity threshold for SAR GPIO so that
* proximity doesn't have to be in HW binary mode.
*/
if (st->gpio_sar_dev_asrt < IQS_DEV_N) {
/* SAR GPIO assert and deassert can be controlled by
* separate sources.
* GPIO polarity | XOR asserted
* 0 0 | 0 1
* 0 1 | 1 0
* 1 0 | 1 0
* 1 1 | 0 1
*/
if (st->gpio_sar_val ^ st->gpio_sar_asrt_pol)
/* currently deasserted */
iqs_gpio_sar(st, !st->prox[st->
gpio_sar_dev_asrt].proximity);
else
/* currently asserted */
iqs_gpio_sar(st, !st->prox[st->
gpio_sar_dev_dasrt].proximity);
}
}
if (st->stream == IQS_STREAM_ALWAYS) {
/* with stream always on we want to control the IRQ rate */
if (ret != RET_NO_CHANGE) {
/* keep IRQ enabled if anything but no change */
ret = RET_HW_UPDATE;
} else if (st->op_i == st->op_read_n - 1) {
/* throttle IRQ at end of read cycle */
iqs_disable_irq(st);
ret = RET_POLL_NEXT;
}
}
return ret;
}
static int iqs_disable(struct iqs_state *st, int snsr_id)
{
bool disable = true;
unsigned int i;
int ret = 0;
if (snsr_id >= 0) {
ret = iqs_dis(st, snsr_id);
if (!ret)
st->enabled &= ~(1 << snsr_id);
if (st->enabled)
disable = false;
} else {
for (i = 0; i < IQS_DEV_N; i++) {
if (st->enabled & (1 << i))
iqs_dis(st, i);
}
}
if (disable) {
iqs_disable_irq(st);
if (st->dw.work.func)
cancel_delayed_work(&st->dw);
ret = iqs_pm(st, false);
if (!ret)
st->enabled = 0;
}
return ret;
}
static int iqs_enable(struct iqs_state *st, int snsr_id, int enable)
{
int ret;
if (enable) {
enable = st->enabled | (1 << snsr_id);
ret = iqs_pm(st, true);
if (!ret) {
if (!st->enabled)
ret = iqs_init(st);
ret |= iqs_en(st, snsr_id);
if (ret < 0) {
iqs_disable(st, snsr_id);
} else {
st->enabled = enable;
iqs_op_rd(st);
mod_delayed_work(system_freezable_wq, &st->dw,
msecs_to_jiffies(IQS_START_DELAY_MS));
}
}
} else {
ret = iqs_disable(st, snsr_id);
}
return ret;
}
static int iqs_enables(struct iqs_state *st, unsigned int en_mask)
{
unsigned int i;
int ret = 0;
for (i = 0; i < IQS_DEV_N; i++) {
if (en_mask & (1 << i))
ret |= iqs_enable(st, i, 1);
}
return ret;
}
static unsigned int iqs_polldelay(struct iqs_state *st)
{
unsigned int poll_delay_ms = IQS_POLL_DLY_MS_MAX;
unsigned int i;
for (i = 0; i < IQS_DEV_HW_N; i++) {
if (st->enabled & (1 << i)) {
if (poll_delay_ms > st->prox[i].poll_delay_ms)
poll_delay_ms = st->prox[i].poll_delay_ms;
}
}
return poll_delay_ms;
}
static void iqs_read(struct iqs_state *st, bool poll)
{
unsigned int ms = st->wd_to_ms;
int ret;
iqs_mutex_lock(st);
if (st->resume) {
if (st->suspend_dis) {
ret = iqs_reenable(st);
} else {
ret = iqs_enables(st, st->susrsm_en);
st->susrsm_en &= ~st->enabled;
}
if (ret) {
if (st->sts & NVS_STS_SPEW_MSG)
dev_err(&st->i2c->dev,
"%s resume ERR=%d Try again in %ums\n",
__func__, ret, ms);
} else {
st->resume = false;
st->susrsm_en = 0;
iqs_enable_irq(st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&st->i2c->dev, "%s resume complete\n",
__func__);
}
mod_delayed_work(system_freezable_wq, &st->dw,
msecs_to_jiffies(ms));
} else if (st->enabled) {
#ifdef IQS_I2C_M_NO_RD_ACK
ret = iqs_rd(st, poll);
if (ret > RET_POLL_NEXT)
iqs_enable_irq(st);
else
ms = iqs_polldelay(st);
#else /* IQS_I2C_M_NO_RD_ACK */
if (st->irq_dis) {
/* if IRQ disabled then in irq throttle mode */
iqs_enable_irq(st); /* IRQ driven mode */
} else {
ret = iqs_rd(st, poll);
if (ret > RET_POLL_NEXT)
iqs_enable_irq(st);
else
ms = iqs_polldelay(st);
}
#endif /* IQS_I2C_M_NO_RD_ACK */
/* always start a delayed work thread as a watchdog */
mod_delayed_work(system_freezable_wq, &st->dw,
msecs_to_jiffies(ms));
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&st->i2c->dev, "%s work delay=%ums\n",
__func__, ms);
}
iqs_mutex_unlock(st);
}
static void iqs_work(struct work_struct *ws)
{
struct iqs_state *st = container_of((struct delayed_work *)ws,
struct iqs_state, dw);
iqs_read(st, false);
}
static irqreturn_t iqs_irq_thread(int irq, void *dev_id)
{
struct iqs_state *st = (struct iqs_state *)dev_id;
iqs_read(st, true);
return IRQ_HANDLED;
}
static irqreturn_t iqs_irq_handler(int irq, void *dev_id)
{
struct iqs_state *st = (struct iqs_state *)dev_id;
if (st->sts & NVS_STS_SPEW_IRQ)
dev_info(&st->i2c->dev, "%s\n", __func__);
return IRQ_WAKE_THREAD;
}
static int iqs_enable_os(void *client, int snsr_id, int enable)
{
struct iqs_state *st = (struct iqs_state *)client;
if (enable < 0)
return st->enabled & (1 << snsr_id);
if (st->os == IQS_OS_CONTROL || st->sts & (NVS_STS_SHUTDOWN |
NVS_STS_SUSPEND))
return iqs_enable(st, snsr_id, enable);
if (enable)
st->prox[snsr_id].report = st->cfg[snsr_id].report_n;
return 0;
}
static int iqs_batch(void *client, int snsr_id, int flags,
unsigned int period_us, unsigned int timeout_us)
{
struct iqs_state *st = (struct iqs_state *)client;
if (timeout_us)
/* timeout not supported (no HW FIFO) */
return -EINVAL;
st->prox[snsr_id].delay_us = period_us;
return 0;
}
static int iqs_thresh_lo(void *client, int snsr_id, int thresh)
{
struct iqs_state *st = (struct iqs_state *)client;
unsigned int hal_i;
unsigned int i;
unsigned int n;
int ret;
if (snsr_id >= IQS_DEV_DELTA && snsr_id <= IQS_DEV_DELTA3) {
st->cfg[snsr_id].thresh_lo = thresh;
return 0;
}
if (snsr_id == IQS_DEV_TOUCH) {
hal_i = st->hal_bit->thresh_tch.hal_i;
i = st->hal_bit->thresh_tch.offset + 1;
n = i + st->hal_bit->thresh_tch.mask;
} else {
hal_i = st->hal_bit->thresh_prx.hal_i;
i = st->hal_bit->thresh_prx.offset + 1;
n = i + st->hal_bit->thresh_prx.mask;
}
for (; i < n; i++) {
st->rc[st->hal_tbl[hal_i].ndx + i] = thresh & 0xFF;
thresh >>= 8;
}
ret = iqs_i2c_write(st, hal_i, 0, false, true);
if (!ret)
st->cfg[snsr_id].thresh_lo = thresh;
return ret;
}
static int iqs_regs(void *client, int snsr_id, char *buf)
{
struct iqs_state *st = (struct iqs_state *)client;
ssize_t t;
bool irq_dis;
unsigned int i;
unsigned int j;
unsigned int n;
int ret = 0;
iqs_mutex_lock(st);
irq_dis = st->irq_dis;
#ifdef IQS_I2C_M_NO_RD_ACK
/* I2C message stacking */
for (i = 0; i < st->hal_tbl_n; i++)
iqs_i2c_rd(st, i, 0);
ret = iqs_i2c(st, false);
t = snprintf(buf, PAGE_SIZE, "registers: (ERR=%d)\n", ret);
for (i = 0; i < st->hal_tbl_n; i++) {
n = st->hal_tbl[i].ndx;
t += snprintf(buf + t, PAGE_SIZE - t, "0x%hhx=", st->rc[n]);
n = st->hal_tbl[i].ndx + st->hal_tbl[i].len;
for (j = st->hal_tbl[i].ndx + 1; j <= n; j++)
t += snprintf(buf + t, PAGE_SIZE - t, "0x%hhx ",
st->rc[j]);
t += snprintf(buf + t, PAGE_SIZE - t, "\n");
}
#else /* IQS_I2C_M_NO_RD_ACK */
t = snprintf(buf, PAGE_SIZE, "registers:\n");
for (i = 0; i < st->hal_tbl_n; i++) {
ret = iqs_i2c_read(st, i, 0, false);
n = st->hal_tbl[i].ndx;
if (ret) {
t += snprintf(buf + t, PAGE_SIZE - t, "0x%hhx=ERR %d",
st->rc[n], ret);
} else {
t += snprintf(buf + t, PAGE_SIZE - t, "0x%hhx=",
st->rc[n]);
n = st->hal_tbl[i].ndx + st->hal_tbl[i].len;
for (j = st->hal_tbl[i].ndx + 1; j <= n; j++)
t += snprintf(buf + t, PAGE_SIZE - t,
"0x%hhx ", st->rc[j]);
t += snprintf(buf + t, PAGE_SIZE - t, "\n");
}
}
#endif /* IQS_I2C_M_NO_RD_ACK */
iqs_irq_restore(st, irq_dis);
iqs_mutex_unlock(st);
return t;
}
static int iqs_nvs_write(void *client, int snsr_id, unsigned int nvs)
{
struct iqs_state *st = (struct iqs_state *)client;
u8 val = (nvs >> 8) & 0xFF;
unsigned int offset;
unsigned int reg;
unsigned int i;
int ret = -EINVAL;
switch (nvs & 0xFF) {
case IQS_INFO_STS:
case IQS_INFO_DBG:
st->dbg = nvs;
return 0;
case IQS_INFO_EXT_STATE_SPEW:
st->sts ^= IQS_STS_EXT_STATE;
dev_info(&st->i2c->dev, "%s EXT_STATE_SPEW=%x\n",
__func__, !!(st->sts & IQS_STS_EXT_STATE));
return 0;
case IQS_INFO_GPIO_SAR_SPEW:
st->sts ^= IQS_STS_GPIO_SAR;
dev_info(&st->i2c->dev, "%s GPIO_SAR_SPEW=%x\n",
__func__, !!(st->sts & IQS_STS_GPIO_SAR));
return 0;
case IQS_INFO_GPIO_RDY_INPUT:
ret = gpio_direction_input(st->gpio_rdy);
dev_info(&st->i2c->dev,
"%s gpio_direction_input(gpio_rdy(%d))=%d\n",
__func__, st->gpio_rdy, ret);
return ret;
case IQS_INFO_GPIO_RDY_OUTPUT:
val = !!val;
ret = gpio_direction_output(st->gpio_rdy, val);
dev_info(&st->i2c->dev,
"%s gpio_direction_output(gpio_rdy(%d), %hhx)=%d\n",
__func__, st->gpio_rdy, val, ret);
return ret;
case IQS_INFO_GPIO_SAR_OUTPUT:
val = !!val;
if (st->gpio_sar >= 0) {
ret = gpio_direction_output(st->gpio_sar, val);
if (!ret)
st->gpio_sar_val = val;
}
dev_info(&st->i2c->dev,
"%s gpio_direction_output(gpio_sar(%d), %hhx)=%d\n",
__func__, st->gpio_sar, val, ret);
return ret;
case IQS_INFO_REG_WR:
offset = ((nvs >> 16) & 0xFF) + 1;
reg = (nvs >> 24) & 0xFF;
for (i = 0; i < st->hal_tbl_n; i++) {
if (st->hal_tbl[i].reg == reg) {
if (offset > st->hal_tbl[i].len)
break;
iqs_mutex_lock(st);
st->rc[st->hal_tbl[i].ndx + offset] = val;
ret = iqs_i2c_write(st, i, 0, false, true);
iqs_mutex_unlock(st);
dev_info(&st->i2c->dev,
"%s %x => %x + %u err=%d\n",
__func__, val, reg, offset - 1, ret);
return ret;
}
}
return ret;
default:
ret = 0;
break;
}
return ret;
}
static ssize_t iqs_nvs_dbg_db(struct iqs_state *st, char *buf, ssize_t t,
unsigned char *db)
{
unsigned int i;
unsigned int j;
unsigned int n;
i = 0;
while (db[i]) {
n = db[i];
i++;
if (n == 0xFF) {
t += snprintf(buf + t, PAGE_SIZE - t,
"flush write and mdelay=%hhu\n", db[i]);
i++;
continue;
}
t += snprintf(buf + t, PAGE_SIZE - t,
"len=%x reg=%x data/mask=", n, db[i]);
i++;
for (j = 0; j < n; j++)
t += snprintf(buf + t, PAGE_SIZE - t, "%x/%x ",
db[i + j], db[i + j + n]);
t += snprintf(buf + t, PAGE_SIZE - t, "\n");
i += (n << 1);
}
if (i == 0)
t += snprintf(buf + t, PAGE_SIZE - t, "<empty>\n");
return t;
}
static ssize_t iqs_nvs_dbg_tst(struct iqs_state *st, char *buf, ssize_t t,
struct iqs_delta_tst *tst)
{
if (tst->lt >= 0 && tst->gt >= 0) {
if (tst->lt > tst->gt)
t += snprintf(buf + t, PAGE_SIZE - t,
"if (ch%d > %d && ch%d < %d)\n",
tst->ch, tst->gt, tst->ch, tst->lt);
else
t += snprintf(buf + t, PAGE_SIZE - t,
"if (ch%d < %d || ch%d > %d)\n",
tst->ch, tst->lt, tst->ch, tst->gt);
return t;
}
if (tst->lt >= 0) {
t += snprintf(buf + t, PAGE_SIZE - t, "if (ch%d < %d)\n",
tst->ch, tst->lt);
return t;
}
if (tst->gt >= 0) {
t += snprintf(buf + t, PAGE_SIZE - t, "if (ch%d > %d)\n",
tst->ch, tst->gt);
return t;
}
t += snprintf(buf + t, PAGE_SIZE - t, "exit conditions\n");
return t;
}
static int iqs_nvs_read(void *client, int snsr_id, char *buf)
{
struct iqs_state *st = (struct iqs_state *)client;
u8 prt = (st->dbg >> 24) & 0xFF;
u8 cmd = (st->dbg >> 16) & 0xFF;
u8 dev = (st->dbg >> 8) & 0xFF;
ssize_t t = 0;
int i;
int j;
int n;
switch (st->dbg & 0xFF) {
case IQS_INFO_DBG:
if (cmd >= IQS_DB_CMD_N) {
t = snprintf(buf, PAGE_SIZE, "ERR: UNKNOWN COMMAND\n");
break;
}
if (cmd == IQS_DB_CMD_DELTA) {
t = snprintf(buf, PAGE_SIZE, "DELTA conditions:\n");
for (i = 0; i < IQS_DELTA_TEST0_N; i++) {
if (i)
t += snprintf(buf + t, PAGE_SIZE - t,
"if %s:\n",
iqs_delta_tst_dt[i]);
else
t += snprintf(buf + t, PAGE_SIZE - t,
"%s:\n",
iqs_delta_tst_dt[i]);
for (j = 0; j < IQS_DELTA_TEST1_N; j++) {
if (st->delta_tst[i][j].ch < 0)
break;
else if (st->delta_tst[i][j].ch >=
IQS_CH_N)
break;
else
t += iqs_nvs_dbg_tst(st,
buf, t,
&st->delta_tst[i][j]);
}
}
return t;
}
if (!prt) {
i = st->part_i;
} else if (prt == IQS_DEVID_IQS253) {
i = IQS_PART_253;
} else if (prt == IQS_DEVID_IQS263) {
i = IQS_PART_263;
} else {
t = snprintf(buf, PAGE_SIZE, "ERR: UNKNOWN PART\n");
break;
}
if (dev > IQS_DEV_HW_N) {
t = snprintf(buf, PAGE_SIZE, "ERR: UNKNOWN DEVICE\n");
break;
} else if (dev) {
n = dev;
dev--;
} else {
n = IQS_DEV_HW_N;
}
if (cmd == IQS_DB_CMD_INIT || !cmd) {
t += snprintf(buf + t, PAGE_SIZE - t,
"%s initialization:\n",
iqs_i2c_device_id[i].name);
t += iqs_nvs_dbg_db(st, buf, t, st->dt_init[i]);
}
if (cmd == IQS_DB_CMD_EN || !cmd) {
for (j = dev; j < n; j++) {
t += snprintf(buf + t, PAGE_SIZE - t,
"%s %s enable:\n",
iqs_i2c_device_id[i].name,
iqs_snsr_names[j]);
t += iqs_nvs_dbg_db(st, buf, t,
&st->dt_en[i][j][0]);
}
}
if (cmd == IQS_DB_CMD_DIS || !cmd) {
for (j = dev; j < n; j++) {
t += snprintf(buf + t, PAGE_SIZE - t,
"%s %s disable:\n",
iqs_i2c_device_id[i].name,
iqs_snsr_names[j]);
t += iqs_nvs_dbg_db(st, buf, t,
&st->dt_dis[i][j][0]);
}
}
if (cmd == IQS_DB_CMD_EVNT || !cmd) {
t += snprintf(buf + t, PAGE_SIZE - t, "%s event:\n",
iqs_i2c_device_id[i].name);
t += iqs_nvs_dbg_db(st, buf, t, st->dt_evnt[i]);
}
if (cmd == IQS_DB_CMD_SUSPND || !cmd) {
t += snprintf(buf + t, PAGE_SIZE - t, "%s suspend:\n",
iqs_i2c_device_id[i].name);
t += iqs_nvs_dbg_db(st, buf, t, st->dt_suspnd[i]);
}
if (cmd == IQS_DB_CMD_EXT_LO || !cmd) {
t += snprintf(buf + t, PAGE_SIZE - t,
"%s external_lo:\n",
iqs_i2c_device_id[i].name);
t += iqs_nvs_dbg_db(st, buf, t, st->dt_ext_lo[i]);
}
if (cmd == IQS_DB_CMD_EXT_HI || !cmd) {
t += snprintf(buf + t, PAGE_SIZE - t,
"%s external_hi:\n",
iqs_i2c_device_id[i].name);
t += iqs_nvs_dbg_db(st, buf, t, st->dt_ext_hi[i]);
}
break;
default:
t = snprintf(buf, PAGE_SIZE, "IQS driver v. %u\n",
IQS_DRIVER_VERSION);
t += snprintf(buf + t, PAGE_SIZE - t, "ATI redo count=%u\n",
st->ati_redo_n);
st->ati_redo_n = 0;
t += snprintf(buf + t, PAGE_SIZE - t, "os_options=%x\n",
st->os);
t += snprintf(buf + t, PAGE_SIZE - t, "stream_mode=%x\n",
st->stream);
t += snprintf(buf + t, PAGE_SIZE - t,
"watchdog_timeout_ms=%u\n", st->wd_to_ms);
t += snprintf(buf + t, PAGE_SIZE - t, "i2c_ss_delay_ns=%lld\n",
st->i2c_ss_war_ns);
t += snprintf(buf + t, PAGE_SIZE - t, "i2c_retry=%u\n",
st->i2c_retry);
t += snprintf(buf + t, PAGE_SIZE - t, "gpio_rdy_retry=%u\n",
st->gpio_rdy_retry);
t += snprintf(buf + t, PAGE_SIZE - t,
"gpio_rdy_delay_count=%u\n", st->gpio_rdy_dly_n);
t += snprintf(buf + t, PAGE_SIZE - t,
"gpio_rdy_delay_us_min=%u\n",
st->gpio_rdy_dly_min);
t += snprintf(buf + t, PAGE_SIZE - t,
"gpio_rdy_delay_us_max=%u\n",
st->gpio_rdy_dly_max);
if (st->gpio_rdy < 0)
t += snprintf(buf + t, PAGE_SIZE - t, "NO gpio_rdy\n");
else
t += snprintf(buf + t, PAGE_SIZE - t,
"gpio_rdy %d=%d\n", st->gpio_rdy,
gpio_get_value_cansleep(st->gpio_rdy));
if (st->gpio_sar < 0)
t += snprintf(buf + t, PAGE_SIZE - t, "NO gpio_sar\n");
else
t += snprintf(buf + t, PAGE_SIZE - t,
"gpio_sar %d=%d\n", st->gpio_sar,
gpio_get_value_cansleep(st->gpio_sar));
t += snprintf(buf + t, PAGE_SIZE - t,
"gpio_sar_assert_polarity=%d\n",
st->gpio_sar_asrt_pol);
t += snprintf(buf + t, PAGE_SIZE - t,
"gpio_sar_dev_assert=%s\n",
iqs_snsr_names[st->gpio_sar_dev_asrt]);
t += snprintf(buf + t, PAGE_SIZE - t,
"gpio_sar_dev_deassert=%s\n",
iqs_snsr_names[st->gpio_sar_dev_dasrt]);
t += snprintf(buf + t, PAGE_SIZE - t,
"gpio_sar_suspend_assert=%d\n",
st->gpio_sar_sus_asrt);
t += snprintf(buf + t, PAGE_SIZE - t,
"deferred_resume_ms=%u\n", st->dfr_rsm_ms);
t += snprintf(buf + t, PAGE_SIZE - t, "resume=%x\n",
st->resume);
for (i = 0; i < IQS_DEV_HW_N; i++) {
if (st->dbnc_lo[i])
t += snprintf(buf + t, PAGE_SIZE - t,
"%s_debounce_lo=%u\n",
iqs_snsr_names[i],
st->dbnc_lo[i]);
if (st->dbnc_hi[i])
t += snprintf(buf + t, PAGE_SIZE - t,
"%s_debounce_hi=%u\n",
iqs_snsr_names[i],
st->dbnc_hi[i]);
}
t += snprintf(buf + t, PAGE_SIZE - t,
"SAR_delta_channel_mask=%u\n", st->delta_ch_msk);
if (st->delta_ch_msk)
t += snprintf(buf + t, PAGE_SIZE - t,
"SAR_delta_average_count=%u\n",
st->delta_avg_n);
t += snprintf(buf + t, PAGE_SIZE - t, "irq=%d\n",
st->i2c->irq);
t += snprintf(buf + t, PAGE_SIZE - t, "irq_disable=%x\n",
st->irq_dis);
t += snprintf(buf + t, PAGE_SIZE - t, "irq_trigger_edge=%x\n",
st->irq_trigger_edge);
for (i = 0; i < IQS_DEV_HW_N; i++)
t += snprintf(buf + t, PAGE_SIZE - t,
"%s_binary_hw=%x\n", iqs_snsr_names[i],
st->prox[i].proximity_binary_hw);
}
st->dbg = IQS_INFO_STS;
return t;
}
static struct nvs_fn_dev iqs_fn_dev = {
.enable = iqs_enable_os,
.batch = iqs_batch,
.thresh_lo = iqs_thresh_lo,
.regs = iqs_regs,
.nvs_write = iqs_nvs_write,
.nvs_read = iqs_nvs_read,
};
int sar_external_status(int status)
{
iqs_ext_sts = status;
atomic_set(&iqs_ext_sts_chg, 1);
if (iqs_fn_dev.sts) {
if (*iqs_fn_dev.sts & (NVS_STS_SPEW_MSG | IQS_STS_EXT_STATE))
pr_info("%s status=%d\n", __func__, status);
}
return 0;
}
EXPORT_SYMBOL(sar_external_status);
#ifdef CONFIG_SUSPEND
static int iqs_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct iqs_state *st = i2c_get_clientdata(client);
unsigned int i;
int ret = 0;
s64 ts = 0; /* = 0 to fix compile */
if (st->sts & NVS_STS_SPEW_MSG)
ts = nvs_timestamp();
/* Due to the device's horrendous communication protocol that causes
* unacceptable delays, suspend flag is used to exit pending actions.
*/
st->susrsm = true;
iqs_mutex_lock(st);
st->susrsm = false;
st->sts |= NVS_STS_SUSPEND;
st->susrsm_en |= st->enabled;
/* determine if we'll be operational during suspend */
for (i = 0; i < IQS_DEV_HW_N; i++) {
if ((st->enabled & (1 << i)) && (st->cfg[i].flags &
SENSOR_FLAG_WAKE_UP))
break;
}
if (i < IQS_DEV_HW_N) {
st->suspend_dis = true; /* stay active during suspend */
/* DT additional action for suspend */
ret = iqs_write(st, st->dt_suspnd[st->part_i], false, false);
iqs_enable_irq(st);
irq_set_irq_wake(st->i2c->irq, 1);
st->irq_set_irq_wake = true;
} else {
st->suspend_dis = false;
iqs_disable(st, -1);
if (st->gpio_sar_sus_asrt >= 0)
iqs_gpio_sar(st, st->gpio_sar_sus_asrt);
}
if (st->dw.work.func)
/* turn off watchdog during suspend */
cancel_delayed_work(&st->dw);
iqs_mutex_unlock(st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s elapsed t=%lldns err=%d\n",
__func__, nvs_timestamp() - ts, ret);
return 0;
}
static int iqs_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct iqs_state *st = i2c_get_clientdata(client);
s64 ts = 0; /* = 0 to fix compile */
int ret = 0;
if (st->sts & NVS_STS_SPEW_MSG)
ts = nvs_timestamp();
st->susrsm = true;
iqs_mutex_lock(st);
st->susrsm = false;
if (st->irq_set_irq_wake) {
irq_set_irq_wake(st->i2c->irq, 0);
st->irq_set_irq_wake = false;
}
st->sts &= ~NVS_STS_SUSPEND;
if (st->susrsm_en) {
/* Due to the device's horrendous communication protocol that
* causes unacceptable delays, resume is deferred.
*/
st->resume = true;
mod_delayed_work(system_freezable_wq, &st->dw,
msecs_to_jiffies(st->dfr_rsm_ms));
}
iqs_mutex_unlock(st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s elapsed t=%lldns err=%d\n",
__func__, nvs_timestamp() - ts, ret);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(iqs_pm_ops, iqs_suspend, iqs_resume);
static void iqs_shutdown(struct i2c_client *client)
{
struct iqs_state *st = i2c_get_clientdata(client);
iqs_mutex_lock(st);
st->sts |= NVS_STS_SHUTDOWN;
iqs_disable(st, -1);
iqs_mutex_unlock(st);
if (st->sts & NVS_STS_SPEW_MSG)
dev_info(&client->dev, "%s\n", __func__);
}
static int iqs_remove(struct i2c_client *client)
{
struct iqs_state *st = i2c_get_clientdata(client);
unsigned int i;
iqs_shutdown(client);
if (st->nvs) {
for (i = 0; i < IQS_DEV_N; i++) {
if (st->prox[i].nvs_st)
st->nvs->remove(st->prox[i].nvs_st);
}
}
iqs_pm_exit(st);
for (i = 0; i < IQS_CH_N; i++)
kfree(st->delta_avg[i]);
dev_info(&client->dev, "%s\n", __func__);
return 0;
}
static void iqs_id_part(struct iqs_state *st, const char *part)
{
unsigned int i;
for (i = 0; i < IQS_DEV_N; i++)
st->cfg[i].part = part;
}
static int iqs_id_dev(struct iqs_state *st, const char *name)
{
unsigned int hal_i;
unsigned int i;
int ret = 1;
/* assume for initial dev id read */
st->hal_tbl = iqs263_hal_tbl;
st->hal_tbl_n = ARRAY_SIZE(iqs263_hal_tbl);
st->hal_bit = &iqs263_hal_bit;
for (i = 0; i < ARRAY_SIZE(st->msg); i++)
st->msg[i].addr = st->i2c_addr;
if (!strcmp(name, IQS_NAME_IQS263))
st->dev_id = IQS_DEVID_IQS263;
else if (!strcmp(name, IQS_NAME_IQS253))
st->dev_id = IQS_DEVID_IQS253;
if (!st->dev_id) {
hal_i = st->hal_bit->devinf_id.hal_i;
i = st->hal_bit->devinf_id.offset + 1;
ret = iqs_i2c_read(st, hal_i, i, false);
if (ret) {
st->hal_tbl_n = 0; /* disable PM I2C */
return ret;
} else {
i += st->hal_tbl[hal_i].ndx;
st->dev_id = st->rc[i];
}
}
switch (st->dev_id) {
case IQS_DEVID_IQS263:
BUG_ON(IQS263_MSG_N != ARRAY_SIZE(iqs263_hal_tbl));
iqs_id_part(st, IQS_NAME_IQS263);
st->part_i = IQS_PART_263;
st->wr_disable = iqs263_wr_disable;
st->wr_stream = iqs263_wr_stream;
st->wr_events = iqs263_wr_events;
st->wr_ati_redo = iqs263_wr_ati_redo;
st->wr_reseed = iqs263_wr_reseed;
break;
case IQS_DEVID_IQS253:
BUG_ON(IQS253_MSG_N != ARRAY_SIZE(iqs253_hal_tbl));
iqs_id_part(st, IQS_NAME_IQS253);
st->part_i = IQS_PART_253;
st->hal_tbl = iqs253_hal_tbl;
st->hal_tbl_n = ARRAY_SIZE(iqs253_hal_tbl);
st->hal_bit = &iqs253_hal_bit;
st->wr_disable = iqs253_wr_disable;
st->wr_stream = iqs253_wr_stream;
st->wr_events = iqs253_wr_events;
st->wr_ati_redo = iqs253_wr_ati_redo;
st->wr_reseed = iqs253_wr_reseed;
break;
default:
return -ENODEV;
}
for (i = 0; i < st->hal_tbl_n; i++)
/* fill in register addresses for I2C writes */
st->rc[st->hal_tbl[i].ndx] = st->hal_tbl[i].reg;
if (!ret)
dev_info(&st->i2c->dev, "%s found %s\n",
__func__, st->cfg[0].part);
return 0;
}
static int iqs_id_i2c(struct iqs_state *st, const char *name)
{
int i;
int ret;
for (i = 0; i < ARRAY_SIZE(iqs_i2c_addrs); i++) {
if (st->i2c->addr == iqs_i2c_addrs[i])
break;
}
if (i < ARRAY_SIZE(iqs_i2c_addrs)) {
st->i2c_addr = st->i2c->addr;
ret = iqs_id_dev(st, name);
} else {
name = IQS_NAME;
for (i = 0; i < ARRAY_SIZE(iqs_i2c_addrs); i++) {
st->i2c_addr = iqs_i2c_addrs[i];
ret = iqs_id_dev(st, name);
if (!ret)
break;
}
}
if (ret)
st->i2c_addr = 0;
return ret;
}
static const struct sensor_cfg iqs_cfg_dflt = {
.snsr_id = SENSOR_TYPE_PROXIMITY,
.ch_n = 1,
.ch_sz = 4,
.part = IQS_NAME,
.vendor = IQS_VENDOR,
.version = IQS_PROX_VERSION,
.max_range = {
.ival = IQS_PROX_MAX_RANGE_IVAL,
.fval = IQS_PROX_MAX_RANGE_MICRO,
},
.resolution = {
.ival = IQS_PROX_RESOLUTION_IVAL,
.fval = IQS_PROX_RESOLUTION_MICRO,
},
.milliamp = {
.ival = IQS_PROX_MILLIAMP_IVAL,
.fval = IQS_PROX_MILLIAMP_MICRO,
},
.delay_us_min = IQS_POLL_DLY_MS_MIN * 1000,
.delay_us_max = IQS_POLL_DLY_MS_MAX * 1000,
.flags = SENSOR_FLAG_ON_CHANGE_MODE |
SENSOR_FLAG_WAKE_UP,
.thresh_lo = IQS_PROX_THRESHOLD,
.thresh_hi = IQS_MULTI_THRESHOLD,
};
static int iqs_of_dt_db(struct iqs_state *st, struct device_node *dn,
char *name, unsigned char *dt_db, int db_n)
{
char str[16];
const char *charp;
unsigned int limit = IQS_MSG_N;
unsigned int i;
int n;
int lenp;
int ret;
n = 0;
for (i = 0; i < limit; i++) {
ret = snprintf(str, sizeof(str), "%s_%u", name, i);
if (ret <= 0) {
dev_err(&st->i2c->dev, "%s snprintf(%s_%u)\n",
__func__, name, i);
return -ENODEV;
}
charp = of_get_property(dn, str, &lenp);
if (charp) {
if (lenp < (db_n - n)) {
memcpy(&dt_db[n], charp, lenp);
if (dt_db[n] == 0xFF)
/* flush is done so limit extended */
limit = i + IQS_MSG_N;
n += lenp;
} else {
dev_err(&st->i2c->dev, "%s ERR: NOMEM @ %s\n",
__func__, str);
return -ENOMEM;
}
} else {
dt_db[n] = 0; /* terminate byte stream */
break;
}
}
return 0;
}
static int iqs_of_dt(struct iqs_state *st, struct device_node *dn)
{
char str[64];
char const *pchar;
const char *dev;
unsigned int part;
unsigned int i;
unsigned int j;
int ret;
/* just test if global disable */
ret = nvs_of_dt(dn, NULL, NULL);
if (ret == -ENODEV)
return -ENODEV;
/* default device specific parameters */
for (i = 0; i < IQS_DEV_N; i++) {
memcpy(&st->cfg[i], &iqs_cfg_dflt, sizeof(st->cfg[0]));
st->cfg[i].name = iqs_snsr_names[i];
st->prox[i].cfg = &st->cfg[i];
st->prox[i].hw_mask = 0xFFFF;
st->prox[i].proximity_binary_hw = true;
nvs_proximity_of_dt(&st->prox[i], dn, st->cfg[i].name);
}
for (i = 0; i <= IQS_CH_N; i++)
/* delta sensors default disable */
st->cfg[IQS_DEV_DELTA + i].snsr_id = -1;
st->wd_to_ms = IQS_POLL_DLY_MS_WATCHDOG;
st->dfr_rsm_ms = IQS_START_DELAY_MS;
st->i2c_ss_war_ns = IQS_I2C_STOP_DLY_NS;
st->i2c_retry = IQS_I2C_RETRY_N;
st->gpio_rdy_retry = IQS_RDY_RETRY_N;
st->gpio_rdy_dly_n = IQS_RDY_DELAY_N;
st->gpio_rdy_dly_min = IQS_RDY_DELAY_US_MIN;
st->gpio_rdy_dly_max = IQS_RDY_DELAY_US_MAX;
st->gpio_rdy = -1;
st->gpio_sar = -1;
st->gpio_sar_sus_asrt = -1;
for (i = 0; i < IQS_DELTA_TEST0_N; i++) {
for (j = 0; j < IQS_DELTA_TEST1_N; j++) {
st->delta_tst[i][j].ch = -1;
st->delta_tst[i][j].lt = -1;
st->delta_tst[i][j].gt = -1;
}
}
/* device tree parameters */
if (dn) {
/* device specific parameters */
for (i = 0; i < IQS_DEV_HW_N; i++) {
snprintf(str, sizeof(str), "%s_debounce_lo",
iqs_snsr_names[i]);
of_property_read_u32(dn, str, &st->dbnc_lo[i]);
snprintf(str, sizeof(str), "%s_debounce_hi",
iqs_snsr_names[i]);
of_property_read_u32(dn, str, &st->dbnc_hi[i]);
}
of_property_read_u32(dn, "SAR_delta_average_count",
&st->delta_avg_n);
if (st->delta_avg_n < 2)
st->delta_avg_n = 0;
if (!of_property_read_u32(dn, "SAR_delta_channel_mask",
&st->delta_ch_msk)) {
st->delta_ch_msk &= ((1 << IQS_CH_N) - 1);
if (st->delta_ch_msk) {
/* enable delta sensor(s) */
st->cfg[IQS_DEV_DELTA].snsr_id =
SENSOR_TYPE_PROXIMITY;
for (i = 0; i < IQS_CH_N; i++) {
if (st->delta_ch_msk & (1 << i)) {
j = IQS_DEV_DELTA0 + i;
st->cfg[j].snsr_id =
SENSOR_TYPE_PROXIMITY;
}
}
}
}
of_property_read_u32(dn, "os_options", &st->os);
of_property_read_u32(dn, "stream_mode", &st->stream);
if (st->stream >= IQS_STREAM_N) {
dev_err(&st->i2c->dev,
"%s ERR: stream_mode %u > %u limit\n",
__func__, st->stream, IQS_STREAM_N - 1);
st->stream = IQS_STREAM_OFF;
}
of_property_read_u32(dn, "deferred_resume_ms",
&st->dfr_rsm_ms);
i = 0;
of_property_read_u32(dn, "irq_trigger_edge", &i);
if (i)
st->irq_trigger_edge = true;
of_property_read_u32(dn, "watchdog_timeout_ms", &st->wd_to_ms);
i = IQS_I2C_STOP_DLY_NS;
of_property_read_u32(dn, "i2c_ss_delay_ns", &i);
st->i2c_ss_war_ns = i;
of_property_read_u32(dn, "i2c_retry", &st->i2c_retry);
of_property_read_u32(dn, "gpio_rdy_retry",
&st->gpio_rdy_retry);
of_property_read_u32(dn, "gpio_rdy_delay_count",
&st->gpio_rdy_dly_n);
of_property_read_u32(dn, "gpio_rdy_delay_us_min",
&st->gpio_rdy_dly_min);
of_property_read_u32(dn, "gpio_rdy_delay_us_max",
&st->gpio_rdy_dly_max);
if (!of_property_read_u32(dn, "gpio_sar_assert_polarity",
&st->gpio_sar_asrt_pol))
st->gpio_sar_asrt_pol = !!st->gpio_sar_asrt_pol;
if (!of_property_read_s32(dn, "gpio_sar_suspend_assert",
&st->gpio_sar_sus_asrt))
st->gpio_sar_sus_asrt = !!st->gpio_sar_sus_asrt;
st->gpio_rdy = of_get_named_gpio(dn, "gpio_rdy", 0);
st->gpio_sar = of_get_named_gpio(dn, "gpio_sar", 0);
if (!of_property_read_string(dn, "gpio_sar_dev_assert",
&pchar)) {
for (i = 0; i < ARRAY_SIZE(iqs_snsr_names); i++) {
if (!strcasecmp(pchar, iqs_snsr_names[i])) {
st->gpio_sar_dev_asrt = i;
break;
}
}
}
if (!of_property_read_string(dn, "gpio_sar_dev_deassert",
&pchar)) {
for (i = 0; i < ARRAY_SIZE(iqs_snsr_names); i++) {
if (!strcasecmp(pchar, iqs_snsr_names[i])) {
st->gpio_sar_dev_dasrt = i;
break;
}
}
}
ret = 0;
for (i = 0; i < IQS_PART_N; i++) {
if (i == 0)
part = 253;
else
part = 263;
snprintf(str, sizeof(str), "%uinit", part);
ret |= iqs_of_dt_db(st, dn, str, st->dt_init[i],
IQS_DT_INIT_N);
snprintf(str, sizeof(str), "%uevent", part);
ret |= iqs_of_dt_db(st, dn, str, st->dt_evnt[i],
IQS_DT_EVNT_N);
snprintf(str, sizeof(str), "%uexternal_lo", part);
ret |= iqs_of_dt_db(st, dn, str, st->dt_ext_lo[i],
IQS_DT_EXT_N);
snprintf(str, sizeof(str), "%uexternal_hi", part);
ret |= iqs_of_dt_db(st, dn, str, st->dt_ext_hi[i],
IQS_DT_EXT_N);
snprintf(str, sizeof(str), "%ususpend", part);
ret |= iqs_of_dt_db(st, dn, str, st->dt_suspnd[i],
IQS_DT_SUSPND_N);
for (j = 0; j < IQS_DEV_HW_N; j++) {
if (j == 0)
dev = "prox";
else
dev = "touch";
snprintf(str, sizeof(str), "%uen_%s",
part, dev);
ret |= iqs_of_dt_db(st, dn, str,
st->dt_en[i][j],
IQS_DT_ABLE_N);
snprintf(str, sizeof(str), "%udis_%s",
part, dev);
ret |= iqs_of_dt_db(st, dn, str,
st->dt_dis[i][j],
IQS_DT_ABLE_N);
}
}
if (ret)
return ret;
for (i = 0; i < IQS_DELTA_TEST0_N; i++) {
for (j = 0; j < IQS_DELTA_TEST1_N; j++) {
snprintf(str, sizeof(str), "%s_%u_ch",
iqs_delta_tst_dt[i], j);
of_property_read_s32(dn, str,
&st->delta_tst[i][j].ch);
snprintf(str, sizeof(str), "%s_%u_lt",
iqs_delta_tst_dt[i], j);
of_property_read_s32(dn, str,
&st->delta_tst[i][j].lt);
snprintf(str, sizeof(str), "%s_%u_gt",
iqs_delta_tst_dt[i], j);
of_property_read_s32(dn, str,
&st->delta_tst[i][j].gt);
}
}
}
for (i = 0; i < IQS_DEV_N; i++) {
for (j = 0; j < 3; j++) {
if (st->os)
/* change 'SAR' to 'sar' for OS visibility */
iqs_snsr_names[i][j] = tolower((unsigned char)
iqs_snsr_names[i][j]);
else
/* change 'sar' to 'SAR' */
iqs_snsr_names[i][j] = toupper((unsigned char)
iqs_snsr_names[i][j]);
}
}
if (gpio_is_valid(st->gpio_rdy)) {
ret = gpio_request(st->gpio_rdy, IQS_NAME);
if (ret) {
dev_err(&st->i2c->dev,
"%s gpio_request(%d %s) ERR:%d\n",
__func__, st->gpio_rdy, IQS_NAME, ret);
/* can't communicate with device without this GPIO */
return -EPROBE_DEFER;
} else {
ret = gpio_direction_input(st->gpio_rdy);
if (ret < 0) {
dev_err(&st->i2c->dev,
"%s gpio_direction_input(%d) ERR:%d\n",
__func__, st->gpio_rdy, ret);
return -ENODEV;
}
}
} else {
/* can't communicate with device without this GPIO */
return -EPROBE_DEFER;
}
if (gpio_is_valid(st->gpio_sar)) {
ret = gpio_request(st->gpio_sar, IQS_NAME);
if (ret) {
dev_err(&st->i2c->dev,
"%s gpio_request(%d %s) ERR:%d\n",
__func__, st->gpio_sar, IQS_NAME, ret);
} else {
/* start with SAR GPIO asserted */
st->gpio_sar_val = -1;
iqs_gpio_sar(st, 1);
}
}
return 0;
}
static int iqs_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct iqs_state *st;
unsigned long irqflags;
unsigned int en;
unsigned int i;
int ret;
dev_info(&client->dev, "%s\n", __func__);
st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL);
if (st == NULL) {
dev_err(&client->dev, "%s devm_kzalloc ERR\n", __func__);
return -ENOMEM;
}
i2c_set_clientdata(client, st);
st->i2c = client;
ret = iqs_of_dt(st, client->dev.of_node);
if (ret) {
if (ret == -ENODEV) {
dev_info(&client->dev, "%s DT disabled\n", __func__);
} else {
dev_err(&client->dev, "%s _of_dt ERR\n", __func__);
ret = -ENODEV;
}
goto iqs_probe_exit;
}
iqs_pm_init(st);
ret = iqs_id_i2c(st, id->name);
if (ret) {
dev_err(&client->dev, "%s _id_i2c ERR\n", __func__);
ret = -ENODEV;
goto iqs_probe_exit;
}
iqs_pm(st, false);
iqs_fn_dev.sts = &st->sts;
iqs_fn_dev.errs = &st->errs;
st->nvs = nvs_iio();
if (st->nvs == NULL) {
ret = -ENODEV;
goto iqs_probe_exit;
}
en = 0;
for (i = 0; i < IQS_DEV_N; i++) {
nvs_of_dt(client->dev.of_node, &st->cfg[i], NULL);
ret = st->nvs->probe(&st->prox[i].nvs_st, st, &client->dev,
&iqs_fn_dev, &st->cfg[i]);
st->cfg[i].snsr_id = i;
if (!ret) {
st->prox[i].handler = st->nvs->handler;
en |= 1 << i;
}
}
if (!en) {
dev_err(&client->dev, "%s nvs_probe ERR\n", __func__);
ret = -ENODEV;
goto iqs_probe_exit;
}
INIT_DELAYED_WORK(&st->dw, iqs_work);
if (st->gpio_rdy > 0)
st->i2c->irq = gpio_to_irq(st->gpio_rdy);
if (client->irq) {
irqflags = IRQF_ONESHOT | IRQF_NO_THREAD;
if (st->irq_trigger_edge)
irqflags |= IRQF_TRIGGER_FALLING;
else
irqflags |= IRQF_TRIGGER_LOW;
for (i = 0; i < IQS_DEV_HW_N; i++) {
if (st->cfg[i].snsr_id >= 0) {
if (st->cfg[i].flags & SENSOR_FLAG_WAKE_UP)
irqflags |= IRQF_NO_SUSPEND;
}
}
ret = request_threaded_irq(client->irq,
iqs_irq_handler, iqs_irq_thread,
irqflags, IQS_NAME, st);
if (ret) {
dev_err(&client->dev, "%s req_threaded_irq ERR %d\n",
__func__, ret);
ret = -ENOMEM;
goto iqs_probe_exit;
}
}
if (st->delta_ch_msk && st->delta_avg_n) {
/* allocate data buffers for delta sensors moving average */
for (i = 0; i < IQS_CH_N; i++) {
st->delta_avg[i] = kzalloc(sizeof(*st->delta_avg[i] *
st->delta_avg_n),
GFP_KERNEL);
if (st->delta_avg[i] == NULL) {
dev_err(&client->dev,
"%s kzalloc delta_avg[%u] sz=%u ERR\n",
__func__, i, st->delta_avg_n << 1);
ret = -ENOMEM;
goto iqs_probe_exit;
}
}
}
iqs_mutex_lock(st);
if (st->os == IQS_OS_CONTROL) {
iqs_disable(st, -1);
} else {
ret = iqs_enables(st, en);
if (ret) {
dev_err(&client->dev, "%s auto enable ERR=%d\n",
__func__, ret);
/* use the resume execution to keep trying */
iqs_pm(st, true);
st->enabled = en;
st->susrsm_en = en;
st->resume = true;
mod_delayed_work(system_freezable_wq, &st->dw,
msecs_to_jiffies(IQS_START_DELAY_MS));
}
}
iqs_mutex_unlock(st);
dev_info(&client->dev, "%s done\n", __func__);
return 0;
iqs_probe_exit:
iqs_remove(client);
return ret;
}
MODULE_DEVICE_TABLE(i2c, iqs_i2c_device_id);
static const struct of_device_id iqs_of_match[] = {
{ .compatible = "azoteq,iqs2x3", },
{ .compatible = "azoteq,iqs253", },
{ .compatible = "azoteq,iqs263", },
{},
};
MODULE_DEVICE_TABLE(of, iqs_of_match);
static struct i2c_driver iqs_driver = {
.class = I2C_CLASS_HWMON,
.probe = iqs_probe,
.remove = iqs_remove,
.shutdown = iqs_shutdown,
.driver = {
.name = IQS_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(iqs_of_match),
.pm = &iqs_pm_ops,
},
.id_table = iqs_i2c_device_id,
};
module_i2c_driver(iqs_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IQS2X3 driver");
MODULE_AUTHOR("NVIDIA Corporation");