2611 lines
78 KiB
C
2611 lines
78 KiB
C
/* drivers/input/touchscreen/it7258_ts_i2c.c
|
|
*
|
|
* Copyright (C) 2014 ITE Tech. Inc.
|
|
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/input.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/regulator/consumer.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/fb.h>
|
|
#include <linux/debugfs.h>
|
|
#include <linux/input/mt.h>
|
|
#include <linux/string.h>
|
|
#include <asm/uaccess.h>
|
|
#include <linux/fs.h>
|
|
|
|
#define MAX_BUFFER_SIZE 144
|
|
#define DEVICE_NAME "it7259"
|
|
#define SCREEN_X_RESOLUTION 320
|
|
#define SCREEN_Y_RESOLUTION 320
|
|
#define DEBUGFS_DIR_NAME "ts_debug"
|
|
#define FW_NAME "it7259_fw.bin"
|
|
#define CFG_NAME "it7259_cfg.bin"
|
|
#define IT7259_CFG_PATH "/persist/it7259.cfg"
|
|
#define IT7259_FW_PATH "/persist/it7259.fw"
|
|
#define VER_BUFFER_SIZE 4
|
|
#define IT_FW_CHECK(x, y) \
|
|
(((x)[0] < (y)->data[8]) || ((x)[1] < (y)->data[9]) || \
|
|
((x)[2] < (y)->data[10]) || ((x)[3] < (y)->data[11]))
|
|
#define IT_CFG_CHECK(x, y) \
|
|
(((x)[0] < (y)->data[(y)->size - 8]) || \
|
|
((x)[1] < (y)->data[(y)->size - 7]) || \
|
|
((x)[2] < (y)->data[(y)->size - 6]) || \
|
|
((x)[3] < (y)->data[(y)->size - 5]))
|
|
#define it7259_COORDS_ARR_SIZE 4
|
|
|
|
/* all commands writes go to this idx */
|
|
#define BUF_COMMAND 0x20
|
|
#define BUF_SYS_COMMAND 0x40
|
|
/*
|
|
* "device ready?" and "wake up please" and "read touch data" reads
|
|
* go to this idx
|
|
*/
|
|
#define BUF_QUERY 0x80
|
|
/* most command response reads go to this idx */
|
|
#define BUF_RESPONSE 0xA0
|
|
#define BUF_SYS_RESPONSE 0xC0
|
|
/* reads of "point" go through here and produce 14 bytes of data */
|
|
#define BUF_POINT_INFO 0xE0
|
|
|
|
/*
|
|
* commands and their subcommands. when no subcommands exist, a zero
|
|
* is send as the second byte
|
|
*/
|
|
#define CMD_IDENT_CHIP 0x00
|
|
/* VERSION_LENGTH bytes of data in response */
|
|
#define CMD_READ_VERSIONS 0x01
|
|
#define SUB_CMD_READ_FIRMWARE_VERSION 0x00
|
|
#define SUB_CMD_READ_CONFIG_VERSION 0x06
|
|
#define VERSION_LENGTH 10
|
|
/* subcommand is zero, next byte is power mode */
|
|
#define CMD_PWR_CTL 0x04
|
|
/* active mode */
|
|
#define PWR_CTL_ACTIVE_MODE 0x00
|
|
/* idle mode */
|
|
#define PWR_CTL_LOW_POWER_MODE 0x01
|
|
/* sleep mode */
|
|
#define PWR_CTL_SLEEP_MODE 0x02
|
|
#define WAIT_CHANGE_MODE 20
|
|
/* command is not documented in the datasheet v1.0.0.7 */
|
|
#define CMD_UNKNOWN_7 0x07
|
|
#define CMD_FIRMWARE_REINIT_C 0x0C
|
|
/* needs to be followed by 4 bytes of zeroes */
|
|
#define CMD_CALIBRATE 0x13
|
|
#define CMD_FIRMWARE_UPGRADE 0x60
|
|
#define SUB_CMD_ENTER_FW_UPGRADE_MODE 0x00
|
|
#define SUB_CMD_EXIT_FW_UPGRADE_MODE 0x80
|
|
/* address for FW read/write */
|
|
#define CMD_SET_START_OFFSET 0x61
|
|
/* subcommand is number of bytes to write */
|
|
#define CMD_FW_WRITE 0x62
|
|
/* subcommand is number of bytes to read */
|
|
#define CMD_FW_READ 0x63
|
|
#define CMD_FIRMWARE_REINIT_6F 0x6F
|
|
|
|
#define FW_WRITE_CHUNK_SIZE 128
|
|
#define FW_WRITE_RETRY_COUNT 4
|
|
#define CHIP_FLASH_SIZE 0x8000
|
|
#define DEVICE_READY_COUNT_MAX 500
|
|
#define DEVICE_READY_COUNT_20 20
|
|
#define IT_I2C_WAIT_10MS 10
|
|
#define IT_I2C_READ_RET 2
|
|
#define IT_I2C_WRITE_RET 1
|
|
|
|
/* result of reading with BUF_QUERY bits */
|
|
#define CMD_STATUS_BITS 0x07
|
|
#define CMD_STATUS_DONE 0x00
|
|
#define CMD_STATUS_BUSY 0x01
|
|
#define CMD_STATUS_ERROR 0x02
|
|
#define CMD_STATUS_NO_CONN 0x07
|
|
#define PT_INFO_BITS 0xF8
|
|
#define PT_INFO_YES 0x80
|
|
|
|
#define PD_FLAGS_DATA_TYPE_BITS 0xF0
|
|
/* other types (like chip-detected gestures) exist but we do not care */
|
|
#define PD_FLAGS_DATA_TYPE_TOUCH 0x00
|
|
#define PD_FLAGS_IDLE_TO_ACTIVE 0x10
|
|
/* a bit for each finger data that is valid (from lsb to msb) */
|
|
#define PD_FLAGS_HAVE_FINGERS 0x07
|
|
#define PD_PALM_FLAG_BIT 0x01
|
|
#define FD_PRESSURE_BITS 0x0F
|
|
#define FD_PRESSURE_NONE 0x00
|
|
#define FD_PRESSURE_LIGHT 0x02
|
|
|
|
#define IT_VTG_MIN_UV 1800000
|
|
#define IT_VTG_MAX_UV 1800000
|
|
#define IT_ACTIVE_LOAD_UA 15000
|
|
#define IT_I2C_VTG_MIN_UV 2600000
|
|
#define IT_I2C_VTG_MAX_UV 3300000
|
|
#define IT_I2C_ACTIVE_LOAD_UA 10000
|
|
#define DELAY_VTG_REG_EN 170
|
|
|
|
#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
|
|
#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend"
|
|
#define PINCTRL_STATE_RELEASE "pmx_ts_release"
|
|
|
|
int download;
|
|
#define COMMAND_SUCCESS 0x0000
|
|
#define COMMAND_ERROR 0x0200
|
|
#define ERROR_QUERY_TIME_OUT 0x0800
|
|
|
|
|
|
struct finger_data {
|
|
u8 xLo;
|
|
u8 hi;
|
|
u8 yLo;
|
|
u8 pressure;
|
|
} __packed;
|
|
|
|
struct point_data {
|
|
u8 flags;
|
|
u8 gesture_id;
|
|
struct finger_data fd[3];
|
|
} __packed;
|
|
|
|
struct it7259_ts_platform_data {
|
|
unsigned int reset_gpio;
|
|
unsigned int reset_gpio_flags;
|
|
unsigned int panel_minx;
|
|
unsigned int panel_miny;
|
|
unsigned int panel_maxx;
|
|
unsigned int panel_maxy;
|
|
unsigned int disp_minx;
|
|
unsigned int disp_miny;
|
|
unsigned int disp_maxx;
|
|
unsigned int disp_maxy;
|
|
unsigned int num_of_fingers;
|
|
unsigned int reset_delay;
|
|
unsigned int avdd_lpm_cur;
|
|
unsigned int irq_gpio;
|
|
unsigned int irq_gpio_flags;
|
|
const char *fw_name;
|
|
const char *cfg_name;
|
|
unsigned short palm_detect_keycode;
|
|
bool low_reset;
|
|
bool wakeup;
|
|
bool palm_detect_en;
|
|
};
|
|
|
|
struct it7259_ts_data {
|
|
struct i2c_client *client;
|
|
struct input_dev *input_dev;
|
|
const struct it7259_ts_platform_data *pdata;
|
|
struct regulator *vdd;
|
|
struct regulator *avdd;
|
|
bool in_low_power_mode;
|
|
bool suspended;
|
|
bool fw_upgrade_result;
|
|
bool cfg_upgrade_result;
|
|
bool fw_cfg_uploading;
|
|
struct work_struct work_pm_relax;
|
|
bool calibration_success;
|
|
bool had_finger_down;
|
|
char fw_name[MAX_BUFFER_SIZE];
|
|
char cfg_name[MAX_BUFFER_SIZE];
|
|
struct mutex fw_cfg_mutex;
|
|
u8 fw_ver[VER_BUFFER_SIZE];
|
|
u8 cfg_ver[VER_BUFFER_SIZE];
|
|
#ifdef CONFIG_FB
|
|
struct notifier_block fb_notif;
|
|
#endif
|
|
struct dentry *dir;
|
|
struct pinctrl *ts_pinctrl;
|
|
struct pinctrl_state *pinctrl_state_active;
|
|
struct pinctrl_state *pinctrl_state_suspend;
|
|
struct pinctrl_state *pinctrl_state_release;
|
|
};
|
|
|
|
/* Function declarations */
|
|
static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data);
|
|
static int it7259_ts_resume(struct device *dev);
|
|
static int it7259_ts_suspend(struct device *dev);
|
|
static int it7259_debug_suspend_set(void *_data, u64 val)
|
|
{
|
|
struct it7259_ts_data *ts_data = _data;
|
|
|
|
if (val)
|
|
it7259_ts_suspend(&ts_data->client->dev);
|
|
else
|
|
it7259_ts_resume(&ts_data->client->dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int it7259_debug_suspend_get(void *_data, u64 *val)
|
|
{
|
|
struct it7259_ts_data *ts_data = _data;
|
|
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
*val = ts_data->suspended;
|
|
mutex_lock(&ts_data->input_dev->mutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, it7259_debug_suspend_get,
|
|
it7259_debug_suspend_set, "%lld\n");
|
|
|
|
/* internal use func - does not make sure chip is ready before read */
|
|
static int it7259_i2c_read_no_ready_check(struct it7259_ts_data *ts_data,
|
|
uint8_t buf_index, uint8_t *buffer, uint16_t buf_len)
|
|
{
|
|
int ret;
|
|
struct i2c_msg msgs[2] = {
|
|
{
|
|
.addr = ts_data->client->addr,
|
|
.flags = I2C_M_NOSTART,
|
|
.len = 1,
|
|
.buf = &buf_index
|
|
},
|
|
{
|
|
.addr = ts_data->client->addr,
|
|
.flags = I2C_M_RD,
|
|
.len = buf_len,
|
|
.buf = buffer
|
|
}
|
|
};
|
|
|
|
memset(buffer, 0xFF, buf_len);
|
|
|
|
ret = i2c_transfer(ts_data->client->adapter, msgs, 2);
|
|
if (ret < 0)
|
|
dev_err(&ts_data->client->dev, "i2c read failed %d\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int it7259_i2c_write_no_ready_check(struct it7259_ts_data *ts_data,
|
|
uint8_t buf_index, const uint8_t *buffer, uint16_t buf_len)
|
|
{
|
|
uint8_t txbuf[257];
|
|
int ret;
|
|
struct i2c_msg msg = {
|
|
.addr = ts_data->client->addr,
|
|
.flags = 0,
|
|
.len = buf_len + 1,
|
|
.buf = txbuf
|
|
};
|
|
|
|
/* just to be careful */
|
|
if (buf_len > sizeof(txbuf) - 1) {
|
|
dev_err(&ts_data->client->dev, "buf length is out of limit\n");
|
|
return false;
|
|
}
|
|
|
|
txbuf[0] = buf_index;
|
|
memcpy(txbuf + 1, buffer, buf_len);
|
|
|
|
ret = i2c_transfer(ts_data->client->adapter, &msg, 1);
|
|
if (ret < 0)
|
|
dev_err(&ts_data->client->dev, "i2c write failed %d\n", ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* Device is apparently always ready for I2C communication but not for
|
|
* actual register reads/writes. This function checks if it is ready
|
|
* for that too. The results of this call often were ignored.
|
|
* If forever is set to TRUE, then check the device's status until it
|
|
* becomes ready with 500 retries at max. Otherwise retry 25 times only.
|
|
* If slowly is set to TRUE, then add sleep of 50 ms in each retry,
|
|
* otherwise don't sleep.
|
|
*/
|
|
static int it7259_wait_device_ready(struct it7259_ts_data *ts_data,
|
|
bool forever, bool slowly)
|
|
{
|
|
uint8_t query;
|
|
uint32_t count = DEVICE_READY_COUNT_20;
|
|
int ret;
|
|
|
|
if (ts_data->fw_cfg_uploading || forever)
|
|
count = DEVICE_READY_COUNT_MAX;
|
|
|
|
do {
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_QUERY, &query,
|
|
sizeof(query));
|
|
if (ret < 0 && ((query & CMD_STATUS_BITS)
|
|
== CMD_STATUS_NO_CONN))
|
|
continue;
|
|
|
|
if ((query & CMD_STATUS_BITS) == CMD_STATUS_DONE)
|
|
break;
|
|
|
|
query = CMD_STATUS_BUSY;
|
|
if (slowly)
|
|
msleep(IT_I2C_WAIT_10MS);
|
|
} while (--count);
|
|
|
|
return ((!(query & CMD_STATUS_BITS)) ? 0 : -ENODEV);
|
|
}
|
|
|
|
static int it7259_i2c_write(struct it7259_ts_data *ts_data, uint8_t buf_index, const uint8_t *buffer, uint16_t buf_len)
|
|
{
|
|
int ret;
|
|
|
|
ret = it7259_wait_device_ready(ts_data, false, false);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return it7259_i2c_write_no_ready_check(ts_data, buf_index, buffer, buf_len);
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PM
|
|
static int it7259_ts_chip_low_power_mode(struct it7259_ts_data *ts_data,
|
|
const u8 sleep_type)
|
|
{
|
|
const u8 cmd_sleep[] = {CMD_PWR_CTL, 0x00, sleep_type};
|
|
u8 dummy;
|
|
int ret;
|
|
|
|
if (sleep_type) {
|
|
ret = it7259_i2c_write_no_ready_check(ts_data, BUF_COMMAND, cmd_sleep, sizeof(cmd_sleep));
|
|
if (ret != IT_I2C_WRITE_RET)
|
|
dev_err(&ts_data->client->dev, "Can't go to sleep or low power mode(%d) %d\n", sleep_type, ret);
|
|
else
|
|
ret = 0;
|
|
} else {
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_QUERY, &dummy, sizeof(dummy));
|
|
if (ret != IT_I2C_READ_RET)
|
|
dev_err(&ts_data->client->dev, "Can't go to active mode %d\n", ret);
|
|
else
|
|
ret = 0;
|
|
}
|
|
|
|
msleep(WAIT_CHANGE_MODE);
|
|
return ret;
|
|
}
|
|
#endif
|
|
static int i2cInternalWriteToIT7259(struct it7259_ts_data *ts_data, int wAddress, unsigned char const dataBuffer[], unsigned short dataLength)
|
|
{
|
|
unsigned char buffer4Write[1024] = {0};
|
|
struct i2c_msg msgs[1] = { { .addr = ts_data->client->addr, .flags = 0, .len = dataLength + 3, .buf = buffer4Write } };
|
|
//printk("====in internal write function===\n");
|
|
|
|
buffer4Write[0] = 0x70;
|
|
buffer4Write[1] = (unsigned char)(wAddress & 0xFF);
|
|
|
|
memcpy(&(buffer4Write[2]), dataBuffer, dataLength);
|
|
return i2c_transfer(ts_data->client->adapter, msgs, 1);
|
|
}
|
|
|
|
static int i2cDirectReadFromIT7259(struct it7259_ts_data *ts_data, int wAddress, unsigned char readDataBuffer[], unsigned short readDataLength)
|
|
{
|
|
int ret;
|
|
unsigned char buffer4Write[1024] = {0};
|
|
struct i2c_msg msgs[2] = { { .addr = ts_data->client->addr, .flags = 0,
|
|
.len = 4, .buf = buffer4Write }, { .addr = ts_data->client->addr, .flags =
|
|
I2C_M_RD, .len = readDataLength, .buf = readDataBuffer } };
|
|
//printk("====in Direct read function===\n");
|
|
|
|
buffer4Write[0] = 0x90;
|
|
buffer4Write[1] = 0x00;
|
|
buffer4Write[2] = (unsigned char)((wAddress & 0xFF00) >> 8);
|
|
buffer4Write[3] = (unsigned char)(wAddress & 0xFF);
|
|
|
|
memset(readDataBuffer, 0xFF, readDataLength);
|
|
ret = i2c_transfer(ts_data->client->adapter, msgs, 2);
|
|
return ret;
|
|
}
|
|
|
|
static int i2cDirectWriteToIT7259(struct it7259_ts_data *ts_data, int wAddress, unsigned char const dataBuffer[], unsigned short dataLength)
|
|
{
|
|
unsigned char buffer4Write[1024] = {0};
|
|
int nRetryCount = 0;
|
|
int nRet = 0;
|
|
struct i2c_msg msgs[1] = { { .addr = ts_data->client->addr, .flags = 0, .len = dataLength + 4, .buf = buffer4Write } };
|
|
//printk("====in Direct write function===\n");
|
|
|
|
buffer4Write[0] = 0x10;
|
|
buffer4Write[1] = 0x00;
|
|
buffer4Write[2] = (unsigned char)((wAddress & 0xFF00) >> 8);
|
|
buffer4Write[3] = (unsigned char)(wAddress & 0xFF);
|
|
memcpy(&(buffer4Write[4]), dataBuffer, dataLength);
|
|
|
|
do {
|
|
nRet = i2c_transfer(ts_data->client->adapter, msgs, 1);
|
|
} while ((nRet <= 0) && (nRetryCount++ < 10));
|
|
|
|
return nRet;
|
|
}
|
|
|
|
|
|
static bool gfnIT7259_SPIFCRReady(struct it7259_ts_data *ts_data)
|
|
{
|
|
int nReadCount = 0;
|
|
unsigned char ucBuffer[2] = {0};
|
|
|
|
do {
|
|
i2cDirectReadFromIT7259(ts_data, 0xF400, ucBuffer, 2);//gfnIT7259_DirectReadMemoryRegister
|
|
} while (((ucBuffer[1] & 0x01) != 0x00) && ++nReadCount < 20); //nReadCount 3000
|
|
|
|
if (nReadCount >= 20) //nReadCount 3000
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
static int gfnIT7259_DirectReadFlash(struct it7259_ts_data *ts_data, int wFlashAddress, unsigned int readLength, unsigned char *pData)
|
|
{
|
|
int nSector = 0;
|
|
unsigned char pucCommandBuffer[1024] = {0};
|
|
int wTmp;
|
|
int wAddress;
|
|
unsigned int /*AddrOffset, */LenOffset;
|
|
unsigned char bufTemp[4] = {0};
|
|
int wOffset;
|
|
int i;
|
|
|
|
nSector = wFlashAddress/0x0400;
|
|
pucCommandBuffer[0] = nSector;
|
|
|
|
//Select Sector
|
|
wAddress = 0xF404;
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, 1);
|
|
if (wTmp <= 0) {
|
|
return COMMAND_ERROR;
|
|
}
|
|
|
|
//Wait SPIFCR
|
|
if (!gfnIT7259_SPIFCRReady(ts_data)) {
|
|
return ERROR_QUERY_TIME_OUT;
|
|
}
|
|
|
|
//Read flash
|
|
wOffset = wFlashAddress - (nSector*0x0400);
|
|
wAddress = 0x3000 + wOffset;
|
|
//printk("======= gfnIT7259_DirectReadFlash 8 byte limit =======\n");
|
|
for (LenOffset = 0; LenOffset < readLength; LenOffset += 4) {
|
|
wTmp = i2cDirectReadFromIT7259(ts_data, wAddress, bufTemp, 4);
|
|
if (wTmp <= 0) {
|
|
return COMMAND_ERROR;
|
|
}
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
pucCommandBuffer[LenOffset + i] = bufTemp[i] ;
|
|
}
|
|
wAddress = wAddress + 4;
|
|
}
|
|
|
|
//Wait SPIFCR
|
|
if (!gfnIT7259_SPIFCRReady(ts_data)) {
|
|
return ERROR_QUERY_TIME_OUT;
|
|
}
|
|
memcpy((unsigned char *)pData, pucCommandBuffer, readLength * sizeof(unsigned char));
|
|
return COMMAND_SUCCESS;
|
|
}
|
|
|
|
static int i2cInternalReadFromIT7259(struct it7259_ts_data *ts_data,
|
|
int wAddress, unsigned char readDataBuffer[], unsigned short readDataLength)
|
|
{
|
|
int ret;
|
|
unsigned char buffer4Write[1024] = {0};
|
|
struct i2c_msg msgs[2] = { { .addr = ts_data->client->addr, .flags = 0,
|
|
.len = 2, .buf = buffer4Write }, { .addr = ts_data->client->addr, .flags =
|
|
I2C_M_RD, .len = readDataLength, .buf = readDataBuffer } };
|
|
//printk("====in internal read function===\n");
|
|
|
|
buffer4Write[0] = 0x70;
|
|
buffer4Write[1] = (unsigned char)(wAddress & 0xFF);
|
|
|
|
memset(readDataBuffer, 0xFF, readDataLength);
|
|
ret = i2c_transfer(ts_data->client->adapter, msgs, 2);
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gfnIT7259_DirectEraseFlash(struct it7259_ts_data *ts_data, unsigned char ucEraseType, int wFlashAddress)
|
|
{
|
|
int nSector = 0;
|
|
unsigned char pucCommandBuffer[1024];
|
|
int wTmp;
|
|
int wAddress;
|
|
nSector = wFlashAddress/0x0400;
|
|
pucCommandBuffer[0] = nSector;
|
|
|
|
//Select Sector
|
|
wAddress = 0xF404;
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, 1);
|
|
if (wTmp <= 0) {
|
|
return COMMAND_ERROR;
|
|
}
|
|
|
|
//Wait SPIFCR
|
|
if (!gfnIT7259_SPIFCRReady(ts_data)) {
|
|
return ERROR_QUERY_TIME_OUT;
|
|
}
|
|
|
|
//Read flash
|
|
wAddress = 0xF402;
|
|
pucCommandBuffer[0] = ucEraseType;
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, 1);
|
|
|
|
//Wait SPIFCR
|
|
if (!gfnIT7259_SPIFCRReady(ts_data)) {
|
|
return ERROR_QUERY_TIME_OUT;
|
|
}
|
|
|
|
return COMMAND_SUCCESS;
|
|
}
|
|
|
|
|
|
static int gfnIT7259_DMAModeWriteFlash(struct it7259_ts_data *ts_data, int wFlashAddress, int wSRAMAddress,
|
|
unsigned int dataLength, unsigned char *pData, bool bPollingWait)
|
|
{
|
|
int nSector = 0;
|
|
int wAddress;
|
|
int wTmp;
|
|
int i;
|
|
unsigned char pucCommandBuffer[1024];
|
|
unsigned char pucReadData[2];
|
|
unsigned int LenOffset;
|
|
unsigned char bufTemp[4];
|
|
unsigned int wStartAddress;
|
|
|
|
//write to address 0x0000 (SRAM only 6K)
|
|
memset(bufTemp, 0xFF, 4); //for 8 byte limit
|
|
wAddress = wSRAMAddress;
|
|
printk("###write to address 0x0000 (wSRAMAddress = %04x, dataLength = %02x)\n",
|
|
wSRAMAddress, dataLength);
|
|
for (LenOffset = 0; LenOffset < dataLength; LenOffset += 4) {
|
|
for (i = 0; i < 4; i++) {
|
|
bufTemp[i] = pData[LenOffset + i];
|
|
}
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, bufTemp, 4);
|
|
if (wTmp <= 0) {
|
|
//printk("###write to address 0x0000 fail!\n");
|
|
return COMMAND_ERROR;
|
|
}
|
|
wAddress = wAddress + 4;
|
|
//printk(" ======== wAddress = %04x , LenOffset = %02x ========\n",wAddress,LenOffset);
|
|
}
|
|
|
|
//Select Sector
|
|
memset(pucCommandBuffer, 0xFF, 1024);
|
|
nSector = wFlashAddress/0x0400;
|
|
pucCommandBuffer[0] = (unsigned char)(nSector & 0xFF);
|
|
|
|
wAddress = 0xF404;
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, 1);//DirectWriteMemoryRegister
|
|
if (wTmp <= 0) {
|
|
printk("###Select Sector fail!");
|
|
return COMMAND_ERROR;
|
|
}
|
|
//Wait SPIFCR
|
|
//printk("###Wait SPIFCR\n");
|
|
if (!gfnIT7259_SPIFCRReady(ts_data)) {
|
|
return ERROR_QUERY_TIME_OUT;
|
|
}
|
|
|
|
//Write Flash strat address
|
|
//printk("###Write Flash strat address\n");
|
|
memset(pucCommandBuffer, 0xFF, 1024);
|
|
wAddress = 0xF41A;
|
|
wStartAddress = wFlashAddress - (nSector*0x0400);
|
|
pucCommandBuffer[0] = wStartAddress & 0x00FF;
|
|
pucCommandBuffer[1] = (wStartAddress & 0xFF00) >> 8 ;
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, 2);//DirectWriteMemoryRegister
|
|
if (wTmp <= 0) {
|
|
printk("###Write Flash strat address fail!\n");
|
|
return COMMAND_ERROR;
|
|
}
|
|
|
|
//Write SARM strat address
|
|
wAddress = 0xF41C;
|
|
memset(pucCommandBuffer, 0xFF, 1024);
|
|
pucCommandBuffer[0] = wSRAMAddress & 0xFF;
|
|
pucCommandBuffer[1] = (wSRAMAddress & 0xFF00) >> 8;
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, 2);//DirectWriteMemoryRegister
|
|
if (wTmp <= 0) {
|
|
printk("###Write SARM strat address fail!\n");
|
|
return COMMAND_ERROR;
|
|
}
|
|
|
|
//write DMA transfer length
|
|
wAddress = 0xF41E;
|
|
pucCommandBuffer[0] = dataLength & 0xFF;
|
|
pucCommandBuffer[1] = (dataLength & 0xFF00) >> 8 ;
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, 2);//DirectWriteMemoryRegister
|
|
if (wTmp <= 0) {
|
|
printk("###write DMA transfer length fail!\n");
|
|
return COMMAND_ERROR;
|
|
}
|
|
|
|
//Write DMA_DIR and DMAEN
|
|
wAddress = 0xF418;
|
|
pucCommandBuffer[0] = 0x0B; //auto erase
|
|
pucCommandBuffer[1] = 0x00;
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, 2);//DirectWriteMemoryRegister
|
|
if (wTmp <= 0) {
|
|
printk("###Write DMA_DIR and DMAEN fail!\n");
|
|
return COMMAND_ERROR;
|
|
}
|
|
if (bPollingWait) {
|
|
//polling bit 0, until value of bit 0 = 0
|
|
wAddress = 0xF418;
|
|
do {
|
|
wTmp = i2cDirectReadFromIT7259(ts_data, wAddress, pucReadData, 2);//gfnIT7259_DirectReadMemoryRegister
|
|
if (wTmp <= 0) {
|
|
break;
|
|
return COMMAND_ERROR;
|
|
}
|
|
} while ((pucReadData[0] & 0x01) != 0x00);
|
|
//Wait SPIFCR
|
|
if (!gfnIT7259_SPIFCRReady(ts_data)) {
|
|
return ERROR_QUERY_TIME_OUT;
|
|
}
|
|
}
|
|
return COMMAND_SUCCESS;
|
|
}
|
|
|
|
static unsigned int gfnIT7259_GetFWSize(struct it7259_ts_data *ts_data)
|
|
{
|
|
int wAddress;
|
|
unsigned char arucBuffer[1024];
|
|
unsigned int unRet = 0;
|
|
|
|
printk("###Entry gfnIT7259_GetFWSize()\n");
|
|
wAddress = 0;
|
|
gfnIT7259_DirectReadFlash(ts_data, wAddress, 0x0400, arucBuffer);
|
|
|
|
unRet = arucBuffer[0x80+12] + (arucBuffer[0x80+13] << 8);
|
|
|
|
return unRet;
|
|
}
|
|
|
|
|
|
static bool gfnIT7259_SwitchCPUClock(struct it7259_ts_data *ts_data, unsigned char ucMode)
|
|
{
|
|
unsigned char ucCommandBuffer[1];
|
|
unsigned char ucRetCommandBuffer[1];
|
|
int nErrCount = 0;
|
|
int dwAddress = 0x0023;
|
|
|
|
ucCommandBuffer[0] = ucMode;
|
|
|
|
do {
|
|
i2cInternalWriteToIT7259(ts_data, dwAddress, ucCommandBuffer, 1);
|
|
|
|
i2cInternalReadFromIT7259(ts_data, dwAddress, ucRetCommandBuffer, 1);
|
|
|
|
nErrCount++;
|
|
} while (((ucRetCommandBuffer[0] & 0x0F) != ucMode) && nErrCount <= 1000);
|
|
|
|
if (nErrCount > 1000) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
static int gfnIT7259_DirectWriteFlash(struct it7259_ts_data *ts_data, int wFlashAddress, unsigned int wWriteLength, unsigned char *pData)
|
|
{
|
|
//printk("###Entry gfnIT7259_DirectWriteFlash()\n");
|
|
//struct IT7259_ts_data *ts = gl_ts;
|
|
//struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
int nSector = 0;
|
|
unsigned char pucCommandBuffer[1024];
|
|
int wTmp;
|
|
int wAddress;
|
|
int wOffset;
|
|
nSector = wFlashAddress/0x0400;
|
|
pucCommandBuffer[0] = nSector;
|
|
|
|
//Select Sector
|
|
wAddress = 0xF404;
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, 1);
|
|
if (wTmp <= 0) {
|
|
return COMMAND_ERROR;
|
|
}
|
|
|
|
//Wait SPIFCR
|
|
if (!gfnIT7259_SPIFCRReady(ts_data)) {
|
|
return ERROR_QUERY_TIME_OUT;
|
|
}
|
|
|
|
//write flash
|
|
wOffset = wFlashAddress - (nSector*0x0400);
|
|
wAddress = 0x3000 + wOffset;
|
|
memcpy(pucCommandBuffer, (unsigned char *)pData, wWriteLength * sizeof(unsigned char));
|
|
//wTmp = gfnIT7259_DirectWriteMemoryRegister(0x01,wAddress,0x0000,wWriteLength, pucCommandBuffer);
|
|
wTmp = i2cDirectWriteToIT7259(ts_data, wAddress, pucCommandBuffer, wWriteLength);
|
|
|
|
if (wTmp <= 0) {
|
|
return COMMAND_ERROR;
|
|
}
|
|
|
|
//Wait SPIFCR
|
|
if (!gfnIT7259_SPIFCRReady(ts_data)) {
|
|
return ERROR_QUERY_TIME_OUT;
|
|
}
|
|
|
|
return COMMAND_SUCCESS;
|
|
}
|
|
|
|
|
|
static bool gfnIT7259_FirmwareDownload(struct it7259_ts_data *ts_data, unsigned int unFirmwareLength, unsigned char arucFW[], unsigned int unConfigLength, unsigned char arucConfig[])
|
|
{
|
|
int dwAddress = 0;
|
|
unsigned char RetDATABuffer[10] = {0};
|
|
unsigned char DATABuffer[10] = {0};
|
|
int nSector = 0;
|
|
unsigned int nFillSize = 0;
|
|
int wTmp = 0;
|
|
unsigned int unTmp = 0;
|
|
unsigned int nConfigSize = 0;
|
|
unsigned long dwFlashSize = 0x10000;
|
|
unsigned int nEndFwSector = 0;
|
|
unsigned int nStartCFGSector = 0;
|
|
unsigned char putFWBuffer[1024];
|
|
int wAddress = 0;
|
|
int wRemainderFWAddress = 0;
|
|
int wConfigAddress = 0;
|
|
unsigned int nRemainderFwSize = 0;
|
|
unsigned int i = 0;
|
|
int nConfigCount = 0;
|
|
int nSize = 0;
|
|
int Tmp = 0;
|
|
|
|
if ((unFirmwareLength == 0) && (unConfigLength == 0)) {
|
|
printk("XXX %s, %d\n", __FUNCTION__, __LINE__);
|
|
return false;
|
|
}
|
|
|
|
|
|
//trun off CPU data clock
|
|
if (!gfnIT7259_SwitchCPUClock(ts_data, 0x01)) {
|
|
printk("###002 gfnIT7259_SwitchCPUClock(0x01) fail!\n");
|
|
return false;
|
|
}
|
|
|
|
|
|
//Wait SPIFCR
|
|
//printk("###003 Wait SPIFCR\n");
|
|
dwAddress = 0xF400;
|
|
do {
|
|
i2cDirectReadFromIT7259(ts_data, dwAddress, RetDATABuffer, 2);
|
|
} while ((RetDATABuffer[1] & 0x01) != 0x00);
|
|
//printk("###003 End SPIFCR\n");
|
|
//Erase signature
|
|
//printk("###004 Erase signature\n");
|
|
dwAddress = 0xF404;
|
|
DATABuffer[0] = 0x3F;
|
|
i2cDirectWriteToIT7259(ts_data, dwAddress, DATABuffer, 1);
|
|
|
|
dwAddress = 0xF402;
|
|
DATABuffer[0] = 0xD7;
|
|
i2cDirectWriteToIT7259(ts_data, dwAddress, DATABuffer, 1);
|
|
|
|
//Wait SPIFCR
|
|
//printk("###005 Wait SPIFCR\n");
|
|
dwAddress = 0xF400;
|
|
do {
|
|
i2cDirectReadFromIT7259(ts_data, dwAddress, RetDATABuffer, 2);
|
|
} while ((RetDATABuffer[1] & 0x01) != 0x00);
|
|
//printk("###005 End SPIFCR\n");
|
|
if ((download == 2) || (download == 3)) {
|
|
//Download FW
|
|
printk("###006 Download FW\n");
|
|
for (i = 0; i < unFirmwareLength; i += 0x0400) {
|
|
if ((unFirmwareLength - i) >= 0x0400)//0x0400
|
|
nFillSize = 0x0400;//0x0400
|
|
else
|
|
nFillSize = unFirmwareLength - i;
|
|
|
|
Tmp = gfnIT7259_DMAModeWriteFlash(ts_data, i, 0x0000, nFillSize, arucFW+i, true);
|
|
|
|
mdelay(100);//for test
|
|
if (wTmp != COMMAND_SUCCESS) {
|
|
//Write Firmware Flash error
|
|
printk("###DMA ModeWrite Firmware Flash error(FlashAddress:%04x)\n", i);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//3. Fw CRC Check
|
|
//check FW CRC
|
|
//printk("###007 check FW CRC\n");
|
|
//write start address
|
|
dwAddress = 0xF40A;
|
|
DATABuffer[0] = 0x00;
|
|
DATABuffer[1] = 0x00;
|
|
i2cDirectWriteToIT7259(ts_data, dwAddress, DATABuffer, 2);
|
|
|
|
//write end address
|
|
dwAddress = 0xF40C;
|
|
DATABuffer[0] = (unFirmwareLength-3) & 0x00ff;
|
|
DATABuffer[1] = ((unFirmwareLength-3) & 0xff00) >> 8;
|
|
i2cDirectWriteToIT7259(ts_data, dwAddress, DATABuffer, 2);
|
|
|
|
//write CRCCR
|
|
dwAddress = 0xF408;
|
|
DATABuffer[0] = 0x01 ;
|
|
i2cDirectWriteToIT7259(ts_data, dwAddress, DATABuffer, 1);
|
|
|
|
//wait CRCCR
|
|
dwAddress = 0xF408;
|
|
do {
|
|
i2cDirectReadFromIT7259(ts_data, dwAddress, RetDATABuffer, 2);
|
|
} while ((RetDATABuffer[0] & 0x01) != 0x00);
|
|
|
|
//read CRC
|
|
dwAddress = 0xF40E;
|
|
i2cDirectReadFromIT7259(ts_data, dwAddress, RetDATABuffer, 2);
|
|
|
|
//compare FW CRC
|
|
//printk("###008 compare FW CRC\n");
|
|
|
|
if (RetDATABuffer[0] != arucFW[unFirmwareLength - 2] || RetDATABuffer[1] != arucFW[unFirmwareLength - 1]) {
|
|
printk("###008 FW CRC check fail\n");
|
|
printk("RetDATABuffer[0]:%02x,RetDATABuffer[1]:%02x,FW[Length-2]:%02x,FW[Length-1]:%02x\n",
|
|
RetDATABuffer[0], RetDATABuffer[1], arucFW[unFirmwareLength - 2], arucFW[unFirmwareLength - 1]);
|
|
return false;//FW CRC check fail
|
|
}
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
if ((download == 1) || (download == 3)) {
|
|
//download config
|
|
printk("###009 start to download config\n");
|
|
unTmp = gfnIT7259_GetFWSize(ts_data);
|
|
nConfigSize = unConfigLength;
|
|
|
|
//3.7 get address for writing config (in flash)
|
|
//check whether fw and config are in the same sector or not
|
|
//set flash size
|
|
//dwFlashSize = 0x10000;
|
|
nEndFwSector = (unTmp - 1) / 1024;
|
|
nStartCFGSector = 62 - (unConfigLength - 1)/1024;
|
|
nRemainderFwSize = 0;
|
|
|
|
if (nEndFwSector == nStartCFGSector) {
|
|
nRemainderFwSize = unTmp - nEndFwSector*1024;
|
|
wAddress = nEndFwSector*0x0400;
|
|
//printk(" =========== nRemainderFwSize = %4x ===========\n",nRemainderFwSize);
|
|
gfnIT7259_DirectReadFlash(ts_data, wAddress, nRemainderFwSize, putFWBuffer);
|
|
}
|
|
|
|
//get config start address
|
|
wTmp = dwFlashSize - 1024 - unConfigLength;
|
|
//printk("###010 get config start address(%04x)\n",wTmp);
|
|
|
|
for (i = wTmp; i < (dwFlashSize - 1024); i += 0x0400) {
|
|
nSector = i/0x0400;
|
|
|
|
if ((nRemainderFwSize != 0) && (nSector == nStartCFGSector)) {
|
|
wRemainderFWAddress = nStartCFGSector*0x0400;
|
|
nFillSize = nRemainderFwSize;
|
|
gfnIT7259_DMAModeWriteFlash(ts_data, wRemainderFWAddress, 0x0000, nFillSize, putFWBuffer, true);
|
|
}
|
|
//write config
|
|
nSize = (unConfigLength - (62 - nSector)*1024);
|
|
|
|
if (nSize >= 1024) {
|
|
wConfigAddress = nSector * 0x0400;
|
|
nFillSize = 1024;
|
|
} else {
|
|
wConfigAddress = i;
|
|
nFillSize = nSize;
|
|
}
|
|
|
|
wTmp = gfnIT7259_DMAModeWriteFlash(ts_data, wConfigAddress, 0x0000, nFillSize, arucConfig + nConfigCount, true);
|
|
|
|
if (wTmp != COMMAND_SUCCESS)
|
|
return false;
|
|
|
|
nConfigCount += nFillSize;
|
|
}
|
|
|
|
//Config CRC Check
|
|
//printk("###011 Config CRC Check\n");
|
|
//write start address
|
|
dwAddress = 0xF40A;
|
|
DATABuffer[0] = (0x10000 - unConfigLength - 1024) & 0x00ff;
|
|
DATABuffer[1] = ((0x10000 - unConfigLength - 1024) & 0xff00) >> 8;
|
|
i2cDirectWriteToIT7259(ts_data, dwAddress, DATABuffer, 2);
|
|
|
|
//write end address
|
|
dwAddress = 0xF40C;
|
|
DATABuffer[0] = (0x10000 - 1024 - 3) & 0x00ff;
|
|
DATABuffer[1] = ((0x10000 - 1024 - 3) & 0xff00) >> 8;
|
|
i2cDirectWriteToIT7259(ts_data, dwAddress, DATABuffer, 2);
|
|
|
|
//write CRCCR
|
|
dwAddress = 0xF408;
|
|
DATABuffer[0] = 0x01 ;
|
|
i2cDirectWriteToIT7259(ts_data, dwAddress, DATABuffer, 1);
|
|
|
|
//wait CRCCR
|
|
dwAddress = 0xF408;
|
|
do {
|
|
i2cDirectReadFromIT7259(ts_data, dwAddress, RetDATABuffer, 2);
|
|
} while ((RetDATABuffer[0] & 0x01) != 0x00);
|
|
|
|
//read CRC
|
|
dwAddress = 0xF40E;
|
|
i2cDirectReadFromIT7259(ts_data, dwAddress, RetDATABuffer, 2);
|
|
|
|
//compare Config CRC
|
|
if ((RetDATABuffer[0] != arucConfig[unConfigLength - 2]) ||
|
|
(RetDATABuffer[1] != arucConfig[unConfigLength - 1])) {
|
|
printk("###011 config CRC Check Error\n");
|
|
printk("RetDATABuffer[0]:%02x,RetDATABuffer[1]:%02x,CFG[Length-2]:%02x,CFG[Length-1]:%02x\n",
|
|
RetDATABuffer[0], RetDATABuffer[1], arucConfig[unConfigLength - 2], arucConfig[unConfigLength - 1]);
|
|
return false;//config CRC Check Error
|
|
}
|
|
}
|
|
|
|
//write signature
|
|
DATABuffer[0] = 0x57;
|
|
DATABuffer[1] = 0x72;
|
|
|
|
gfnIT7259_DirectEraseFlash(ts_data, 0xD7, (dwFlashSize - 1024));
|
|
gfnIT7259_DirectWriteFlash(ts_data, (dwFlashSize - 1024), 2, DATABuffer);
|
|
|
|
DATABuffer[0] = 0x00;
|
|
DATABuffer[1] = 0x00;
|
|
i2cDirectReadFromIT7259(ts_data, dwAddress, DATABuffer, 2);
|
|
|
|
//trun on CPU data clock
|
|
//printk("###012 trun on CPU data clock\n");
|
|
if (!gfnIT7259_SwitchCPUClock(ts_data, 0x04)) {
|
|
printk("###012 trun on CPU data clock fail\n");
|
|
return false;
|
|
}
|
|
|
|
printk("###gfnIT7259_FirmwareDownload() end.\n");
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static int Upgrade_FW_CFG(struct it7259_ts_data *ts_data)
|
|
{
|
|
unsigned int fw_size = 0;
|
|
unsigned int config_size = 0;
|
|
|
|
struct file *fw_fd = NULL;
|
|
struct file *config_fd = NULL;
|
|
mm_segment_t fs;
|
|
|
|
unsigned char *fw_buf = kzalloc(0x10000, GFP_KERNEL);
|
|
unsigned char *config_buf = kzalloc(0x500, GFP_KERNEL);
|
|
|
|
printk(KERN_ERR"Execute Upgrade_FW_CFG()\n");
|
|
if (fw_buf == NULL || config_buf == NULL) {
|
|
printk("kzalloc failed\n");
|
|
}
|
|
|
|
fs = get_fs();
|
|
set_fs(get_ds());
|
|
//load fw file
|
|
fw_fd = filp_open(IT7259_FW_PATH, O_RDONLY, 0);
|
|
|
|
if (fw_fd < 0) {
|
|
printk("open %s failed \n", IT7259_FW_PATH);
|
|
return 1;
|
|
}
|
|
|
|
fw_size = fw_fd->f_op->read(fw_fd, fw_buf, 0x10000, &fw_fd->f_pos);
|
|
printk(KERN_ERR "File Firmware version : %02x %02x %02x %02x\n", fw_buf[136], fw_buf[137], fw_buf[138], fw_buf[139]);
|
|
//printk("--------------------- fw_size = %x\n", fw_size);
|
|
|
|
//load config file
|
|
config_fd = filp_open(IT7259_CFG_PATH, O_RDONLY, 0);
|
|
if (config_fd < 0) {
|
|
printk("open %s failed \n", IT7259_CFG_PATH);
|
|
return 1;
|
|
}
|
|
|
|
config_size = config_fd->f_op->read(config_fd, config_buf, 0x500, &config_fd->f_pos);
|
|
printk(KERN_ERR "File Config version : %02x %02x %02x %02x\n", config_buf[config_size-8], config_buf[config_size-7],
|
|
config_buf[config_size-6], config_buf[config_size-5]);
|
|
|
|
set_fs(fs);
|
|
filp_close(fw_fd, NULL);
|
|
filp_close(config_fd, NULL);
|
|
printk(KERN_ERR "Chip firmware version : %02x %02x %02x %02x\n",
|
|
ts_data->fw_ver[0], ts_data->fw_ver[1],
|
|
ts_data->fw_ver[2], ts_data->fw_ver[3]);
|
|
printk(KERN_ERR "Chip config version : %02x %02x %02x %02x\n",
|
|
ts_data->cfg_ver[0], ts_data->cfg_ver[1],
|
|
ts_data->cfg_ver[2], ts_data->cfg_ver[3]);
|
|
download = 0;
|
|
if ((ts_data->cfg_ver[0] != config_buf[config_size-8]) ||
|
|
(ts_data->cfg_ver[1] != config_buf[config_size-7]) ||
|
|
(ts_data->cfg_ver[2] != config_buf[config_size-6])
|
|
|| (ts_data->cfg_ver[3] != config_buf[config_size-5]))
|
|
download += 1;
|
|
|
|
if ((ts_data->fw_ver[0] != fw_buf[136]) ||
|
|
(ts_data->fw_ver[1] != fw_buf[137]) ||
|
|
(ts_data->fw_ver[2] != fw_buf[138]) ||
|
|
(ts_data->fw_ver[3] != fw_buf[139]))
|
|
download += 2;
|
|
|
|
printk(KERN_ERR "%s, print download = %d\n", __func__, download);
|
|
|
|
if (download == 0) {
|
|
printk(KERN_ERR "Do not need to upgrade\n");
|
|
return 0;
|
|
} else {
|
|
if (gfnIT7259_FirmwareDownload(ts_data, fw_size, fw_buf, config_size, config_buf) == false) {
|
|
//fail
|
|
return 1;
|
|
} else {
|
|
//success
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static ssize_t sysfs_point_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
uint8_t pt_data[sizeof(struct point_data)];
|
|
int readSuccess;
|
|
ssize_t ret;
|
|
|
|
readSuccess = it7259_i2c_read_no_ready_check(ts_data, BUF_POINT_INFO,
|
|
pt_data, sizeof(pt_data));
|
|
|
|
if (readSuccess == IT_I2C_READ_RET) {
|
|
ret = scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"point_show read ret[%d]--point[%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x]\n",
|
|
readSuccess, pt_data[0], pt_data[1],
|
|
pt_data[2], pt_data[3], pt_data[4],
|
|
pt_data[5], pt_data[6], pt_data[7],
|
|
pt_data[8], pt_data[9], pt_data[10],
|
|
pt_data[11], pt_data[12], pt_data[13]);
|
|
} else {
|
|
ret = scnprintf(buf, MAX_BUFFER_SIZE, "failed to read point data\n");
|
|
}
|
|
dev_dbg(dev, "%s", buf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static ssize_t sysfs_upgrade_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
printk(KERN_INFO "%s():\n", __func__);
|
|
if (ts_data->suspended) {
|
|
dev_err(dev, "Device is suspended, can't upgrade FW/CFG !!!\n");
|
|
return -EBUSY;
|
|
}
|
|
|
|
mutex_lock(&ts_data->fw_cfg_mutex);
|
|
if (Upgrade_FW_CFG(ts_data)) {
|
|
printk(KERN_ERR "IT7259_upgrade_failed\n");
|
|
} else {
|
|
printk(KERN_ERR "IT7259_upgrade_OK\n\n");
|
|
}
|
|
mutex_unlock(&ts_data->fw_cfg_mutex);
|
|
return 1;
|
|
}
|
|
|
|
static ssize_t sysfs_upgrade_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
return scnprintf(buf, MAX_BUFFER_SIZE, "%d\n", ts_data->cfg_upgrade_result);
|
|
}
|
|
|
|
static ssize_t sysfs_GetCSEL_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
static const u8 Current_Mode[] = {0x1A, 0x05, 0x00};
|
|
static const u8 Ground_Mode[] = {0x1A, 0x05, 0x01};
|
|
static const u8 Shielding_Mode[] = {0x1A, 0x05, 0x02};
|
|
u8 Current_CSEL[56] = {0,};
|
|
u8 Ground_CSEL[56] = {0,};
|
|
u8 Shielding_CSEL[56] = {0,};
|
|
int ret;
|
|
|
|
ret = it7259_i2c_write_no_ready_check(ts_data, BUF_COMMAND, Current_Mode,
|
|
sizeof(Current_Mode));
|
|
if (ret != IT_I2C_WRITE_RET) {
|
|
dev_err(&ts_data->client->dev, "failed to write CMD_IDENT_CHIP\n");
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to write CMD_IDENT_CHIP\n");
|
|
}
|
|
|
|
ret = it7259_wait_device_ready(ts_data, true, false);
|
|
if (ret < 0) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip status\n");
|
|
}
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, Current_CSEL,
|
|
sizeof(Current_CSEL));
|
|
if (ret != IT_I2C_READ_RET) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip-id\n");
|
|
}
|
|
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"it7259 Current_CSEL : 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n ===========================================================================\n",
|
|
Current_CSEL[0], Current_CSEL[1], Current_CSEL[2], Current_CSEL[3], Current_CSEL[4], Current_CSEL[5], Current_CSEL[6], Current_CSEL[7],
|
|
Current_CSEL[8], Current_CSEL[9], Current_CSEL[10], Current_CSEL[11], Current_CSEL[12], Current_CSEL[13], Current_CSEL[14], Current_CSEL[15],
|
|
Current_CSEL[16], Current_CSEL[17], Current_CSEL[18], Current_CSEL[19], Current_CSEL[20], Current_CSEL[21], Current_CSEL[22], Current_CSEL[23],
|
|
Current_CSEL[24], Current_CSEL[25], Current_CSEL[26], Current_CSEL[27], Current_CSEL[28], Current_CSEL[29], Current_CSEL[30], Current_CSEL[31],
|
|
Current_CSEL[32], Current_CSEL[33], Current_CSEL[34], Current_CSEL[35], Current_CSEL[36], Current_CSEL[37], Current_CSEL[38], Current_CSEL[39],
|
|
Current_CSEL[40], Current_CSEL[41], Current_CSEL[42], Current_CSEL[43], Current_CSEL[44], Current_CSEL[45], Current_CSEL[46], Current_CSEL[47],
|
|
Current_CSEL[48], Current_CSEL[49], Current_CSEL[50], Current_CSEL[51], Current_CSEL[52], Current_CSEL[53], Current_CSEL[54], Current_CSEL[55]);
|
|
|
|
ret = it7259_i2c_write_no_ready_check(ts_data, BUF_COMMAND, Ground_Mode,
|
|
sizeof(Ground_Mode));
|
|
if (ret != IT_I2C_WRITE_RET) {
|
|
dev_err(&ts_data->client->dev, "failed to write CMD_IDENT_CHIP\n");
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to write CMD_IDENT_CHIP\n");
|
|
}
|
|
ret = it7259_wait_device_ready(ts_data, true, false);
|
|
if (ret < 0) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip status\n");
|
|
}
|
|
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, Ground_CSEL,
|
|
sizeof(Ground_CSEL));
|
|
if (ret != IT_I2C_READ_RET) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip-id\n");
|
|
}
|
|
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"it7259 Ground_CSEL : 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n ===========================================================================\n",
|
|
Ground_CSEL[0], Ground_CSEL[1], Ground_CSEL[2], Ground_CSEL[3], Ground_CSEL[4], Ground_CSEL[5], Ground_CSEL[6], Ground_CSEL[7],
|
|
Ground_CSEL[8], Ground_CSEL[9], Ground_CSEL[10], Ground_CSEL[11], Ground_CSEL[12], Ground_CSEL[13], Ground_CSEL[14], Ground_CSEL[15],
|
|
Ground_CSEL[16], Ground_CSEL[17], Ground_CSEL[18], Ground_CSEL[19], Ground_CSEL[20], Ground_CSEL[21], Ground_CSEL[22], Ground_CSEL[23],
|
|
Ground_CSEL[24], Ground_CSEL[25], Ground_CSEL[26], Ground_CSEL[27], Ground_CSEL[28], Ground_CSEL[29], Ground_CSEL[30], Ground_CSEL[31],
|
|
Ground_CSEL[32], Ground_CSEL[33], Ground_CSEL[34], Ground_CSEL[35], Ground_CSEL[36], Ground_CSEL[37], Ground_CSEL[38], Ground_CSEL[39],
|
|
Ground_CSEL[40], Ground_CSEL[41], Ground_CSEL[42], Ground_CSEL[43], Ground_CSEL[44], Ground_CSEL[45], Ground_CSEL[46], Ground_CSEL[47],
|
|
Ground_CSEL[48], Ground_CSEL[49], Ground_CSEL[50], Ground_CSEL[51], Ground_CSEL[52], Ground_CSEL[53], Ground_CSEL[54], Ground_CSEL[55]);
|
|
|
|
ret = it7259_i2c_write_no_ready_check(ts_data, BUF_COMMAND, Shielding_Mode,
|
|
sizeof(Shielding_Mode));
|
|
if (ret != IT_I2C_WRITE_RET) {
|
|
dev_err(&ts_data->client->dev, "failed to write CMD_IDENT_CHIP\n");
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to write CMD_IDENT_CHIP\n");
|
|
}
|
|
|
|
ret = it7259_wait_device_ready(ts_data, true, false);
|
|
if (ret < 0) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip status\n");
|
|
}
|
|
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, Shielding_CSEL,
|
|
sizeof(Shielding_CSEL));
|
|
if (ret != IT_I2C_READ_RET) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip-id\n");
|
|
}
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"it7259 Shielding_CSEL : 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n ===========================================================================\n",
|
|
Shielding_CSEL[0], Shielding_CSEL[1], Shielding_CSEL[2], Shielding_CSEL[3], Shielding_CSEL[4], Shielding_CSEL[5], Shielding_CSEL[6], Shielding_CSEL[7],
|
|
Shielding_CSEL[8], Shielding_CSEL[9], Shielding_CSEL[10], Shielding_CSEL[11], Shielding_CSEL[12], Shielding_CSEL[13], Shielding_CSEL[14], Shielding_CSEL[15],
|
|
Shielding_CSEL[16], Shielding_CSEL[17], Shielding_CSEL[18], Shielding_CSEL[19], Shielding_CSEL[20], Shielding_CSEL[21], Shielding_CSEL[22], Shielding_CSEL[23],
|
|
Shielding_CSEL[24], Shielding_CSEL[25], Shielding_CSEL[26], Shielding_CSEL[27], Shielding_CSEL[28], Shielding_CSEL[29], Shielding_CSEL[30], Shielding_CSEL[31],
|
|
Shielding_CSEL[32], Shielding_CSEL[33], Shielding_CSEL[34], Shielding_CSEL[35], Shielding_CSEL[36], Shielding_CSEL[37], Shielding_CSEL[38], Shielding_CSEL[39],
|
|
Shielding_CSEL[40], Shielding_CSEL[41], Shielding_CSEL[42], Shielding_CSEL[43], Shielding_CSEL[44], Shielding_CSEL[45], Shielding_CSEL[46], Shielding_CSEL[47],
|
|
Shielding_CSEL[48], Shielding_CSEL[49], Shielding_CSEL[50], Shielding_CSEL[51], Shielding_CSEL[52], Shielding_CSEL[53], Shielding_CSEL[54], Shielding_CSEL[55]);
|
|
|
|
}
|
|
|
|
static ssize_t sysfs_readstage_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
static const u8 read_stage[] = {0x1A, 0x00, 0x01, 0x05};
|
|
u8 stage_CDC[10] = {0,};
|
|
int ret;
|
|
|
|
ret = it7259_i2c_write_no_ready_check(ts_data, BUF_COMMAND, read_stage,
|
|
sizeof(read_stage));
|
|
if (ret != IT_I2C_WRITE_RET) {
|
|
dev_err(&ts_data->client->dev, "failed to write CMD_IDENT_CHIP\n");
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to write CMD_IDENT_CHIP\n");
|
|
}
|
|
|
|
ret = it7259_wait_device_ready(ts_data, true, false);
|
|
if (ret < 0) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip status\n");
|
|
}
|
|
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, stage_CDC,
|
|
sizeof(stage_CDC));
|
|
if (ret != IT_I2C_READ_RET) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip-id\n");
|
|
}
|
|
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"it7259 stage CDC : 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X\n",
|
|
stage_CDC[0], stage_CDC[1], stage_CDC[2], stage_CDC[3], stage_CDC[4],
|
|
stage_CDC[5], stage_CDC[6], stage_CDC[7], stage_CDC[8], stage_CDC[9]);
|
|
|
|
}
|
|
static ssize_t sysfs_chipID_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
static const uint8_t cmd_ident[] = {CMD_IDENT_CHIP};
|
|
uint8_t chip_id[10] = {0,};
|
|
int ret;
|
|
|
|
ret = it7259_wait_device_ready(ts_data, false, true);
|
|
if (ret < 0) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip status\n");
|
|
}
|
|
|
|
ret = it7259_i2c_write_no_ready_check(ts_data, BUF_COMMAND, cmd_ident,
|
|
sizeof(cmd_ident));
|
|
if (ret != IT_I2C_WRITE_RET) {
|
|
dev_err(&ts_data->client->dev, "failed to write CMD_IDENT_CHIP\n");
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to write CMD_IDENT_CHIP\n");
|
|
}
|
|
|
|
ret = it7259_wait_device_ready(ts_data, true, false);
|
|
if (ret < 0) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip status\n");
|
|
}
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, chip_id,
|
|
sizeof(chip_id));
|
|
if (ret != IT_I2C_READ_RET) {
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"failed to read chip-id\n");
|
|
}
|
|
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"it7259_ts_chip_identify read id: %02X %c%c%c%c%c%c%c %c%c\n",
|
|
chip_id[0], chip_id[1], chip_id[2], chip_id[3], chip_id[4],
|
|
chip_id[5], chip_id[6], chip_id[7], chip_id[8], chip_id[9]);
|
|
}
|
|
|
|
static ssize_t sysfs_version_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"fw{%X.%X.%X.%X} cfg{%X.%X.%X.%X}\n",
|
|
ts_data->fw_ver[0], ts_data->fw_ver[1],
|
|
ts_data->fw_ver[2], ts_data->fw_ver[3],
|
|
ts_data->cfg_ver[0], ts_data->cfg_ver[1],
|
|
ts_data->cfg_ver[2], ts_data->cfg_ver[3]);
|
|
}
|
|
|
|
static ssize_t sysfs_cfg_name_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
char *strptr;
|
|
|
|
if (count >= MAX_BUFFER_SIZE) {
|
|
dev_err(dev, "Input over %d chars long\n", MAX_BUFFER_SIZE);
|
|
return -EINVAL;
|
|
}
|
|
|
|
strptr = strnstr(buf, ".bin", count);
|
|
if (!strptr) {
|
|
dev_err(dev, "Input is invalid cfg file\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
strlcpy(ts_data->cfg_name, buf, count);
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t sysfs_cfg_name_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
if (strnlen(ts_data->cfg_name, MAX_BUFFER_SIZE) > 0)
|
|
return scnprintf(buf, MAX_BUFFER_SIZE, "%s\n",
|
|
ts_data->cfg_name);
|
|
else
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"No config file name given\n");
|
|
}
|
|
|
|
static ssize_t sysfs_fw_name_store(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
char *strptr;
|
|
|
|
if (count >= MAX_BUFFER_SIZE) {
|
|
dev_err(dev, "Input over %d chars long\n", MAX_BUFFER_SIZE);
|
|
return -EINVAL;
|
|
}
|
|
|
|
strptr = strnstr(buf, ".bin", count);
|
|
if (!strptr) {
|
|
dev_err(dev, "Input is invalid fw file\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
strlcpy(ts_data->fw_name, buf, count);
|
|
return count;
|
|
}
|
|
|
|
static ssize_t sysfs_fw_name_show(struct device *dev,
|
|
struct device_attribute *attr, char *buf)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
|
|
if (strnlen(ts_data->fw_name, MAX_BUFFER_SIZE) > 0)
|
|
return scnprintf(buf, MAX_BUFFER_SIZE, "%s\n",
|
|
ts_data->fw_name);
|
|
else
|
|
return scnprintf(buf, MAX_BUFFER_SIZE,
|
|
"No firmware file name given\n");
|
|
}
|
|
|
|
static DEVICE_ATTR(version, S_IRUGO | S_IWUSR, sysfs_version_show, NULL);
|
|
static DEVICE_ATTR(chipID, S_IRUGO | S_IWUSR, sysfs_chipID_show, NULL);
|
|
static DEVICE_ATTR(readstage, S_IRUGO | S_IWUSR, sysfs_readstage_show, NULL);
|
|
static DEVICE_ATTR(GetCSEL, S_IRUGO | S_IWUSR, sysfs_GetCSEL_show, NULL);
|
|
static DEVICE_ATTR(upgrade, S_IRUGO | S_IWUSR, sysfs_upgrade_show, sysfs_upgrade_store);
|
|
static DEVICE_ATTR(point, S_IRUGO | S_IWUSR, sysfs_point_show, NULL);
|
|
static DEVICE_ATTR(fw_name, S_IRUGO | S_IWUSR, sysfs_fw_name_show, sysfs_fw_name_store);
|
|
static DEVICE_ATTR(cfg_name, S_IRUGO | S_IWUSR, sysfs_cfg_name_show, sysfs_cfg_name_store);
|
|
|
|
static struct attribute *it7259_attributes[] = {
|
|
&dev_attr_version.attr,
|
|
&dev_attr_upgrade.attr,
|
|
&dev_attr_point.attr,
|
|
&dev_attr_fw_name.attr,
|
|
&dev_attr_cfg_name.attr,
|
|
&dev_attr_chipID.attr,
|
|
&dev_attr_readstage.attr,
|
|
&dev_attr_GetCSEL.attr,
|
|
NULL
|
|
};
|
|
|
|
static const struct attribute_group it7259_attr_group = {
|
|
.attrs = it7259_attributes,
|
|
};
|
|
|
|
#ifdef CONFIG_PM
|
|
static void it7259_ts_release_all(struct it7259_ts_data *ts_data)
|
|
{
|
|
int finger;
|
|
|
|
for (finger = 0; finger < ts_data->pdata->num_of_fingers; finger++) {
|
|
input_mt_slot(ts_data->input_dev, finger);
|
|
input_mt_report_slot_state(ts_data->input_dev,
|
|
MT_TOOL_FINGER, 0);
|
|
}
|
|
|
|
input_report_key(ts_data->input_dev, BTN_TOUCH, 0);
|
|
input_sync(ts_data->input_dev);
|
|
}
|
|
#endif
|
|
static irqreturn_t it7259_ts_threaded_handler(int irq, void *devid)
|
|
{
|
|
u16 tmp;
|
|
struct point_data pt_data;
|
|
struct it7259_ts_data *ts_data = devid;
|
|
struct input_dev *input_dev = ts_data->input_dev;
|
|
u8 dev_status, finger, touch_count = 0, finger_status;
|
|
u8 pressure = FD_PRESSURE_NONE;
|
|
u16 x, y, x_center, y_center, panel_radius, disp_radius, x_position, y_position;
|
|
u32 sq_rad_position, sq_disp_position;
|
|
bool palm_detected;
|
|
int ret;
|
|
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
|
|
// printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
/* verify there is point data to read & it is readable and valid */
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_QUERY, &dev_status,
|
|
sizeof(dev_status));
|
|
if (ret == IT_I2C_READ_RET)
|
|
if (!((dev_status & PT_INFO_BITS) & PT_INFO_YES))
|
|
return IRQ_HANDLED;
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_POINT_INFO,
|
|
(void *)&pt_data, sizeof(pt_data));
|
|
if (ret != IT_I2C_READ_RET) {
|
|
dev_err(&ts_data->client->dev,
|
|
"failed to read point data buffer\n");
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
// printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
/* Check if controller moves from idle to active state */
|
|
if ((pt_data.flags & PD_FLAGS_DATA_TYPE_BITS) !=
|
|
PD_FLAGS_DATA_TYPE_TOUCH) {
|
|
/*
|
|
* This code adds the touch-to-wake functionality to the ITE
|
|
* tech driver. When user puts a finger on touch controller in
|
|
* idle state, the controller moves to active state and driver
|
|
* sends the KEY_WAKEUP event to wake the device. The
|
|
* pm_stay_awake() call tells the pm core to stay awake until
|
|
* the CPU cores are up already. The schedule_work() call
|
|
* schedule a work that tells the pm core to relax once the CPU
|
|
* cores are up.
|
|
*/
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
|
|
if ((pt_data.flags & PD_FLAGS_DATA_TYPE_BITS) ==
|
|
PD_FLAGS_IDLE_TO_ACTIVE &&
|
|
pt_data.gesture_id == 0) {
|
|
printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
pm_stay_awake(&ts_data->client->dev);
|
|
// printk("%s %d %s KEY_WAKEUP:0x%x\n", __FILE__, __LINE__, __func__, KEY_WAKEUP);
|
|
input_report_key(input_dev, KEY_WAKEUP, 1);
|
|
input_sync(input_dev);
|
|
input_report_key(input_dev, KEY_WAKEUP, 0);
|
|
input_sync(input_dev);
|
|
schedule_work(&ts_data->work_pm_relax);
|
|
} else {
|
|
dev_dbg(&ts_data->client->dev,
|
|
"Ignore the touch data\n");
|
|
}
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
/*
|
|
* Check if touch data also includes any palm gesture or not.
|
|
* If palm gesture is detected, then send the keycode parsed
|
|
* from the DT.
|
|
printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
*/
|
|
palm_detected = pt_data.gesture_id & PD_PALM_FLAG_BIT;
|
|
if (palm_detected && ts_data->pdata->palm_detect_en) {
|
|
//printk("%s %d %s palm_detect_keycode:0x%x\n", __FILE__, __LINE__, __func__, ts_data->pdata->palm_detect_keycode);
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
|
|
input_report_key(input_dev,
|
|
ts_data->pdata->palm_detect_keycode, 1);
|
|
input_sync(input_dev);
|
|
input_report_key(input_dev,
|
|
ts_data->pdata->palm_detect_keycode, 0);
|
|
input_sync(input_dev);
|
|
}
|
|
|
|
for (finger = 0; finger < ts_data->pdata->num_of_fingers; finger++) {
|
|
finger_status = pt_data.flags & (0x01 << finger);
|
|
//printk("%s %d %s finger:0x%x\n", __FILE__, __LINE__, __func__, finger);
|
|
input_mt_slot(input_dev, finger);
|
|
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
|
|
finger_status != 0);
|
|
|
|
x = pt_data.fd[finger].xLo +
|
|
(((u16)(pt_data.fd[finger].hi & 0x0F)) << 8);
|
|
y = pt_data.fd[finger].yLo +
|
|
(((u16)(pt_data.fd[finger].hi & 0xF0)) << 4);
|
|
pressure = pt_data.fd[finger].pressure & FD_PRESSURE_BITS;
|
|
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
//printk("X: %d Y:%d, pressure:%d\n", x, y, pressure);
|
|
|
|
if (finger_status) {
|
|
if (pressure >= FD_PRESSURE_LIGHT) {
|
|
/* Center co-odinate of panel */
|
|
x_center = 246;
|
|
y_center = 246;
|
|
|
|
/* Radius of the panel */
|
|
panel_radius = x_center;
|
|
|
|
/* Radius of the display */
|
|
disp_radius = 226;
|
|
|
|
/* Distance from present co-ordinate to center co-ordinate */
|
|
if (x > x_center) {
|
|
x_position = x - x_center;
|
|
} else {
|
|
x_position = x_center - x; //only x
|
|
}
|
|
|
|
if (y > y_center) {
|
|
y_position = y - y_center;
|
|
} else {
|
|
y_position = y_center - y; //only y
|
|
}
|
|
|
|
sq_rad_position = (u32)((x_position * x_position) + (u32)(y_position * y_position));
|
|
sq_disp_position = (u32)(disp_radius * disp_radius);
|
|
|
|
tmp = x;
|
|
x = y;
|
|
y = 240 - tmp;
|
|
if (sq_rad_position > sq_disp_position) {
|
|
|
|
//printk("####%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
printk("#### Bezel Touch X: %d Y:%d\n", x, y);
|
|
|
|
input_report_key(input_dev, BTN_TOUCH, 1);
|
|
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
|
|
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
|
|
touch_count++;
|
|
////input_report_key(input_dev, BTN_TOUCH, 0);
|
|
// input_report_key(input_dev, BTN_TOOL_FINGER, 1);
|
|
// input_report_abs(input_dev, ABS_MT_POSITION_X, TS_REMAP_X[x][y]);
|
|
// input_report_abs(input_dev, ABS_MT_POSITION_Y, TS_REMAP_Y[x][y]);
|
|
// input_report_abs(input_dev, ABS_DISTANCE, 5/** Z distance dummy*/);
|
|
// bezel_count++;
|
|
////input_sync(ts_data->input_dev);
|
|
} else {
|
|
//printk("####%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
printk("#### Display Touch X: %d Y:%d\n", x, y);
|
|
input_report_key(input_dev, BTN_TOUCH, 1);
|
|
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
|
|
input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
|
|
touch_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
|
|
|
|
//printk("%s %d %s BTN_TOUCH:0x%x\n", __FILE__, __LINE__, __func__, BTN_TOUCH);
|
|
//printk("%s %d %s touch_count:%d\n", __FILE__, __LINE__, __func__, touch_count);
|
|
input_report_key(input_dev, BTN_TOUCH, touch_count > 0);
|
|
input_sync(input_dev);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static void it7259_ts_work_func(struct work_struct *work)
|
|
{
|
|
struct it7259_ts_data *ts_data = container_of(work,
|
|
struct it7259_ts_data, work_pm_relax);
|
|
|
|
pm_relax(&ts_data->client->dev);
|
|
}
|
|
|
|
static int it7259_ts_chip_identify(struct it7259_ts_data *ts_data)
|
|
{
|
|
static const uint8_t cmd_ident[] = {CMD_IDENT_CHIP};
|
|
static const uint8_t expected_id[] = {0x0A, 'I', 'T', 'E', '7',
|
|
'2', '5', '1'};
|
|
uint8_t chip_id[10] = {0,};
|
|
int ret;
|
|
|
|
/*
|
|
* Sometimes, the controller may not respond immediately after
|
|
* writing the command, so wait for device to get ready.
|
|
* FALSE means to retry 20 times at max to read the chip status.
|
|
* TRUE means to add delay in each retry.
|
|
*/
|
|
ret = it7259_wait_device_ready(ts_data, false, true);
|
|
if (ret < 0) {
|
|
dev_err(&ts_data->client->dev,
|
|
"failed to read chip status %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = it7259_i2c_write_no_ready_check(ts_data, BUF_COMMAND, cmd_ident,
|
|
sizeof(cmd_ident));
|
|
if (ret != IT_I2C_WRITE_RET) {
|
|
dev_err(&ts_data->client->dev,
|
|
"failed to write CMD_IDENT_CHIP %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Sometimes, the controller may not respond immediately after
|
|
* writing the command, so wait for device to get ready.
|
|
* TRUE means to retry 500 times at max to read the chip status.
|
|
* FALSE means to avoid unnecessary delays in each retry.
|
|
*/
|
|
ret = it7259_wait_device_ready(ts_data, true, false);
|
|
if (ret < 0) {
|
|
dev_err(&ts_data->client->dev,
|
|
"failed to read chip status %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, chip_id,
|
|
sizeof(chip_id));
|
|
if (ret != IT_I2C_READ_RET) {
|
|
dev_err(&ts_data->client->dev,
|
|
"failed to read chip-id %d\n", ret);
|
|
return ret;
|
|
}
|
|
dev_info(&ts_data->client->dev,
|
|
"it7259_ts_chip_identify read id: %02X %c%c%c%c%c%c%c %c%c\n",
|
|
chip_id[0], chip_id[1], chip_id[2], chip_id[3], chip_id[4],
|
|
chip_id[5], chip_id[6], chip_id[7], chip_id[8], chip_id[9]);
|
|
|
|
if (memcmp(chip_id, expected_id, sizeof(expected_id)))
|
|
return -EINVAL;
|
|
|
|
/* if (chip_id[8] == '5' && chip_id[9] == '6')
|
|
dev_info(&ts_data->client->dev, "rev BX3 found\n");
|
|
else if (chip_id[8] == '6' && chip_id[9] == '6')
|
|
dev_info(&ts_data->client->dev, "rev BX4 found\n");
|
|
else
|
|
dev_info(&ts_data->client->dev, "unknown revision (0x%02X 0x%02X) found\n",
|
|
chip_id[8], chip_id[9]);
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
|
|
{
|
|
#if 0
|
|
return (regulator_count_voltages(reg) > 0) ?
|
|
regulator_set_optimum_mode(reg, load_uA) : 0;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static int it7259_regulator_configure(struct it7259_ts_data *ts_data, bool on)
|
|
{
|
|
int retval;
|
|
|
|
if (on == false)
|
|
goto hw_shutdown;
|
|
|
|
#if 0
|
|
ts_data->vdd = devm_regulator_get(&ts_data->client->dev, "axp2101_aldo3");
|
|
if (IS_ERR(ts_data->vdd)) {
|
|
dev_err(&ts_data->client->dev,
|
|
"%s: Failed to get vdd regulator\n", __func__);
|
|
return PTR_ERR(ts_data->vdd);
|
|
}
|
|
|
|
if (regulator_count_voltages(ts_data->vdd) > 0) {
|
|
retval = regulator_set_voltage(ts_data->vdd,
|
|
IT_VTG_MIN_UV, IT_VTG_MAX_UV);
|
|
if (retval) {
|
|
dev_err(&ts_data->client->dev,
|
|
"regulator set_vtg failed retval =%d\n",
|
|
retval);
|
|
goto err_set_vtg_vdd;
|
|
}
|
|
}
|
|
#endif
|
|
ts_data->avdd = devm_regulator_get(&ts_data->client->dev, "vcc-ctp");
|
|
if (IS_ERR(ts_data->avdd)) {
|
|
dev_err(&ts_data->client->dev,
|
|
"%s: Failed to get i2c regulator\n", __func__);
|
|
retval = PTR_ERR(ts_data->avdd);
|
|
goto err_get_vtg_i2c;
|
|
}
|
|
|
|
if (regulator_count_voltages(ts_data->avdd) > 0) {
|
|
retval = regulator_set_voltage(ts_data->avdd,
|
|
IT_I2C_VTG_MIN_UV, IT_I2C_VTG_MAX_UV);
|
|
if (retval) {
|
|
dev_err(&ts_data->client->dev,
|
|
"reg set i2c vtg failed retval =%d\n",
|
|
retval);
|
|
goto err_set_vtg_i2c;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
err_set_vtg_i2c:
|
|
err_get_vtg_i2c:
|
|
#if 0
|
|
if (regulator_count_voltages(ts_data->vdd) > 0)
|
|
regulator_set_voltage(ts_data->vdd, 0, IT_VTG_MAX_UV);
|
|
#endif
|
|
return retval;
|
|
|
|
hw_shutdown:
|
|
#if 0
|
|
if (regulator_count_voltages(ts_data->vdd) > 0)
|
|
regulator_set_voltage(ts_data->vdd, 0, IT_VTG_MAX_UV);
|
|
#endif
|
|
if (regulator_count_voltages(ts_data->avdd) > 0)
|
|
regulator_set_voltage(ts_data->avdd, 0, IT_I2C_VTG_MAX_UV);
|
|
return 0;
|
|
};
|
|
|
|
static int it7259_power_on(struct it7259_ts_data *ts_data, bool on)
|
|
{
|
|
int retval;
|
|
|
|
if (on == false)
|
|
goto power_off;
|
|
|
|
#if 0
|
|
retval = reg_set_optimum_mode_check(ts_data->vdd,
|
|
IT_ACTIVE_LOAD_UA);
|
|
if (retval < 0) {
|
|
dev_err(&ts_data->client->dev,
|
|
"Regulator vdd set_opt failed rc=%d\n",
|
|
retval);
|
|
return retval;
|
|
}
|
|
|
|
retval = regulator_enable(ts_data->vdd);
|
|
if (retval) {
|
|
dev_err(&ts_data->client->dev,
|
|
"Regulator vdd enable failed rc=%d\n",
|
|
retval);
|
|
goto error_reg_en_vdd;
|
|
}
|
|
#endif
|
|
|
|
retval = reg_set_optimum_mode_check(ts_data->avdd,
|
|
IT_I2C_ACTIVE_LOAD_UA);
|
|
if (retval < 0) {
|
|
dev_err(&ts_data->client->dev,
|
|
"Regulator avdd set_opt failed rc=%d\n",
|
|
retval);
|
|
goto error_reg_opt_i2c;
|
|
}
|
|
|
|
retval = regulator_enable(ts_data->avdd);
|
|
if (retval) {
|
|
dev_err(&ts_data->client->dev,
|
|
"Regulator avdd enable failed rc=%d\n",
|
|
retval);
|
|
goto error_reg_en_avdd;
|
|
}
|
|
return 0;
|
|
|
|
error_reg_en_avdd:
|
|
reg_set_optimum_mode_check(ts_data->avdd, 0);
|
|
error_reg_opt_i2c:
|
|
#if 0
|
|
regulator_disable(ts_data->vdd);
|
|
#endif
|
|
#if 0
|
|
reg_set_optimum_mode_check(ts_data->vdd, 0);
|
|
#endif
|
|
return retval;
|
|
|
|
power_off:
|
|
#if 0
|
|
reg_set_optimum_mode_check(ts_data->vdd, 0);
|
|
regulator_disable(ts_data->vdd);
|
|
#endif
|
|
reg_set_optimum_mode_check(ts_data->avdd, 0);
|
|
regulator_disable(ts_data->avdd);
|
|
return 0;
|
|
}
|
|
|
|
static int it7259_gpio_configure(struct it7259_ts_data *ts_data, bool on)
|
|
{
|
|
int retval = 0;
|
|
|
|
if (on) {
|
|
if (gpio_is_valid(ts_data->pdata->irq_gpio)) {
|
|
/* configure touchscreen irq gpio */
|
|
retval = gpio_request(ts_data->pdata->irq_gpio,
|
|
"ite_irq_gpio");
|
|
if (retval) {
|
|
dev_err(&ts_data->client->dev,
|
|
"unable to request irq gpio [%d]\n",
|
|
retval);
|
|
goto err_irq_gpio_req;
|
|
}
|
|
|
|
retval = gpio_direction_input(ts_data->pdata->irq_gpio);
|
|
if (retval) {
|
|
dev_err(&ts_data->client->dev,
|
|
"unable to set direction for irq gpio [%d]\n",
|
|
retval);
|
|
goto err_irq_gpio_dir;
|
|
}
|
|
} else {
|
|
dev_err(&ts_data->client->dev,
|
|
"irq gpio not provided\n");
|
|
goto err_irq_gpio_req;
|
|
}
|
|
|
|
if (gpio_is_valid(ts_data->pdata->reset_gpio)) {
|
|
/* configure touchscreen reset out gpio */
|
|
retval = gpio_request(ts_data->pdata->reset_gpio,
|
|
"ite_reset_gpio");
|
|
if (retval) {
|
|
dev_err(&ts_data->client->dev,
|
|
"unable to request reset gpio [%d]\n",
|
|
retval);
|
|
goto err_reset_gpio_req;
|
|
}
|
|
|
|
retval = gpio_direction_output(
|
|
ts_data->pdata->reset_gpio, 1);
|
|
if (retval) {
|
|
dev_err(&ts_data->client->dev,
|
|
"unable to set direction for reset gpio [%d]\n",
|
|
retval);
|
|
goto err_reset_gpio_dir;
|
|
}
|
|
|
|
if (ts_data->pdata->low_reset)
|
|
gpio_set_value(ts_data->pdata->reset_gpio, 0);
|
|
else
|
|
gpio_set_value(ts_data->pdata->reset_gpio, 1);
|
|
|
|
udelay(ts_data->pdata->reset_delay);
|
|
if (ts_data->pdata->low_reset)
|
|
gpio_set_value(ts_data->pdata->reset_gpio, 1);
|
|
else
|
|
gpio_set_value(ts_data->pdata->reset_gpio, 0);
|
|
} else {
|
|
dev_err(&ts_data->client->dev,
|
|
"reset gpio not provided\n");
|
|
goto err_reset_gpio_req;
|
|
}
|
|
} else {
|
|
if (gpio_is_valid(ts_data->pdata->irq_gpio))
|
|
gpio_free(ts_data->pdata->irq_gpio);
|
|
if (gpio_is_valid(ts_data->pdata->reset_gpio)) {
|
|
/*
|
|
* This is intended to save leakage current
|
|
* only. Even if the call(gpio_direction_input)
|
|
* fails, only leakage current will be more but
|
|
* functionality will not be affected.
|
|
*/
|
|
retval = gpio_direction_input(
|
|
ts_data->pdata->reset_gpio);
|
|
if (retval) {
|
|
dev_err(&ts_data->client->dev,
|
|
"unable to set direction for gpio reset [%d]\n",
|
|
retval);
|
|
}
|
|
gpio_free(ts_data->pdata->reset_gpio);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_reset_gpio_dir:
|
|
if (gpio_is_valid(ts_data->pdata->reset_gpio))
|
|
gpio_free(ts_data->pdata->reset_gpio);
|
|
err_reset_gpio_req:
|
|
err_irq_gpio_dir:
|
|
if (gpio_is_valid(ts_data->pdata->irq_gpio))
|
|
gpio_free(ts_data->pdata->irq_gpio);
|
|
err_irq_gpio_req:
|
|
return retval;
|
|
}
|
|
#if CONFIG_OF
|
|
#if 0
|
|
static int it7259_get_dt_coords(struct device *dev, char *name, struct it7259_ts_platform_data *pdata)
|
|
{
|
|
u32 coords[it7259_COORDS_ARR_SIZE];
|
|
struct property *prop;
|
|
struct device_node *np = dev->of_node;
|
|
int coords_size, rc;
|
|
|
|
prop = of_find_property(np, name, NULL);
|
|
if (!prop)
|
|
return -EINVAL;
|
|
if (!prop->value)
|
|
return -ENODATA;
|
|
|
|
coords_size = prop->length / sizeof(u32);
|
|
if (coords_size != it7259_COORDS_ARR_SIZE) {
|
|
dev_err(dev, "invalid %s\n", name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = of_property_read_u32_array(np, name, coords, coords_size);
|
|
if (rc && (rc != -EINVAL)) {
|
|
dev_err(dev, "Unable to read %s\n", name);
|
|
return rc;
|
|
}
|
|
|
|
if (strcmp(name, "panel-coords") == 0) {
|
|
pdata->panel_minx = coords[0];
|
|
pdata->panel_miny = coords[1];
|
|
pdata->panel_maxx = coords[2];
|
|
pdata->panel_maxy = coords[3];
|
|
|
|
if (pdata->panel_maxx == 0 || pdata->panel_minx > 0)
|
|
rc = -EINVAL;
|
|
else if (pdata->panel_maxy == 0 || pdata->panel_miny > 0)
|
|
rc = -EINVAL;
|
|
|
|
if (rc) {
|
|
dev_err(dev, "Invalid panel resolution %d\n", rc);
|
|
return rc;
|
|
}
|
|
} else if (strcmp(name, "display-coords") == 0) {
|
|
pdata->disp_minx = coords[0];
|
|
pdata->disp_miny = coords[1];
|
|
pdata->disp_maxx = coords[2];
|
|
pdata->disp_maxy = coords[3];
|
|
} else {
|
|
dev_err(dev, "unsupported property %s\n", name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int it7259_parse_dt(struct device *dev, struct it7259_ts_platform_data *pdata)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
struct device_node *np = dev->of_node;
|
|
u32 temp_val;
|
|
int rc;
|
|
|
|
/* reset, irq gpio info */
|
|
pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &pdata->reset_gpio_flags);
|
|
|
|
pdata->irq_gpio = of_get_named_gpio_flags(np, "int-gpios", 0, &pdata->irq_gpio_flags);
|
|
|
|
rc = of_property_read_u32(np, "num-fingers", &temp_val);
|
|
if (!rc)
|
|
pdata->num_of_fingers = temp_val;
|
|
else if (rc != -EINVAL) {
|
|
dev_err(dev, "Unable to read reset delay\n");
|
|
return rc;
|
|
}
|
|
//printk("%s %d %s num-fingers:%d\n", __FILE__, __LINE__, __func__, temp_val);
|
|
pdata->wakeup = of_property_read_bool(np, "wakeup");
|
|
//printk("%s %d %s wakeup:%d\n", __FILE__, __LINE__, __func__, pdata->wakeup);
|
|
pdata->palm_detect_en = of_property_read_bool(np, "palm-detect-en");
|
|
//printk("%s %d %s palm-detect-en:%d\n", __FILE__, __LINE__, __func__, pdata->palm_detect_en);
|
|
if (pdata->palm_detect_en) {
|
|
rc = of_property_read_u32(np, "ite,palm-detect-keycode", &temp_val);
|
|
if (!rc) {
|
|
pdata->palm_detect_keycode = temp_val;
|
|
} else {
|
|
dev_err(dev, "Unable to read palm-detect-keycode\n");
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
rc = of_property_read_string(np, "fw-name", &pdata->fw_name);
|
|
if (rc && (rc != -EINVAL)) {
|
|
dev_err(dev, "Unable to read fw image name %d\n", rc);
|
|
return rc;
|
|
} else if (rc == -EINVAL) {
|
|
pdata->fw_name = NULL;
|
|
}
|
|
//printk("%s %d %s rc:%d\n", __FILE__, __LINE__, __func__, rc);
|
|
rc = of_property_read_string(np, "cfg-name", &pdata->cfg_name);
|
|
if (rc && (rc != -EINVAL)) {
|
|
dev_err(dev, "Unable to read cfg image name %d\n", rc);
|
|
return rc;
|
|
} else if (rc == -EINVAL) {
|
|
pdata->cfg_name = NULL;
|
|
}
|
|
|
|
//printk("%s %d %s rc:%d\n", __FILE__, __LINE__, __func__, rc);
|
|
snprintf(ts_data->fw_name, MAX_BUFFER_SIZE, "%s", (pdata->fw_name != NULL) ? pdata->fw_name : FW_NAME);
|
|
snprintf(ts_data->cfg_name, MAX_BUFFER_SIZE, "%s", (pdata->cfg_name != NULL) ? pdata->cfg_name : CFG_NAME);
|
|
|
|
rc = of_property_read_u32(np, "reset-delay", &temp_val);
|
|
if (!rc)
|
|
pdata->reset_delay = temp_val;
|
|
else if (rc != -EINVAL) {
|
|
dev_err(dev, "Unable to read reset delay\n");
|
|
return rc;
|
|
}
|
|
//printk("%s %d %s reset_delay:%d\n", __FILE__, __LINE__, __func__, pdata->reset_delay);
|
|
|
|
rc = of_property_read_u32(np, "avdd-lpm-cur", &temp_val);
|
|
if (!rc) {
|
|
pdata->avdd_lpm_cur = temp_val;
|
|
} else if (rc && (rc != -EINVAL)) {
|
|
dev_err(dev, "Unable to read avdd lpm current value %d\n", rc);
|
|
return rc;
|
|
}
|
|
pdata->low_reset = of_property_read_bool(np, "low-reset");
|
|
//printk("%s %d %s low_reset:%d\n", __FILE__, __LINE__, __func__, pdata->low_reset);
|
|
#if 1
|
|
pdata->disp_minx = 0;
|
|
pdata->disp_miny = 0;
|
|
pdata->disp_maxx = 240;
|
|
pdata->disp_maxy = 240;
|
|
pdata->panel_minx = 0;
|
|
pdata->panel_miny = 0;
|
|
pdata->panel_maxx = 240;
|
|
pdata->panel_maxy = 240;
|
|
#else
|
|
rc = it7259_get_dt_coords(dev, "display-coords", pdata);
|
|
if (rc && (rc != -EINVAL))
|
|
return rc;
|
|
|
|
rc = it7259_get_dt_coords(dev, "panel-coords", pdata);
|
|
if (rc && (rc != -EINVAL))
|
|
return rc;
|
|
#endif
|
|
return 0;
|
|
}
|
|
#else
|
|
static inline int it7259_ts_parse_dt(struct device *dev, struct it7259_ts_platform_data *pdata)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
static int it7259_ts_pinctrl_init(struct it7259_ts_data *ts_data)
|
|
{
|
|
int retval = 0;
|
|
|
|
/* Get pinctrl if target uses pinctrl */
|
|
ts_data->ts_pinctrl = devm_pinctrl_get(&(ts_data->client->dev));
|
|
if (IS_ERR_OR_NULL(ts_data->ts_pinctrl)) {
|
|
retval = PTR_ERR(ts_data->ts_pinctrl);
|
|
dev_dbg(&ts_data->client->dev, "Target does not use pinctrl %d\n", retval);
|
|
goto err_pinctrl_get;
|
|
}
|
|
|
|
ts_data->pinctrl_state_active = pinctrl_lookup_state(ts_data->ts_pinctrl, PINCTRL_STATE_ACTIVE);
|
|
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_active)) {
|
|
retval = PTR_ERR(ts_data->pinctrl_state_active);
|
|
dev_err(&ts_data->client->dev, "Can not lookup %s pinstate %d\n", PINCTRL_STATE_ACTIVE, retval);
|
|
goto err_pinctrl_lookup;
|
|
}
|
|
|
|
ts_data->pinctrl_state_suspend = pinctrl_lookup_state(ts_data->ts_pinctrl, PINCTRL_STATE_SUSPEND);
|
|
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_suspend)) {
|
|
retval = PTR_ERR(ts_data->pinctrl_state_suspend);
|
|
dev_err(&ts_data->client->dev, "Can not lookup %s pinstate %d\n", PINCTRL_STATE_SUSPEND, retval);
|
|
goto err_pinctrl_lookup;
|
|
}
|
|
|
|
ts_data->pinctrl_state_release = pinctrl_lookup_state(ts_data->ts_pinctrl, PINCTRL_STATE_RELEASE);
|
|
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) {
|
|
retval = PTR_ERR(ts_data->pinctrl_state_release);
|
|
dev_dbg(&ts_data->client->dev, "Can not lookup %s pinstate %d\n", PINCTRL_STATE_RELEASE, retval);
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_pinctrl_lookup:
|
|
devm_pinctrl_put(ts_data->ts_pinctrl);
|
|
err_pinctrl_get:
|
|
ts_data->ts_pinctrl = NULL;
|
|
return retval;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* this code to get versions from the chip via i2c transactions, and save
|
|
* them in driver data structure.
|
|
*/
|
|
static void it7259_get_chip_versions(struct it7259_ts_data *ts_data)
|
|
{
|
|
static const u8 cmd_read_fw_ver[] = {CMD_READ_VERSIONS, SUB_CMD_READ_FIRMWARE_VERSION};
|
|
static const u8 cmd_read_cfg_ver[] = {CMD_READ_VERSIONS, SUB_CMD_READ_CONFIG_VERSION};
|
|
u8 ver_fw[VERSION_LENGTH] = {0}, ver_cfg[VERSION_LENGTH] = {0};
|
|
int ret = 0;
|
|
|
|
ret = it7259_i2c_write(ts_data, BUF_COMMAND, cmd_read_fw_ver, sizeof(cmd_read_fw_ver));
|
|
if (ret == IT_I2C_WRITE_RET) {
|
|
/*
|
|
* Sometimes, the controller may not respond immediately after
|
|
* writing the command, so wait for device to get ready.
|
|
*/
|
|
ret = it7259_wait_device_ready(ts_data, true, false);
|
|
if (ret < 0)
|
|
dev_err(&ts_data->client->dev, "failed to read chip status %d\n", ret);
|
|
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, ver_fw, VERSION_LENGTH);
|
|
if (ret == IT_I2C_READ_RET)
|
|
memcpy(ts_data->fw_ver, ver_fw + (5 * sizeof(u8)), VER_BUFFER_SIZE * sizeof(u8));
|
|
else
|
|
dev_err(&ts_data->client->dev, "failed to read fw-ver from chip %d\n", ret);
|
|
} else {
|
|
dev_err(&ts_data->client->dev, "failed to write fw-read command %d\n", ret);
|
|
}
|
|
|
|
ret = it7259_i2c_write(ts_data, BUF_COMMAND, cmd_read_cfg_ver, sizeof(cmd_read_cfg_ver));
|
|
if (ret == IT_I2C_WRITE_RET) {
|
|
/*
|
|
* Sometimes, the controller may not respond immediately after
|
|
* writing the command, so wait for device to get ready.
|
|
*/
|
|
ret = it7259_wait_device_ready(ts_data, true, false);
|
|
if (ret < 0)
|
|
dev_err(&ts_data->client->dev, "failed to read chip status %d\n", ret);
|
|
|
|
ret = it7259_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, ver_cfg, VERSION_LENGTH);
|
|
if (ret == IT_I2C_READ_RET)
|
|
memcpy(ts_data->cfg_ver, ver_cfg + (1 * sizeof(u8)), VER_BUFFER_SIZE * sizeof(u8));
|
|
else
|
|
dev_err(&ts_data->client->dev, "failed to read cfg-ver from chip %d\n", ret);
|
|
} else {
|
|
dev_err(&ts_data->client->dev, "failed to write cfg-read command %d\n", ret);
|
|
}
|
|
|
|
dev_info(&ts_data->client->dev, "Current fw{%X.%X.%X.%X} cfg{%X.%X.%X.%X}\n",
|
|
ts_data->fw_ver[0], ts_data->fw_ver[1], ts_data->fw_ver[2],
|
|
ts_data->fw_ver[3], ts_data->cfg_ver[0], ts_data->cfg_ver[1],
|
|
ts_data->cfg_ver[2], ts_data->cfg_ver[3]);
|
|
}
|
|
|
|
|
|
static int it7259_ts_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
static const uint8_t cmd_start[] = {CMD_UNKNOWN_7};
|
|
struct it7259_ts_data *ts_data = NULL;
|
|
struct it7259_ts_platform_data *pdata = NULL;
|
|
uint8_t rsp[2];
|
|
int ret = -1, err;
|
|
struct dentry *temp;
|
|
|
|
printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
|
dev_err(&client->dev, "need I2C_FUNC_I2C\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
ts_data = devm_kzalloc(&client->dev, sizeof(*ts_data), GFP_KERNEL);
|
|
if (!ts_data)
|
|
return -ENOMEM;
|
|
|
|
ts_data->client = client;
|
|
i2c_set_clientdata(client, ts_data);
|
|
|
|
if (client->dev.of_node) {
|
|
pdata = devm_kzalloc(&client->dev, sizeof(struct it7259_ts_platform_data), GFP_KERNEL);
|
|
if (!pdata)
|
|
return -ENOMEM;
|
|
|
|
ret = it7259_parse_dt(&client->dev, pdata);
|
|
if (ret)
|
|
return ret;
|
|
} else {
|
|
pdata = client->dev.platform_data;
|
|
}
|
|
|
|
if (!pdata) {
|
|
dev_err(&client->dev, "No platform data found\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
ts_data->pdata = pdata;
|
|
|
|
ret = it7259_regulator_configure(ts_data, true);
|
|
if (ret < 0) {
|
|
dev_err(&client->dev, "Failed to configure regulators\n");
|
|
goto err_reg_configure;
|
|
}
|
|
ret = it7259_power_on(ts_data, true);
|
|
if (ret < 0) {
|
|
dev_err(&client->dev, "Failed to power on\n");
|
|
goto err_power_device;
|
|
}
|
|
/*
|
|
* After enabling regulators, controller needs a delay to come to
|
|
* an active state.
|
|
*/
|
|
msleep(DELAY_VTG_REG_EN);
|
|
|
|
ret = it7259_ts_pinctrl_init(ts_data);
|
|
if (!ret && ts_data->ts_pinctrl) {
|
|
/*
|
|
* Pinctrl handle is optional. If pinctrl handle is found
|
|
* let pins to be configured in active state. If not
|
|
* found continue further without error.
|
|
*/
|
|
ret = pinctrl_select_state(ts_data->ts_pinctrl,
|
|
ts_data->pinctrl_state_active);
|
|
if (ret < 0) {
|
|
dev_err(&ts_data->client->dev,
|
|
"failed to select pin to active state %d",
|
|
ret);
|
|
}
|
|
} else {
|
|
ret = it7259_gpio_configure(ts_data, true);
|
|
if (ret < 0) {
|
|
dev_err(&client->dev, "Failed to configure gpios\n");
|
|
goto err_gpio_config;
|
|
}
|
|
}
|
|
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
ret = it7259_ts_chip_identify(ts_data);
|
|
if (ret) {
|
|
dev_err(&client->dev, "Failed to identify chip %d!!!", ret);
|
|
goto err_identification_fail;
|
|
}
|
|
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
it7259_get_chip_versions(ts_data);
|
|
|
|
ts_data->input_dev = input_allocate_device();
|
|
if (!ts_data->input_dev) {
|
|
dev_err(&client->dev, "failed to allocate input device\n");
|
|
ret = -ENOMEM;
|
|
goto err_input_alloc;
|
|
}
|
|
|
|
/* Initialize mutex for fw and cfg upgrade */
|
|
mutex_init(&ts_data->fw_cfg_mutex);
|
|
|
|
ts_data->input_dev->name = DEVICE_NAME;
|
|
ts_data->input_dev->phys = "I2C";
|
|
ts_data->input_dev->id.bustype = BUS_I2C;
|
|
ts_data->input_dev->id.vendor = 0x0001;
|
|
ts_data->input_dev->id.product = 0x7259;
|
|
set_bit(EV_SYN, ts_data->input_dev->evbit);
|
|
set_bit(EV_KEY, ts_data->input_dev->evbit);
|
|
set_bit(EV_ABS, ts_data->input_dev->evbit);
|
|
set_bit(INPUT_PROP_DIRECT, ts_data->input_dev->propbit);
|
|
set_bit(BTN_TOUCH, ts_data->input_dev->keybit);
|
|
printk("disp_minx=%d, %d\n", ts_data->pdata->disp_minx, ts_data->pdata->disp_maxx);
|
|
printk("disp_miny=%d, %d\n", ts_data->pdata->disp_miny, ts_data->pdata->disp_maxy);
|
|
input_set_abs_params(ts_data->input_dev, ABS_MT_POSITION_X,
|
|
ts_data->pdata->disp_minx, ts_data->pdata->disp_maxx, 0, 0);
|
|
input_set_abs_params(ts_data->input_dev, ABS_MT_POSITION_Y,
|
|
ts_data->pdata->disp_miny, ts_data->pdata->disp_maxy, 0, 0);
|
|
input_mt_init_slots(ts_data->input_dev,
|
|
ts_data->pdata->num_of_fingers, 0);
|
|
input_set_drvdata(ts_data->input_dev, ts_data);
|
|
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
if (pdata->wakeup) {
|
|
set_bit(KEY_WAKEUP, ts_data->input_dev->keybit);
|
|
INIT_WORK(&ts_data->work_pm_relax, it7259_ts_work_func);
|
|
device_init_wakeup(&client->dev, pdata->wakeup);
|
|
}
|
|
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
if (pdata->palm_detect_en)
|
|
set_bit(ts_data->pdata->palm_detect_keycode,
|
|
ts_data->input_dev->keybit);
|
|
|
|
if (input_register_device(ts_data->input_dev)) {
|
|
dev_err(&client->dev, "failed to register input device\n");
|
|
goto err_input_register;
|
|
}
|
|
|
|
//printk("%s %d %s client->irq:%d\n", __FILE__, __LINE__, __func__, client->irq);
|
|
client->irq = gpio_to_irq(ts_data->pdata->irq_gpio);
|
|
//printk("%s %d %s client->irq:%d\n", __FILE__, __LINE__, __func__, client->irq);
|
|
ret = request_threaded_irq(client->irq, NULL, it7259_ts_threaded_handler,
|
|
IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts_data);
|
|
if (ret != 0) {
|
|
dev_err(&client->dev, "request_irq failed %d\n", ret);
|
|
goto err_irq_reg;
|
|
}
|
|
|
|
if (sysfs_create_group(&(client->dev.kobj), &it7259_attr_group)) {
|
|
dev_err(&client->dev, "failed to register sysfs #2\n");
|
|
goto err_sysfs_grp_create;
|
|
}
|
|
|
|
#if defined(CONFIG_FB)
|
|
ts_data->fb_notif.notifier_call = fb_notifier_callback;
|
|
|
|
ret = fb_register_client(&ts_data->fb_notif);
|
|
if (ret)
|
|
dev_err(&client->dev, "Unable to register fb_notifier %d\n",
|
|
ret);
|
|
#endif
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
it7259_i2c_write_no_ready_check(ts_data, BUF_COMMAND, cmd_start,
|
|
sizeof(cmd_start));
|
|
udelay(pdata->reset_delay);
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
it7259_i2c_read_no_ready_check(ts_data, BUF_RESPONSE, rsp, sizeof(rsp));
|
|
udelay(pdata->reset_delay);
|
|
|
|
//printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
ts_data->dir = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL);
|
|
if (ts_data->dir == NULL || IS_ERR(ts_data->dir)) {
|
|
dev_err(&client->dev,
|
|
"%s: Failed to create debugfs directory, ret = %ld\n",
|
|
__func__, PTR_ERR(ts_data->dir));
|
|
ret = PTR_ERR(ts_data->dir);
|
|
goto err_create_debugfs_dir;
|
|
}
|
|
|
|
printk("%s %d %s\n", __FILE__, __LINE__, __func__);
|
|
temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, ts_data->dir,
|
|
ts_data, &debug_suspend_fops);
|
|
if (temp == NULL || IS_ERR(temp)) {
|
|
dev_err(&client->dev,
|
|
"%s: Failed to create suspend debugfs file, ret = %ld\n",
|
|
__func__, PTR_ERR(temp));
|
|
ret = PTR_ERR(temp);
|
|
goto err_create_debugfs_file;
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_create_debugfs_file:
|
|
debugfs_remove_recursive(ts_data->dir);
|
|
err_create_debugfs_dir:
|
|
#if defined(CONFIG_FB)
|
|
if (fb_unregister_client(&ts_data->fb_notif))
|
|
dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
|
|
#endif
|
|
sysfs_remove_group(&(client->dev.kobj), &it7259_attr_group);
|
|
|
|
err_sysfs_grp_create:
|
|
free_irq(client->irq, ts_data);
|
|
|
|
err_irq_reg:
|
|
input_unregister_device(ts_data->input_dev);
|
|
|
|
err_input_register:
|
|
if (pdata->wakeup) {
|
|
cancel_work_sync(&ts_data->work_pm_relax);
|
|
device_init_wakeup(&client->dev, false);
|
|
}
|
|
if (ts_data->input_dev)
|
|
input_free_device(ts_data->input_dev);
|
|
ts_data->input_dev = NULL;
|
|
|
|
err_input_alloc:
|
|
err_identification_fail:
|
|
if (ts_data->ts_pinctrl) {
|
|
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) {
|
|
devm_pinctrl_put(ts_data->ts_pinctrl);
|
|
ts_data->ts_pinctrl = NULL;
|
|
} else {
|
|
err = pinctrl_select_state(ts_data->ts_pinctrl,
|
|
ts_data->pinctrl_state_release);
|
|
if (err)
|
|
dev_err(&ts_data->client->dev,
|
|
"failed to select relase pinctrl state %d\n",
|
|
err);
|
|
}
|
|
} else {
|
|
if (gpio_is_valid(pdata->reset_gpio))
|
|
gpio_free(pdata->reset_gpio);
|
|
if (gpio_is_valid(pdata->irq_gpio))
|
|
gpio_free(pdata->irq_gpio);
|
|
}
|
|
|
|
err_gpio_config:
|
|
it7259_power_on(ts_data, false);
|
|
|
|
err_power_device:
|
|
it7259_regulator_configure(ts_data, false);
|
|
|
|
err_reg_configure:
|
|
return ret;
|
|
}
|
|
|
|
static int it7259_ts_remove(struct i2c_client *client)
|
|
{
|
|
struct it7259_ts_data *ts_data = i2c_get_clientdata(client);
|
|
int ret;
|
|
|
|
debugfs_remove_recursive(ts_data->dir);
|
|
#if defined(CONFIG_FB)
|
|
if (fb_unregister_client(&ts_data->fb_notif))
|
|
dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
|
|
#endif
|
|
sysfs_remove_group(&(client->dev.kobj), &it7259_attr_group);
|
|
free_irq(client->irq, ts_data);
|
|
input_unregister_device(ts_data->input_dev);
|
|
if (ts_data->input_dev)
|
|
input_free_device(ts_data->input_dev);
|
|
ts_data->input_dev = NULL;
|
|
if (ts_data->pdata->wakeup) {
|
|
cancel_work_sync(&ts_data->work_pm_relax);
|
|
device_init_wakeup(&client->dev, false);
|
|
}
|
|
if (ts_data->ts_pinctrl) {
|
|
if (IS_ERR_OR_NULL(ts_data->pinctrl_state_release)) {
|
|
devm_pinctrl_put(ts_data->ts_pinctrl);
|
|
ts_data->ts_pinctrl = NULL;
|
|
} else {
|
|
ret = pinctrl_select_state(ts_data->ts_pinctrl,
|
|
ts_data->pinctrl_state_release);
|
|
if (ret)
|
|
dev_err(&ts_data->client->dev,
|
|
"failed to select relase pinctrl state %d\n",
|
|
ret);
|
|
}
|
|
} else {
|
|
if (gpio_is_valid(ts_data->pdata->reset_gpio))
|
|
gpio_free(ts_data->pdata->reset_gpio);
|
|
if (gpio_is_valid(ts_data->pdata->irq_gpio))
|
|
gpio_free(ts_data->pdata->irq_gpio);
|
|
}
|
|
it7259_power_on(ts_data, false);
|
|
it7259_regulator_configure(ts_data, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_FB)
|
|
static int fb_notifier_callback(struct notifier_block *self,
|
|
unsigned long event, void *data)
|
|
{
|
|
struct it7259_ts_data *ts_data = container_of(self,
|
|
struct it7259_ts_data, fb_notif);
|
|
struct fb_event *evdata = data;
|
|
int *blank;
|
|
|
|
if (evdata && evdata->data && ts_data && ts_data->client) {
|
|
if (event == FB_EVENT_BLANK) {
|
|
blank = evdata->data;
|
|
if (*blank == FB_BLANK_UNBLANK)
|
|
it7259_ts_resume(&(ts_data->client->dev));
|
|
else if (*blank == FB_BLANK_POWERDOWN ||
|
|
*blank == FB_BLANK_VSYNC_SUSPEND)
|
|
it7259_ts_suspend(&(ts_data->client->dev));
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_PM
|
|
static int it7259_ts_resume(struct device *dev)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
int retval;
|
|
|
|
if (device_may_wakeup(dev)) {
|
|
if (ts_data->in_low_power_mode) {
|
|
/* Set active current for the avdd regulator */
|
|
if (ts_data->pdata->avdd_lpm_cur) {
|
|
retval = reg_set_optimum_mode_check(
|
|
ts_data->avdd,
|
|
IT_I2C_ACTIVE_LOAD_UA);
|
|
if (retval < 0)
|
|
dev_err(dev, "Regulator avdd set_opt failed at resume rc=%d\n",
|
|
retval);
|
|
}
|
|
|
|
ts_data->in_low_power_mode = false;
|
|
disable_irq_wake(ts_data->client->irq);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (ts_data->ts_pinctrl) {
|
|
retval = pinctrl_select_state(ts_data->ts_pinctrl,
|
|
ts_data->pinctrl_state_active);
|
|
if (retval < 0) {
|
|
dev_err(dev, "Cannot get default pinctrl state %d\n",
|
|
retval);
|
|
goto err_pinctrl_select_suspend;
|
|
}
|
|
}
|
|
|
|
enable_irq(ts_data->client->irq);
|
|
ts_data->suspended = false;
|
|
return 0;
|
|
|
|
err_pinctrl_select_suspend:
|
|
return retval;
|
|
}
|
|
|
|
static int it7259_ts_suspend(struct device *dev)
|
|
{
|
|
struct it7259_ts_data *ts_data = dev_get_drvdata(dev);
|
|
int retval;
|
|
|
|
if (ts_data->fw_cfg_uploading) {
|
|
dev_dbg(dev, "Fw/cfg uploading. Can't go to suspend.\n");
|
|
return -EBUSY;
|
|
}
|
|
|
|
if (device_may_wakeup(dev)) {
|
|
if (!ts_data->in_low_power_mode) {
|
|
/* put the device in low power idle mode */
|
|
retval = it7259_ts_chip_low_power_mode(ts_data,
|
|
PWR_CTL_LOW_POWER_MODE);
|
|
if (retval)
|
|
dev_err(dev, "Can't go to low power mode %d\n",
|
|
retval);
|
|
|
|
/* Set lpm current for avdd regulator */
|
|
if (ts_data->pdata->avdd_lpm_cur) {
|
|
retval = reg_set_optimum_mode_check(
|
|
ts_data->avdd,
|
|
ts_data->pdata->avdd_lpm_cur);
|
|
if (retval < 0)
|
|
dev_err(dev, "Regulator avdd set_opt failed at suspend rc=%d\n",
|
|
retval);
|
|
}
|
|
|
|
ts_data->in_low_power_mode = true;
|
|
enable_irq_wake(ts_data->client->irq);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
disable_irq(ts_data->client->irq);
|
|
|
|
it7259_ts_release_all(ts_data);
|
|
|
|
if (ts_data->ts_pinctrl) {
|
|
retval = pinctrl_select_state(ts_data->ts_pinctrl,
|
|
ts_data->pinctrl_state_suspend);
|
|
if (retval < 0) {
|
|
dev_err(dev, "Cannot get idle pinctrl state %d\n",
|
|
retval);
|
|
goto err_pinctrl_select_suspend;
|
|
}
|
|
}
|
|
|
|
ts_data->suspended = true;
|
|
|
|
return 0;
|
|
|
|
err_pinctrl_select_suspend:
|
|
return retval;
|
|
}
|
|
|
|
static const struct dev_pm_ops it7259_ts_dev_pm_ops = {
|
|
.suspend = it7259_ts_suspend,
|
|
.resume = it7259_ts_resume,
|
|
};
|
|
#else
|
|
static int it7259_ts_resume(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int it7259_ts_suspend(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static const struct i2c_device_id it7259_ts_id[] = {
|
|
{ DEVICE_NAME, 0},
|
|
{}
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(i2c, it7259_ts_id);
|
|
|
|
static const struct of_device_id it7259_match_table[] = {
|
|
{ .compatible = "ite,it7251_ts",},
|
|
{},
|
|
};
|
|
|
|
static struct i2c_driver it7259_ts_driver = {
|
|
.driver = {
|
|
.owner = THIS_MODULE,
|
|
.name = DEVICE_NAME,
|
|
.of_match_table = it7259_match_table,
|
|
#ifdef CONFIG_PM
|
|
.pm = &it7259_ts_dev_pm_ops,
|
|
#endif
|
|
},
|
|
.probe = it7259_ts_probe,
|
|
.remove = it7259_ts_remove,
|
|
.id_table = it7259_ts_id,
|
|
};
|
|
|
|
module_i2c_driver(it7259_ts_driver);
|
|
|
|
MODULE_DESCRIPTION("it7259 Touchscreen Driver");
|
|
MODULE_LICENSE("GPL v2");
|