/*
*
* hyntrion TouchScreen driver.
*
* Copyright (c) 2012-2019, hyntrion Systems, Ltd., all rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************************************************
*
* File Name: hyn_core.c
*
* Author: hyntrion Driver Team
*
* Created: 2016-08-08
*
* Abstract: entrance for hyntrion ts driver
*
* Version: V1.0
*
*****************************************************************************/
/*****************************************************************************
* Included header files
*****************************************************************************/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#if defined(CONFIG_FB)
#include <linux/notifier.h>
#include <linux/fb.h>
#elif defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#define FTS_SUSPEND_LEVEL 1 /* Early-suspend level */
#endif
#include "hyn_core.h"
#include "hyn_common.h"
#include "i2cdev.h"
/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
#define HYN_DRIVER_NAME "hyn_ts"
#define INTERVAL_READ_REG 200 /* unit:ms */
#define TIMEOUT_READ_REG 1000 /* unit:ms */
#if HYN_POWER_SOURCE_CUST_EN
#define HYN_VTG_MIN_UV 2800000
#define HYN_VTG_MAX_UV 3300000
#define HYN_I2C_VTG_MIN_UV 1800000
#define HYN_I2C_VTG_MAX_UV 1800000
#endif
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
struct hyn_ts_data *hyn_data;
extern struct i2c_client *hi_client;
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
#ifdef CONFIG_HAS_EARLYSUSPEND
static int hyn_ts_suspend(struct device *dev);
#endif
static int hyn_ts_resume(struct device *dev);
static int hyn_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen)
{
int ret=0;
mutex_lock(&hyn_data->bus_lock);
ret = hi_i2c_read(*cmd,cmdlen,data,datalen);
mutex_unlock(&hyn_data->bus_lock);
return ret;
}
static int hyn_read_reg(u8 addr, u8 *value)
{
return hyn_read(&addr, 1, value, 1);
}
//#ifdef CONFIG_HAS_EARLYSUSPEND
static int hyn_write(u8 *writebuf, u32 writelen)
{
int ret;
mutex_lock(&hyn_data->bus_lock);
ret = hi_i2c_write(writebuf[0],1,writebuf[1],1);
mutex_unlock(&hyn_data->bus_lock);
return ret;
}
static int hyn_write_reg(u8 addr, u8 value)
{
u8 buf[2] = { 0 };
buf[0] = addr;
buf[1] = value;
return hyn_write(buf, sizeof(buf));
}
//#endif
static int hyn_bus_exit(struct hyn_ts_data *ts_data)
{
HYN_FUNC_ENTER();
HYN_FUNC_EXIT();
return 0;
}
static int hyn_reset_proc(int hdelayms)
{
gpio_direction_output(hyn_data->pdata->reset_gpio,0);
mdelay(20);
gpio_direction_output(hyn_data->pdata->reset_gpio,1);
mdelay(hdelayms);
return 0;
}
/*****************************************************************************
* Name: hyn_wait_tp_to_valid
* Brief: Read chip id until TP FW become valid(Timeout: TIMEOUT_READ_REG),
* need call when reset/power on/resume...
* Input:
* Output:
* Return: return 0 if tp valid, otherwise return error code
*****************************************************************************/
static int hyn_wait_tp_to_valid(void)
{
int ret = 0;
int cnt = 0;
u8 reg_value = 0;
u8 chip_id = hyn_data->ic_info.ids.chip_id;
do {
ret = hyn_read_reg(HYN_REG_CHIP_ID, ®_value);
if ((ret < 0) || (reg_value != chip_id))//
{
HYN_DEBUG("TP Not Ready, ReadData = 0x%x", reg_value);
} else if (reg_value == chip_id) {
HYN_INFO("TP Ready, Device ID = 0x%x", reg_value);
return 0;
}
cnt++;
msleep(INTERVAL_READ_REG);
} while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG);
return ret;
}
/*****************************************************************************
* Name: hyn_tp_state_recovery
* Brief: Need execute this function when reset
* Input:
* Output:
* Return:
*****************************************************************************/
static void hyn_tp_state_recovery(struct hyn_ts_data *ts_data)
{
HYN_FUNC_ENTER();
/* wait tp stable */
hyn_wait_tp_to_valid();
HYN_FUNC_EXIT();
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void hyn_irq_disable(void)
{
unsigned long irqflags;
HYN_FUNC_ENTER();
spin_lock_irqsave(&hyn_data->irq_lock, irqflags);
if (!hyn_data->irq_disabled) {
disable_irq_nosync(hyn_data->irq);
hyn_data->irq_disabled = true;
}
spin_unlock_irqrestore(&hyn_data->irq_lock, irqflags);
HYN_FUNC_EXIT();
}
#endif
static void hyn_irq_enable(void)
{
unsigned long irqflags = 0;
HYN_FUNC_ENTER();
spin_lock_irqsave(&hyn_data->irq_lock, irqflags);
if (hyn_data->irq_disabled) {
enable_irq(hyn_data->irq);
hyn_data->irq_disabled = false;
}
spin_unlock_irqrestore(&hyn_data->irq_lock, irqflags);
HYN_FUNC_EXIT();
}
/*****************************************************************************
* Name: hyn_get_ic_information
* Brief: read chip id to get ic information, after run the function, driver w-
* ill know which IC is it.
* If cant get the ic information, maybe not hyntrion's touch IC, need
* unregister the driver
* Input:
* Output:
* Return: return 0 if get correct ic information, otherwise return error code
*****************************************************************************/
static int hyn_get_ic_information(struct hyn_ts_data *ts_data)
{
int ret = 0;
int cnt = 0;
u8 chip_id[2] = { 0 };
ts_data->ic_info.is_incell = HYN_CHIP_IDC;
ts_data->ic_info.hid_supported = HYN_HID_SUPPORTTED;
do {
ret = hyn_read_reg(HYN_REG_CHIP_ID, &chip_id[0]);
ret |= hyn_read_reg(HYN_REG_FW_VER, &chip_id[1]);
if (ret < 0) {
HYN_DEBUG("i2c read invalid, read:0x%02x%02x",
chip_id[0], chip_id[1]);
} else {
ts_data->ic_info.ids.chip_id = chip_id[0];
ts_data->ic_info.ids.fw_ver = chip_id[1];
break;
}
cnt++;
msleep(INTERVAL_READ_REG);
} while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG);
if ((cnt * INTERVAL_READ_REG) >= TIMEOUT_READ_REG) {
HYN_INFO("read chip_ID fail !!!");
ts_data->ic_info.ids.chip_id = 0xFF;
ts_data->ic_info.ids.fw_ver = 0; //to set low FWver waite behand autoupdata
}
HYN_DEBUG("chip_ID = 0x%02x, FW_ver = 0x%02x",chip_id[0], chip_id[1]);
return 0;
}
#if HYN_FW_UPDATA
#include "capacitive_hynitron_cst8xx_update.h"
extern unsigned char app_bin[];
static unsigned char *p_cst836u_upgrade_firmware;
#define REG_LEN_1B 1
#define REG_LEN_2B 2
static int hctp_write_bytes(u