// SPDX-License-Identifier: GPL-2.0+
/*
* Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
*
* Copyright (C) 2018 Jeff LaBundy <jeff@labundy.com>
*
* These devices require firmware exported from a PC-based configuration tool
* made available by the vendor. Firmware files may be pushed to the device's
* nonvolatile memory by writing the filename to the 'fw_file' sysfs control.
*
* Link to PC-based configuration tool and datasheet: https://www.azoteq.com/
*/
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/firmware.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/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#define IQS5XX_FW_FILE_LEN 64
#define IQS5XX_NUM_RETRIES 10
#define IQS5XX_NUM_CONTACTS 5
#define IQS5XX_WR_BYTES_MAX 2
#define IQS5XX_PROD_NUM_IQS550 40
#define IQS5XX_PROD_NUM_IQS572 58
#define IQS5XX_PROD_NUM_IQS525 52
#define IQS5XX_SHOW_RESET BIT(7)
#define IQS5XX_ACK_RESET BIT(7)
#define IQS5XX_SUSPEND BIT(0)
#define IQS5XX_RESUME 0
#define IQS5XX_SETUP_COMPLETE BIT(6)
#define IQS5XX_WDT BIT(5)
#define IQS5XX_ALP_REATI BIT(3)
#define IQS5XX_REATI BIT(2)
#define IQS5XX_TP_EVENT BIT(2)
#define IQS5XX_EVENT_MODE BIT(0)
#define IQS5XX_PROD_NUM 0x0000
#define IQS5XX_SYS_INFO0 0x000F
#define IQS5XX_SYS_INFO1 0x0010
#define IQS5XX_SYS_CTRL0 0x0431
#define IQS5XX_SYS_CTRL1 0x0432
#define IQS5XX_SYS_CFG0 0x058E
#define IQS5XX_SYS_CFG1 0x058F
#define IQS5XX_X_RES 0x066E
#define IQS5XX_Y_RES 0x0670
#define IQS5XX_EXP_FILE 0x0677
#define IQS5XX_CHKSM 0x83C0
#define IQS5XX_APP 0x8400
#define IQS5XX_CSTM 0xBE00
#define IQS5XX_PMAP_END 0xBFFF
#define IQS5XX_END_COMM 0xEEEE
#define IQS5XX_CHKSM_LEN (IQS5XX_APP - IQS5XX_CHKSM)
#define IQS5XX_APP_LEN (IQS5XX_CSTM - IQS5XX_APP)
#define IQS5XX_CSTM_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CSTM)
#define IQS5XX_PMAP_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CHKSM)
#define IQS5XX_REC_HDR_LEN 4
#define IQS5XX_REC_LEN_MAX 255
#define IQS5XX_REC_TYPE_DATA 0x00
#define IQS5XX_REC_TYPE_EOF 0x01
#define IQS5XX_BL_ADDR_MASK 0x40
#define IQS5XX_BL_CMD_VER 0x00
#define IQS5XX_BL_CMD_READ 0x01
#define IQS5XX_BL_CMD_EXEC 0x02
#define IQS5XX_BL_CMD_CRC 0x03
#define IQS5XX_BL_BLK_LEN_MAX 64
#define IQS5XX_BL_ID 0x0200
#define IQS5XX_BL_STATUS_NONE 0xEE
#define IQS5XX_BL_CRC_PASS 0x00
#define IQS5XX_BL_CRC_FAIL 0x01
#define IQS5XX_BL_ATTEMPTS 3
struct iqs5xx_dev_id_info {
__be16 prod_num;
__be16 proj_num;
u8 major_ver;
u8 minor_ver;
u8 bl_status;
} __packed;
struct iqs5xx_ihex_rec {
char start;
char len[2];
char addr[4];
char type[2];
char data[2];
} __packed;
struct iqs5xx_touch_data {
__be16 abs_x;
__be16 abs_y;
__be16 strength;
u8 area;
} __packed;
struct iqs5xx_status {
u8 sys_info[2];
u8 num_active;
__be16 rel_x;
__be16 rel_y;
struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
} __packed;
struct iqs5xx_private {
struct i2c_client *client;
struct input_dev *input;
struct gpio_desc *reset_gpio;
struct touchscreen_properties prop;
struct mutex lock;
struct iqs5xx_dev_id_info dev_id_info;
u8 exp_file[2];
};
static int iqs5xx_read_burst(struct i2c_client *client,
u16 reg, void *val, u16 len)
{
__be16 reg_buf = cpu_to_be16(reg);
int ret, i;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0,
.len = sizeof(reg_buf),
.buf = (u8 *)®_buf,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = (u8 *)val,
},
};
/*
* The first addressing attempt outside of a communication window fails
* and must be retried, after which the device clock stretches until it
* is available.
*/
for (i = 0; i < IQS5XX_NUM_RETRIES; i++) {
ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
if (ret == ARRAY_SIZE(msg))
return 0;
usleep_range(200, 300);
}
if (ret >= 0)
ret = -EIO;
dev_err(&client->dev, "Failed to read from address 0x%04X: %d\n",
reg, ret);
return ret;
}
static int iqs5xx_read_word(struct i2c_client *client, u16 reg, u16 *val)
{
__be16 val_buf;
int error;
error = iqs5xx_read_burst(client, reg, &val_buf, sizeof(val_buf));
if (error)
return error;
*val = be16_to_cpu(val_buf);
return 0;
}
static int iqs5xx_write_burst(struct i2c_client *client,
u16 reg, const void *val, u16 len)
{
int ret, i;
u16 mlen = sizeof(reg) + len;
u8 mbuf[sizeof(reg) + IQS5XX_WR_BYTES_MAX];
if (len > IQS5XX_WR_BYTES_MAX)
return -EINVAL;
put_unaligned_be16(reg, mbuf);
memcpy(mbuf + sizeof(reg), val, len);
/*
* The first addressing attempt outside of a communication window fails
* and must be retried, after which the device clock stretches until it
* is available.
*/
for (i = 0; i < IQS5XX_NUM_RETRIES; i++) {
ret = i2c_master_send(client, mbuf, mlen);
if (ret == mlen)
return 0;
usl