/*
* Weida HiTech WDT87xx TouchScreen I2C driver
*
* Copyright (c) 2015 Weida Hi-Tech Co., Ltd.
* HN Chen <hn.chen@weidahitech.com>
*
* This software is licensed under the terms of the GNU General Public
* License, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*/
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/firmware.h>
#include <linux/input/mt.h>
#include <linux/acpi.h>
#include <asm/unaligned.h>
#define WDT87XX_NAME "wdt87xx_i2c"
#define WDT87XX_FW_NAME "wdt87xx_fw.bin"
#define WDT87XX_CFG_NAME "wdt87xx_cfg.bin"
#define MODE_ACTIVE 0x01
#define MODE_READY 0x02
#define MODE_IDLE 0x03
#define MODE_SLEEP 0x04
#define MODE_STOP 0xFF
#define WDT_MAX_FINGER 10
#define WDT_RAW_BUF_COUNT 54
#define WDT_V1_RAW_BUF_COUNT 74
#define WDT_FIRMWARE_ID 0xa9e368f5
#define PG_SIZE 0x1000
#define MAX_RETRIES 3
#define MAX_UNIT_AXIS 0x7FFF
#define PKT_READ_SIZE 72
#define PKT_WRITE_SIZE 80
/* the finger definition of the report event */
#define FINGER_EV_OFFSET_ID 0
#define FINGER_EV_OFFSET_X 1
#define FINGER_EV_OFFSET_Y 3
#define FINGER_EV_SIZE 5
#define FINGER_EV_V1_OFFSET_ID 0
#define FINGER_EV_V1_OFFSET_W 1
#define FINGER_EV_V1_OFFSET_P 2
#define FINGER_EV_V1_OFFSET_X 3
#define FINGER_EV_V1_OFFSET_Y 5
#define FINGER_EV_V1_SIZE 7
/* The definition of a report packet */
#define TOUCH_PK_OFFSET_REPORT_ID 0
#define TOUCH_PK_OFFSET_EVENT 1
#define TOUCH_PK_OFFSET_SCAN_TIME 51
#define TOUCH_PK_OFFSET_FNGR_NUM 53
#define TOUCH_PK_V1_OFFSET_REPORT_ID 0
#define TOUCH_PK_V1_OFFSET_EVENT 1
#define TOUCH_PK_V1_OFFSET_SCAN_TIME 71
#define TOUCH_PK_V1_OFFSET_FNGR_NUM 73
/* The definition of the controller parameters */
#define CTL_PARAM_OFFSET_FW_ID 0
#define CTL_PARAM_OFFSET_PLAT_ID 2
#define CTL_PARAM_OFFSET_XMLS_ID1 4
#define CTL_PARAM_OFFSET_XMLS_ID2 6
#define CTL_PARAM_OFFSET_PHY_CH_X 8
#define CTL_PARAM_OFFSET_PHY_CH_Y 10
#define CTL_PARAM_OFFSET_PHY_X0 12
#define CTL_PARAM_OFFSET_PHY_X1 14
#define CTL_PARAM_OFFSET_PHY_Y0 16
#define CTL_PARAM_OFFSET_PHY_Y1 18
#define CTL_PARAM_OFFSET_PHY_W 22
#define CTL_PARAM_OFFSET_PHY_H 24
#define CTL_PARAM_OFFSET_FACTOR 32
/* The definition of the device descriptor */
#define WDT_GD_DEVICE 1
#define DEV_DESC_OFFSET_VID 8
#define DEV_DESC_OFFSET_PID 10
/* Communication commands */
#define PACKET_SIZE 56
#define VND_REQ_READ 0x06
#define VND_READ_DATA 0x07
#define VND_REQ_WRITE 0x08
#define VND_CMD_START 0x00
#define VND_CMD_STOP 0x01
#define VND_CMD_RESET 0x09
#define VND_CMD_ERASE 0x1A
#define VND_GET_CHECKSUM 0x66
#define VND_SET_DATA 0x83
#define VND_SET_COMMAND_DATA 0x84
#define VND_SET_CHECKSUM_CALC 0x86
#define VND_SET_CHECKSUM_LENGTH 0x87
#define VND_CMD_SFLCK 0xFC
#define VND_CMD_SFUNL 0xFD
#define CMD_SFLCK_KEY 0xC39B
#define CMD_SFUNL_KEY 0x95DA
#define STRIDX_PLATFORM_ID 0x80
#define STRIDX_PARAMETERS 0x81
#define CMD_BUF_SIZE 8
#define PKT_BUF_SIZE 64
/* The definition of the command packet */
#define CMD_REPORT_ID_OFFSET 0x0
#define CMD_TYPE_OFFSET 0x1
#define CMD_INDEX_OFFSET 0x2
#define CMD_KEY_OFFSET 0x3
#define CMD_LENGTH_OFFSET 0x4
#define CMD_DATA_OFFSET 0x8
/* The definition of firmware chunk tags */
#define FOURCC_ID_RIFF 0x46464952
#define FOURCC_ID_WHIF 0x46494857
#define FOURCC_ID_FRMT 0x544D5246
#define FOURCC_ID_FRWR 0x52575246
#define FOURCC_ID_CNFG 0x47464E43
#define CHUNK_ID_FRMT FOURCC_ID_FRMT
#define CHUNK_ID_FRWR FOURCC_ID_FRWR
#define CHUNK_ID_CNFG FOURCC_ID_CNFG
#define FW_FOURCC1_OFFSET 0
#define FW_SIZE_OFFSET 4
#define FW_FOURCC2_OFFSET 8
#define FW_PAYLOAD_OFFSET 40
#define FW_CHUNK_ID_OFFSET 0
#define FW_CHUNK_SIZE_OFFSET 4
#define FW_CHUNK_TGT_START_OFFSET 8
#define FW_CHUNK_PAYLOAD_LEN_OFFSET 12
#define FW_CHUNK_SRC_START_OFFSET 16
#define FW_CHUNK_VERSION_OFFSET 20
#define FW_CHUNK_ATTR_OFFSET 24
#define FW_CHUNK_PAYLOAD_OFFSET 32
/* Controller requires minimum 300us between commands */
#define WDT_COMMAND_DELAY_MS 2
#define WDT_FLASH_WRITE_DELAY_MS 4
#define WDT_FLASH_ERASE_DELAY_MS 200
#define WDT_FW_RESET_TIME 2500
struct wdt87xx_sys_param {
u16 fw_id;
u16 plat_id;
u16 xmls_id1;
u16 xmls_id2;
u16 phy_ch_x;
u16 phy_ch_y;
u16 phy_w;
u16 phy_h;
u16 scaling_factor;
u32 max_x;
u32 max_y;
u16 vendor_id;
u16 product_id;
};
struct wdt87xx_data {
struct i2c_client *client;
struct input_dev *input;
/* Mutex for fw update to prevent concurrent access */
struct mutex fw_mutex;
struct wdt87xx_sys_param param;
u8 phys[32];
};
static int wdt87xx_i2c_xfer(struct i2c_client *client,
void *txdata, size_t txlen,
void *rxdata, size_t rxlen)
{
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = 0,
.len = txlen,
.buf = txdata,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = rxlen,
.buf = rxdata,
},
};
int error;
int ret;
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs)) {
error = ret < 0 ? ret : -EIO;
dev_err(&client->dev, "%s: i2c transfer failed: %d\n",
__func__, error);
return error;
}
return 0;
}
static int wdt87xx_get_desc(struct i2c_client *client, u8 desc_idx,
u8 *buf, size_t len)
{
u8 tx_buf[] = { 0x22, 0x00, 0x10, 0x0E, 0x23, 0x00 };
int error;
tx_buf[2] |= desc_idx & 0xF;
error = wdt87xx_i2c_xfer(