input: touchscreen: add raydium touch driver
Supports Raydium WT030 controllers.
Change-Id: I7a98769b1e4f410e8f413a2dcc5bbc57e25f88d0
Signed-off-by: gary-rad-ic <gary.wu@rad-ic.com>
Git-commit: b18c8702a86c87acc232f1d535e208228b551883
Git-repo: https://source.codeaurora.org/quic/la/kernel/msm-4.9/commit/?h=gary-rad-ic/CAF
[vvalluru@codeaurora.org: removed LICENSE, README.md and updated commit text]
Signed-off-by: Venkata Prahlad Valluru <vvalluru@codeaurora.org>
diff --git a/drivers/input/touchscreen/raydium_wt030/Makefile b/drivers/input/touchscreen/raydium_wt030/Makefile
new file mode 100644
index 0000000..d97f4550
--- /dev/null
+++ b/drivers/input/touchscreen/raydium_wt030/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the touchscreen raydium drivers.
+#
+obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_driver.o raydium_sysfs.o raydium_fw_update.o
+
+obj-$(CONFIG_TOUCHSCREEN_RM_TS_SELFTEST) += drv_interface.o raydium_selftest.o chip_raydium/ic_drv_global.o chip_raydium/ic_drv_interface.o drv_interface.o chip_raydium/f302_ic_control.o chip_raydium/f302_ic_test.o
diff --git a/drivers/input/touchscreen/raydium_wt030/raydium_driver.c b/drivers/input/touchscreen/raydium_wt030/raydium_driver.c
new file mode 100644
index 0000000..d040ae2
--- /dev/null
+++ b/drivers/input/touchscreen/raydium_wt030/raydium_driver.c
@@ -0,0 +1,2292 @@
+/* drivers/input/touchscreen/raydium_wt030/raydium_driver.c
+ *
+ * Raydium TouchScreen driver.
+ *
+ * Copyright (c) 2010 Raydium tech Ltd.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/unistd.h>
+#include <linux/uaccess.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/device.h>
+#include <linux/kprobes.h>
+#include <asm/traps.h>
+#include <linux/firmware.h>
+#include <linux/of_gpio.h>
+#include "raydium_driver.h"
+
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif /*end of CONFIG_FB*/
+
+struct raydium_slot_status {
+ unsigned char pt_id; /*Occupied point ID*/
+ unsigned char need_update; /*Mark as info need to be updated*/
+ unsigned char pt_report_offset; /*point info offset in report*/
+};
+/*The first 3 elements are currently occupied. therest is new coming points*/
+struct raydium_slot_status gst_slot[MAX_TOUCH_NUM * 2];
+struct raydium_slot_status gst_slot_init = {0xFF, 0, 0};
+
+#if (defined(CONFIG_RM_SYSFS_DEBUG))
+const struct attribute_group raydium_attr_group;
+#endif /*end of CONFIG_RM_SYSFS_DEBUG*/
+
+unsigned char g_u8_addr;
+unsigned char g_u8_raydium_flag;
+unsigned char g_u8_i2c_mode;
+unsigned char g_u8_upgrade_type;
+unsigned char g_u8_raw_data_type;
+unsigned int g_u32_raw_data_len; /* 72 bytes*/
+unsigned long g_u32_addr;
+unsigned int g_u32_length;
+unsigned int g_u32_driver_version;
+unsigned char *g_rad_fw_image, *g_rad_init_image;
+unsigned char *g_rad_boot_image, *g_rad_para_image;
+unsigned char *g_rad_testfw_image, *g_rad_testpara_image;
+unsigned char g_u8_table_setting, g_u8_table_init;
+unsigned char g_u8_resetflag;
+#ifdef ESD_SOLUTION_EN
+unsigned char g_u8_checkflag;
+#endif
+#ifdef ENABLE_DUMP_DATA
+unsigned char g_u8_dumpcount;
+unsigned char g_u8_dump_flag;
+unsigned char g_u8_palm_flag;
+unsigned long timeout;
+#endif
+struct raydium_ts_data *g_raydium_ts;
+/*******************************************************************************
+* Name: raydium_variable_init
+* Brief:
+* Input:
+* Output:
+* Return:
+*******************************************************************************/
+static void raydium_variable_init(void)
+{
+ g_u8_addr = RAYDIUM_PDA2_PDA_CFG_ADDR;
+ g_u8_raydium_flag = 0;
+ g_u8_i2c_mode = PDA2_MODE;
+ g_u8_upgrade_type = 0;
+ g_u8_raw_data_type = RAYDIUM_FT_UPDATE;
+ g_u32_raw_data_len = 36 * 2; /* 72 bytes*/
+ g_u32_addr = RAD_CHK_I2C_CMD;
+ g_u32_length = 1;
+ g_u8_table_setting = 0;
+ g_u8_table_init = 0;
+ g_rad_fw_image = NULL;
+ g_rad_init_image = NULL;
+ g_rad_boot_image = NULL;
+ g_rad_para_image = NULL;
+ g_rad_testfw_image = NULL;
+ g_rad_testpara_image = NULL;
+ g_u32_driver_version = ((RAD_MAIN_VERSION << 24) |
+ (RAD_MINOR_VERSION << 16) |
+ (RAD_CUSTOMER_VERSION));
+ g_u8_resetflag = false;
+#ifdef ESD_SOLUTION_EN
+ g_u8_checkflag = false;
+#endif
+#ifdef ENABLE_DUMP_DATA
+ g_u8_dumpcount = 0;
+ g_u8_dump_flag = false;
+ g_u8_palm_flag = false;
+#endif
+}
+
+
+/*******************************************************************************
+* Name: raydium_gpio_configure
+* Brief:
+* Input:
+* Output:
+* Return:
+*******************************************************************************/
+
+static int raydium_gpio_configure(bool on)
+{
+ int i32_err = 0;
+
+ if (on) {
+ if (gpio_is_valid(g_raydium_ts->irq_gpio)) {
+ i32_err = gpio_request(g_raydium_ts->irq_gpio,
+ "raydium_irq_gpio");
+ if (i32_err) {
+ dev_err(&g_raydium_ts->client->dev,
+ "[touch]irq gpio request failed");
+ goto err_irq_gpio_req;
+ }
+
+ i32_err = gpio_direction_input(g_raydium_ts->irq_gpio);
+ if (i32_err) {
+ dev_err(&g_raydium_ts->client->dev,
+ "[touch]set_direction for irq gpio failed\n");
+ goto err_irq_gpio_dir;
+ }
+ }
+ if (gpio_is_valid(g_raydium_ts->rst_gpio)) {
+ i32_err = gpio_request(g_raydium_ts->rst_gpio,
+ "raydium_rst_gpio");
+ if (i32_err) {
+ dev_err(&g_raydium_ts->client->dev,
+ "[touch]rst gpio request failed");
+ goto err_irq_gpio_req;
+ }
+
+ i32_err = gpio_direction_output(g_raydium_ts->rst_gpio, 1);
+ if (i32_err) {
+ dev_err(&g_raydium_ts->client->dev,
+ "[touch]set_direction for irq gpio failed\n");
+ goto err_rst_gpio_dir;
+ }
+ }
+ } else {
+ if (gpio_is_valid(g_raydium_ts->irq_gpio))
+ gpio_free(g_raydium_ts->irq_gpio);
+ }
+ return 0;
+err_rst_gpio_dir:
+ if (gpio_is_valid(g_raydium_ts->rst_gpio))
+ gpio_free(g_raydium_ts->rst_gpio);
+ return i32_err;
+err_irq_gpio_dir:
+ if (gpio_is_valid(g_raydium_ts->irq_gpio))
+ gpio_free(g_raydium_ts->irq_gpio);
+err_irq_gpio_req:
+ return i32_err;
+}
+
+/*******************************************************************************
+* Name: raydium_ts_pinctrl_init
+* Brief:
+* Input:
+* Output:
+* Return:
+*******************************************************************************/
+#ifdef MSM_NEW_VER
+static int raydium_ts_pinctrl_init(void)
+{
+ int i32_ret;
+
+ /* Get pinctrl if target uses pinctrl */
+ g_raydium_ts->ts_pinctrl = devm_pinctrl_get(&(g_raydium_ts->client->dev));
+ if (IS_ERR_OR_NULL(g_raydium_ts->ts_pinctrl)) {
+ i32_ret = PTR_ERR(g_raydium_ts->ts_pinctrl);
+ pr_err("[touch]target does not use pinctrl %d\n", i32_ret);
+ goto err_pinctrl_get;
+ }
+
+ g_raydium_ts->pinctrl_state_active
+ = pinctrl_lookup_state(g_raydium_ts->ts_pinctrl, PINCTRL_STATE_ACTIVE);
+ if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_active)) {
+ i32_ret = PTR_ERR(g_raydium_ts->pinctrl_state_active);
+ pr_err("[touch]Can not lookup %s pinstate %d\n",
+ PINCTRL_STATE_ACTIVE, i32_ret);
+ goto err_pinctrl_lookup;
+ }
+
+ g_raydium_ts->pinctrl_state_suspend
+ = pinctrl_lookup_state(g_raydium_ts->ts_pinctrl,
+ PINCTRL_STATE_SUSPEND);
+ if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_suspend)) {
+ i32_ret = PTR_ERR(g_raydium_ts->pinctrl_state_suspend);
+ pr_err("[touch]Can not lookup %s pinstate %d\n",
+ PINCTRL_STATE_SUSPEND, i32_ret);
+ goto err_pinctrl_lookup;
+ }
+
+ g_raydium_ts->pinctrl_state_release
+ = pinctrl_lookup_state(g_raydium_ts->ts_pinctrl,
+ PINCTRL_STATE_RELEASE);
+ if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_release)) {
+ i32_ret = PTR_ERR(g_raydium_ts->pinctrl_state_release);
+ pr_err("[touch]Can not lookup %s pinstate %d\n",
+ PINCTRL_STATE_RELEASE, i32_ret);
+ }
+
+ return 0;
+
+err_pinctrl_lookup:
+ devm_pinctrl_put(g_raydium_ts->ts_pinctrl);
+err_pinctrl_get:
+ g_raydium_ts->ts_pinctrl = NULL;
+ return i32_ret;
+}
+#endif/*end of MSM_NEW_VER*/
+#ifdef ESD_SOLUTION_EN
+static int raydium_hw_reset_fun(struct i2c_client *client)
+{
+ int i32_ret = SUCCESS;
+
+ pr_info("[touch]HW reset\n");
+ if ((g_u8_raydium_flag & ENG_MODE) == 0)
+ raydium_irq_control(DISABLE);
+
+ g_u8_resetflag = true;
+ /*HW reset*/
+ gpio_set_value(g_raydium_ts->rst_gpio, 1);
+ gpio_set_value(g_raydium_ts->rst_gpio, 0);
+ msleep(RAYDIUM_RESET_INTERVAL_MSEC);
+ gpio_set_value(g_raydium_ts->rst_gpio, 1);
+
+ g_u8_i2c_mode = PDA2_MODE;
+
+ i32_ret = wait_irq_state(client, 300, 2000);
+ if (i32_ret != ERROR) {
+ msleep(25);
+ }
+
+ if ((g_u8_raydium_flag & ENG_MODE) == 0)
+ raydium_irq_control(ENABLE);
+
+ pr_info("[touch]Raydium HW reset : %d\n", i32_ret);
+ return i32_ret;
+}
+#endif
+int raydium_i2c_pda_set_address(unsigned int u32_address,
+ unsigned char u8_mode)
+{
+ int i32_ret = 0;
+ unsigned char u8_retry;
+ unsigned char u8_buf[RAD_I2C_PDA_ADDRESS_LENGTH];
+ struct i2c_client *client = g_raydium_ts->client;
+
+ client->addr = RAYDIUM_I2C_EID;
+ u8_buf[0] = (u32_address & 0x0000FF00) >> 8;
+ u8_buf[1] = (u32_address & 0x00FF0000) >> 16;
+ u8_buf[2] = (u32_address & 0xFF000000) >> 24;
+ u8_buf[3] = u8_mode;
+
+ for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
+ i32_ret = i2c_master_send(client, u8_buf,
+ RAD_I2C_PDA_ADDRESS_LENGTH);
+ if (i32_ret != RAD_I2C_PDA_ADDRESS_LENGTH) {
+ pr_err("[touch]%s: I2C retry %d\n",
+ __func__, u8_retry + 1);
+ usleep_range(500, 1500);
+ } else {
+ break;
+ }
+ }
+
+ return (i32_ret == RAD_I2C_PDA_ADDRESS_LENGTH) ? i32_ret : -EIO;
+}
+
+/*device attribute raydium_i2c_pda2_mode used*/
+int raydium_i2c_pda_read(struct i2c_client *client,
+ unsigned int u32_addr, unsigned char *u8_r_data,
+ unsigned short u16_length)
+{
+ int i32_ret;
+ unsigned char u8_retry;
+ unsigned char u8_mode = 0x00;
+ unsigned char u8_buf;
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = RAYDIUM_I2C_NID,
+ .flags = RAYDIUM_I2C_WRITE,
+ .len = 1,
+ .buf = &u8_buf,
+ },
+ {
+ .addr = RAYDIUM_I2C_NID,
+ .flags = RAYDIUM_I2C_READ,
+ .len = u16_length,
+ .buf = u8_r_data,
+ },
+ };
+
+ if (u16_length == 4)
+ u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
+ RAD_I2C_PDA_2_MODE_DISABLE |
+ RAD_I2C_PDA_MODE_WORD_MODE;
+ else
+ u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
+ RAD_I2C_PDA_2_MODE_DISABLE;
+
+ u8_mode |= 0x03;
+
+ u8_buf = u32_addr & MASK_8BIT;
+
+ i32_ret = raydium_i2c_pda_set_address(u32_addr, u8_mode);
+ if (i32_ret != RAD_I2C_PDA_ADDRESS_LENGTH)
+ goto exit;
+ usleep_range(50, 80);
+
+ for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
+ if (i2c_transfer(g_raydium_ts->client->adapter, msg, 2) == 2) {
+ i32_ret = u16_length;
+ break;
+ }
+ pr_err("%s: I2C retry %d\n", __func__, u8_retry + 1);
+ usleep_range(500, 1500);
+ }
+
+ if (u8_retry == SYN_I2C_RETRY_TIMES) {
+ pr_err("%s: I2C read over retry limit\n", __func__);
+ i32_ret = -EIO;
+ }
+exit:
+ return i32_ret;
+}
+
+int raydium_i2c_pda_write(struct i2c_client *client,
+ unsigned int u32_addr, unsigned char *u8_w_data,
+ unsigned short u16_length)
+{
+ int i32_ret;
+ unsigned char u8_retry;
+ unsigned char u8_mode = 0x00;
+ unsigned char u8_buf[MAX_WRITE_PACKET_SIZE + 1];
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = RAYDIUM_I2C_NID,
+ .flags = RAYDIUM_I2C_WRITE,
+ .len = u16_length + 1,
+ .buf = u8_buf,
+ },
+ };
+
+ if (u16_length > MAX_WRITE_PACKET_SIZE)
+ return -EINVAL;
+
+ if (u16_length == 4)
+ u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
+ RAD_I2C_PDA_2_MODE_DISABLE |
+ RAD_I2C_PDA_MODE_WORD_MODE;
+ else
+ u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
+ RAD_I2C_PDA_2_MODE_DISABLE;
+
+ u8_buf[0] = u32_addr & MASK_8BIT;
+ memcpy(&u8_buf[1], u8_w_data, u16_length);
+
+ i32_ret = raydium_i2c_pda_set_address(u32_addr, u8_mode);
+ if (i32_ret != RAD_I2C_PDA_ADDRESS_LENGTH)
+ goto exit;
+ //usleep_range(50, 80);
+
+ for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
+ if (i2c_transfer(client->adapter, msg, 1) == 1) {
+ i32_ret = u16_length;
+ break;
+ }
+ pr_err("[touch]%s: I2C retry %d\n", __func__, u8_retry + 1);
+ usleep_range(500, 1500);
+ }
+
+ if (u8_retry == SYN_I2C_RETRY_TIMES) {
+ pr_err("[touch]%s: I2C write over retry limit\n", __func__);
+ i32_ret = -EIO;
+ }
+exit:
+ return i32_ret;
+}
+
+int raydium_i2c_pda2_set_page(struct i2c_client *client,
+ unsigned int is_suspend,
+ unsigned char u8_page)
+{
+ int i32_ret = -1;
+ unsigned char u8_retry;
+ unsigned int u8_ret = (is_suspend) ? 10 : 2;
+ unsigned char u8_buf[RAYDIUM_I2C_PDA2_PAGE_LENGTH];
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = RAYDIUM_I2C_NID,
+ .flags = RAYDIUM_I2C_WRITE,
+ .len = RAYDIUM_I2C_PDA2_PAGE_LENGTH,
+ .buf = u8_buf,
+ },
+ };
+
+ u8_buf[0] = RAYDIUM_PDA2_PAGE_ADDR;
+ u8_buf[1] = u8_page;
+ for (; u8_ret > 0; u8_ret--) {
+ for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
+ if (i2c_transfer(client->adapter, msg, 1) == 1) {
+ i32_ret = RAYDIUM_I2C_PDA2_PAGE_LENGTH;
+ break;
+ }
+ usleep_range(500, 1500);
+ }
+ if (i32_ret == RAYDIUM_I2C_PDA2_PAGE_LENGTH)
+ break;
+ usleep_range(2000, 5000);
+ }
+
+ if (0 == u8_ret) {
+ pr_err("[touch]%s: I2C write over retry limit\n", __func__);
+ i32_ret = -EIO;
+ }
+
+ return i32_ret;
+}
+
+int raydium_i2c_pda2_read(struct i2c_client *client,
+ unsigned char u8_addr,
+ unsigned char *u8_r_data,
+ unsigned short u16_length)
+{
+ int i32_ret = -1;
+ unsigned char u8_retry;
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = RAYDIUM_I2C_NID,
+ .flags = RAYDIUM_I2C_WRITE,
+ .len = 1,
+ .buf = &u8_addr,
+ },
+ {
+ .addr = RAYDIUM_I2C_NID,
+ .flags = RAYDIUM_I2C_READ,
+ .len = u16_length,
+ .buf = u8_r_data,
+ },
+ };
+ g_u8_i2c_mode = PDA2_MODE;
+ for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
+ if (i2c_transfer(g_raydium_ts->client->adapter, msg, 2) == 2) {
+ i32_ret = u16_length;
+ break;
+ }
+ usleep_range(500, 1500);
+ }
+
+ if (u8_retry == SYN_I2C_RETRY_TIMES) {
+ pr_err("[touch]%s: I2C read over retry limit\n", __func__);
+ i32_ret = -EIO;
+ }
+
+ return i32_ret;
+}
+
+int raydium_i2c_pda2_write(struct i2c_client *client,
+ unsigned char u8_addr,
+ unsigned char *u8_w_data,
+ unsigned short u16_length)
+{
+ int i32_ret = -1;
+ unsigned char u8_retry;
+ unsigned char u8_buf[MAX_WRITE_PACKET_SIZE + 1];
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = RAYDIUM_I2C_NID,
+ .flags = RAYDIUM_I2C_WRITE,
+ .len = u16_length + 1,
+ .buf = u8_buf,
+ },
+ };
+
+ if (u16_length > MAX_WRITE_PACKET_SIZE)
+ return -EINVAL;
+ g_u8_i2c_mode = PDA2_MODE;
+ u8_buf[0] = u8_addr;
+ memcpy(&u8_buf[1], u8_w_data, u16_length);
+
+ for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
+ if (i2c_transfer(client->adapter, msg, 1) == 1) {
+ i32_ret = u16_length;
+ break;
+ }
+ usleep_range(500, 1500);
+ }
+
+ if (u8_retry == SYN_I2C_RETRY_TIMES) {
+ pr_err("[touch]%s: I2C write over retry limit\n", __func__);
+ i32_ret = -EIO;
+ }
+
+ return i32_ret;
+}
+
+void raydium_irq_control(bool enable)
+{
+ if (enable) {
+ if (g_raydium_ts->irq_enabled) {
+ /*mutex_unlock(&ts->lock);*/
+ dev_info(&g_raydium_ts->client->dev,
+ "[touch]Already enable irq\n");
+ return;
+ }
+
+ /* Clear interrupts first */
+ if (g_raydium_ts->blank != FB_BLANK_POWERDOWN) {
+ if (g_u8_i2c_mode == PDA2_MODE) {
+ mutex_lock(&g_raydium_ts->lock);
+ if (raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0) < 0)
+ pr_err("[touch]set page fail%s\n",
+ __func__);
+ mutex_unlock(&g_raydium_ts->lock);
+ usleep_range(500, 1500);
+ }
+ }
+ while (g_raydium_ts->irq_desc->depth > 0) {
+ pr_info("[touch]irq enable\n");
+ g_raydium_ts->irq_enabled = true;
+ enable_irq(g_raydium_ts->irq);
+ }
+ } else {
+ if (g_raydium_ts->irq_enabled) {
+ if (g_raydium_ts->irq_desc->depth == 0) {
+ disable_irq(g_raydium_ts->irq);
+ g_raydium_ts->irq_enabled = false;
+ pr_info("[touch]irq disable\n");
+ }
+ }
+ }
+}
+
+#ifdef CONFIG_RM_SYSFS_DEBUG
+
+int raydium_i2c_mode_control(struct i2c_client *client,
+ unsigned char u8_mode)
+{
+ unsigned char u8_buf[4];
+
+ switch (u8_mode) {
+ case 0: /* Disable INT flag */
+ pr_info("[touch]RAD INT flag : %d\n", g_raydium_ts->irq_enabled);
+ disable_irq(g_raydium_ts->irq);
+ g_raydium_ts->irq_enabled = false;
+ pr_info("[touch]RAD irq disable\n");
+ break;
+ case 1: /* Enable INT flag */
+ pr_info("[touch]RAD INT flag : %d\n", g_raydium_ts->irq_enabled);
+ enable_irq(g_raydium_ts->irq);
+ g_raydium_ts->irq_enabled = true;
+ pr_info("[touch]RAD irq enable\n");
+ break;
+ case 2: /* Disable INT by raydium_irq_control */
+ raydium_irq_control(DISABLE);
+ break;
+ case 3: /* Enable INT by raydium_irq_control */
+ raydium_irq_control(ENABLE);
+ break;
+ case 4: /* Show RAD INT depth */
+ pr_info("[touch]RAD INT depth : %d\n", g_raydium_ts->irq_desc->depth);
+ break;
+ case 7:
+ raydium_i2c_pda2_set_page(client,
+ g_raydium_ts->is_suspend , RAYDIUM_PDA2_2_PDA);
+ g_u8_i2c_mode = PDA_MODE;
+ pr_info("[touch]Disable PDA2_MODE\n");
+ break;
+ case 8:
+ raydium_i2c_pda_read(client, RAD_PDA2_CTRL_CMD, u8_buf, 4);
+ u8_buf[0] |= RAD_ENABLE_PDA2 | RAD_ENABLE_SI2;
+ raydium_i2c_pda_write(client, RAD_PDA2_CTRL_CMD, u8_buf, 4);
+ raydium_i2c_pda_set_address(0x50000628, DISABLE);
+
+ g_u8_i2c_mode = PDA2_MODE;
+ pr_info("[touch]Enable PDA2_MODE\n");
+ break;
+ }
+ return 0;
+}
+
+
+const struct attribute_group raydium_attr_group = {
+ .attrs = raydium_attributes
+};
+
+/*create sysfs for debug update firmware*/
+static int raydium_create_sysfs(struct i2c_client *client)
+{
+ int ret = -1;
+
+ ret = sysfs_create_group(&(client->dev.kobj), &raydium_attr_group);
+ if (ret) {
+ pr_err("[touch]failed to register sysfs\n");
+ sysfs_remove_group(&client->dev.kobj, &raydium_attr_group);
+ ret = -EIO;
+ } else {
+ pr_info("[touch]create raydium sysfs attr_group successful\n");
+ }
+ return ret;
+}
+
+static void raydium_release_sysfs(struct i2c_client *client)
+{
+ sysfs_remove_group(&client->dev.kobj, &raydium_attr_group);
+}
+#endif /*end of CONFIG_RM_SYSFS_DEBUG*/
+
+#ifdef ESD_SOLUTION_EN
+int raydium_esd_check(void)
+{
+ int i32_ret = 0;
+ unsigned char u8_esd_status[MAX_TCH_STATUS_PACKET_SIZE];
+ unsigned char u8_w_data[4];
+
+ mutex_lock(&g_raydium_ts->lock);
+ if (g_u8_i2c_mode == PDA2_MODE) {
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit;
+ /*read esd status*/
+ i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
+ RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR,
+ u8_esd_status, MAX_TCH_STATUS_PACKET_SIZE);
+ if (i32_ret < 0) {
+ pr_err("[touch]%s: failed to read data: %d\n",
+ __func__, __LINE__);
+ goto exit;
+ }
+
+ if (u8_esd_status[POS_FW_STATE] != 0x1A &&
+ u8_esd_status[POS_FW_STATE] != 0xAA) {
+ if (g_u8_resetflag == true) {
+ pr_err("[touch]%s -> filter abnormal irq\n"
+ , __func__);
+ goto exit;
+ }
+ pr_err("[touch]%s -> abnormal irq, FW state = 0x%x\n",
+ __func__, u8_esd_status[POS_FW_STATE]);
+ g_u8_resetflag = false;
+ i32_ret = -1;
+ goto exit;
+
+ }
+ u8_w_data[POS_SEQ] = 0;
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR,
+ u8_w_data, 1);
+ if (i32_ret < 0) {
+ pr_err("[touch]%s: failed to clear seq: %d\n",
+ __func__, __LINE__);
+ goto exit;
+ }
+ g_u8_resetflag = false;
+ }
+exit:
+ mutex_unlock(&g_raydium_ts->lock);
+ pr_info("[touch] raydium_esd_check\n");
+ return i32_ret;
+}
+#endif
+
+
+#ifdef ENABLE_DUMP_DATA
+int raydium_dump_data(unsigned char u8_frame, unsigned char u8_type)
+{
+ unsigned char u8_rbuffer[MAX_READ_PACKET_SIZE*2];
+ short i16_data_buffer[MAX_READ_PACKET_SIZE*2];
+ unsigned char u8_w_data[RAYDIUM_FT_CMD_LENGTH];
+ unsigned int u32_target_addr;
+ unsigned int u32_offset;
+ unsigned short u16_read_length;
+ int i32_ret = -1;
+ int i32_retry = 0;
+ unsigned char u8_i, u8_j, u8_k;
+ char write_string[1000];
+
+ pr_info("[touch] %s -> type:%d\n", __func__, u8_type);
+
+ for (u8_i = 0; u8_i < u8_frame; u8_i++) {
+
+ u8_w_data[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP;
+ u8_w_data[RAD_FT_CMD_POS] = u8_type;
+
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_w_data, RAYDIUM_FT_CMD_LENGTH);
+
+ memset(u8_rbuffer, 0x00, MAX_READ_PACKET_SIZE*2);
+ /* make sure update flag was set*/
+ for (i32_retry = 0; i32_retry < 5; i32_retry++) {
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_rbuffer,
+ RAYDIUM_FT_CMD_LENGTH);
+ if (i32_ret < 0)
+ goto exit_flag_error;
+
+ if ((u8_rbuffer[RAD_FT_CMD_POS] & RAYDIUM_FT_UPDATE) ==
+ RAYDIUM_FT_UPDATE)
+ break;
+
+ usleep_range(4500, 5500);
+ }
+
+ if (i32_retry == 5) {
+ i32_ret = -EAGAIN;
+ pr_info("[touch] %s -> flag timeout\n", __func__);
+ }
+
+ u32_offset = 0;
+ u16_read_length = 0;
+#if DATA_MAP_5_5
+ g_u32_raw_data_len = 0x32;
+#else
+ g_u32_raw_data_len = 0x48;
+#endif
+ while (u32_offset < g_u32_raw_data_len) {
+ u16_read_length = g_u32_raw_data_len;
+
+ u32_target_addr = RAD_READ_FT_DATA_CMD + u32_offset;
+
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ *(unsigned int *)u8_rbuffer =
+ (RAD_I2C_PDA_MODE_ENABLE << 24)
+ | ((u32_target_addr & (~MASK_8BIT)) >> 8);
+
+ /*using byte mode to read 4 bytes*/
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_PDA_CFG_ADDR,
+ u8_rbuffer, 4);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_ENABLE_PDA);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
+ (unsigned char)(u32_target_addr & MASK_8BIT),
+ u8_rbuffer,
+ u16_read_length);
+
+ if (i32_ret < 0)
+ goto exit_flag_error;
+
+ memcpy((i16_data_buffer + u32_offset),
+ u8_rbuffer,
+ u16_read_length);
+
+ u32_offset += u16_read_length;
+ }
+ pr_info("[touch] frame%d\n", u8_i);
+#if DATA_MAP_5_5
+ for (u8_j = 0; u8_j < 25; u8_j += 5) {
+ pr_info("[touch] %4d, %4d, %4d, %4d, %4d\r\n",
+ i16_data_buffer[u8_j], i16_data_buffer[u8_j+1],
+ i16_data_buffer[u8_j+2], i16_data_buffer[u8_j+3],
+ i16_data_buffer[u8_j+4]);
+ }
+#else
+ for (u8_j = 0; u8_j < 36; u8_j += 6) {
+ pr_info("[touch] %4d, %4d, %4d, %4d, %4d, %4d\r\n",
+ i16_data_buffer[u8_j], i16_data_buffer[u8_j+1],
+ i16_data_buffer[u8_j+2], i16_data_buffer[u8_j+3],
+ i16_data_buffer[u8_j+4], i16_data_buffer[u8_j+5]);
+ }
+#endif
+ /* clear update flag to get next one*/
+ u8_rbuffer[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP;
+ u8_rbuffer[RAD_FT_CMD_POS] = u8_type;
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_rbuffer, RAYDIUM_FT_CMD_LENGTH);
+ if (i32_ret < 0)
+ goto exit_flag_error;
+
+ }
+ return 0;
+exit_i2c_error:
+ pr_info("%s exit_i2c_error return %d\r\n", __func__, i32_ret);
+exit_flag_error:
+ return i32_ret;
+}
+
+static void raydium_dump_data_work(struct work_struct *work)
+{
+
+ int i32_ret = 0;
+ unsigned char u8_data_type;
+ unsigned char u8_w_data[RAYDIUM_FT_CMD_LENGTH];
+
+ /* set mode */
+ memset(u8_w_data, 0x00, RAYDIUM_FT_CMD_LENGTH);
+ pr_info("[touch] raydium_dump_data_work\n");
+
+ disable_irq_nosync(g_raydium_ts->irq);
+ g_raydium_ts->irq_enabled = false;
+
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ u8_w_data[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_FT_MODE;
+
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_w_data, 1);
+ if (i32_ret < 0)
+ goto exit_error;
+ pr_info("[touch] RAYDIUM_HOST_CMD_FT_MODE\n");
+
+ /*baseline*/
+ u8_data_type = 0x02;
+ raydium_dump_data(1, u8_data_type);
+ u8_data_type = 0x04;
+ raydium_dump_data(1, u8_data_type);
+ u8_data_type = 0x10;
+ raydium_dump_data(10, u8_data_type);
+
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_error;
+ u8_w_data[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_TP_MODE;
+
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_w_data, 1);
+
+ u8_w_data[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP;
+ u8_w_data[RAD_FT_CMD_POS] = 0;
+
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_w_data, RAD_FT_CMD_LENGTH);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ enable_irq(g_raydium_ts->irq);
+ g_raydium_ts->irq_enabled = true;
+exit_error:
+ return;
+}
+
+#endif
+#ifdef FILTER_POINTS
+int raydium_pointer_filter(int i32_index,
+ unsigned short u16_diff_x,
+ unsigned short u16_diff_y)
+{
+ if (abs(ts->x_pos[i32_index] - ts->last_x_pos[i32_index]) > u16_diff_x)
+ return 0;
+ if (abs(ts->y_pos[i32_index] - ts->last_y_pos[i32_index]) > u16_diff_y)
+ return 0;
+
+ return 1;
+}
+#endif
+
+#ifdef HOST_NOTIFY_EN
+int raydium_notify_function(unsigned short u16_display_mode)
+{
+ int i32_ret = 0;
+ unsigned char u8_rbuffer[4];
+
+ mutex_lock(&g_raydium_ts->lock);
+ if (g_u8_i2c_mode == PDA2_MODE) {
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit;
+ memset(u8_rbuffer, 0,sizeof(u8_rbuffer));
+
+ u8_rbuffer[0] = RAYDIUM_HOST_CMD_DISPLAY_MODE;
+ u8_rbuffer[2] = (unsigned char) (u16_display_mode & 0x00ff);
+ u8_rbuffer[3] = (unsigned char) ((u16_display_mode & 0xff00) >> 8);
+ pr_info("[touch] display mode %d %d %d\r\n",u16_display_mode,u8_rbuffer[2],u8_rbuffer[3]);
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_rbuffer, 4);
+ }
+exit:
+ mutex_unlock(&g_raydium_ts->lock);
+ pr_info("[touch] raydium_notify_function\n");
+ return i32_ret;
+}
+#endif
+static int raydium_touch_report(unsigned char *p_u8_buf,
+ unsigned char u8_points_amount)
+{
+ unsigned char u8_i, u8_j, u8_offset = 0, u8_pt_id;
+ signed short i16_wx, i16_wy;
+ /* number of touch points */
+ unsigned char u8_touch_count = 0;
+ DECLARE_BITMAP(ids, g_raydium_ts->u8_max_touchs);
+
+ bitmap_zero(ids, g_raydium_ts->u8_max_touchs);
+
+ for (u8_i = 0; u8_i < (g_raydium_ts->u8_max_touchs * 2); u8_i++) {
+ gst_slot[u8_i].need_update = 0;
+ gst_slot[u8_i].pt_report_offset = 0;
+ }
+
+ /*Check incoming point info*/
+ for (u8_i = 0; u8_i < u8_points_amount; u8_i++) {
+ u8_pt_id = p_u8_buf[POS_PT_ID + u8_i * LEN_PT];
+ /* Current*/
+ for (u8_j = 0; u8_j < g_raydium_ts->u8_max_touchs; u8_j++) {
+ if (u8_pt_id == gst_slot[u8_j].pt_id) {
+ gst_slot[u8_j].need_update = 1;
+ gst_slot[u8_j].pt_report_offset = u8_i;
+ break;
+ }
+ }
+ /* New coming*/
+ if (u8_j == g_raydium_ts->u8_max_touchs) {
+ for (u8_j = g_raydium_ts->u8_max_touchs;
+ u8_j < (g_raydium_ts->u8_max_touchs * 2); u8_j++) {
+ if (!gst_slot[u8_j].need_update) {
+ gst_slot[u8_j].pt_id = u8_pt_id;
+ gst_slot[u8_j].need_update = 1;
+ gst_slot[u8_j].pt_report_offset = u8_i;
+ pr_info("[touch]x:%d,y:%d\n",
+ p_u8_buf[POS_X_L + u8_offset] |
+ p_u8_buf[POS_X_H + u8_offset] << 8,
+ p_u8_buf[POS_Y_L + u8_offset] |
+ p_u8_buf[POS_Y_H + u8_offset] << 8);
+ break;
+ }
+ }
+ }
+ }
+
+ /*Release slot with non-occupied point*/
+ for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
+ if (!gst_slot[u8_i].need_update) {
+ input_mt_slot(g_raydium_ts->input_dev, u8_i);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, false);
+ gst_slot[u8_i].pt_id = 0xFF;
+ gst_slot[u8_i].pt_report_offset = 0;
+ gst_slot[u8_i].need_update = 0;
+ }
+ }
+ /*Assign new one to non-occupied slot*/
+ for (u8_i = g_raydium_ts->u8_max_touchs;
+ u8_i < (g_raydium_ts->u8_max_touchs * 2); u8_i++) {
+ if (gst_slot[u8_i].need_update) {
+ for (u8_j = 0; u8_j < g_raydium_ts->u8_max_touchs; u8_j++) {
+ if (!gst_slot[u8_j].need_update) {
+ gst_slot[u8_j] = gst_slot[u8_i];
+ gst_slot[u8_i] = gst_slot_init;
+ break;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+#ifdef FILTER_POINTS
+ for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
+ if (gst_slot[u8_i].need_update) {
+ u8_offset = gst_slot[u8_i].pt_report_offset * LEN_PT;
+ g_raydium_ts->x_pos[i] = p_u8_buf[POS_X_L + u8_offset] |
+ p_u8_buf[POS_X_H + u8_offset] << BYTE_SHIFT;
+ g_raydium_ts->y_pos[i] = p_u8_buf[POS_Y_L + u8_offset] |
+ p_u8_buf[POS_Y_H + u8_offset] << BYTE_SHIFT;
+ g_raydium_ts->pressure = p_u8_buf[POS_PRESSURE_L + u8_offset] |
+ p_u8_buf[POS_PRESSURE_H + u8_offset] << BYTE_SHIFT;
+ i16_wx = p_u8_buf[POS_WX_L + u8_offset] |
+ p_u8_buf[POS_WX_H + u8_offset] << BYTE_SHIFT;
+ i16_wy = p_u8_buf[POS_WY_L + u8_offset] |
+ p_u8_buf[POS_WY_H + u8_offset] << BYTE_SHIFT;
+
+ if (!raydium_pointer_filter(g_raydium_ts, u8_i, DELTA_X, DELTA_Y)) {
+ input_mt_slot(g_raydium_ts->input_dev, u8_i);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, true);
+ __set_bit(i, ids);
+
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_POSITION_X, g_raydium_ts->x_pos[u8_i]);
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_POSITION_Y, g_raydium_ts->y_pos[u8_i]);
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_PRESSURE, g_raydium_ts->pressure);
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_TOUCH_MAJOR, max(i16_wx, i16_wy));
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_TOUCH_MINOR, min(i16_wx, i16_wy));
+ input_report_key(g_raydium_ts->input_dev,
+ BTN_TOUCH, 1);
+ input_report_key(g_raydium_ts->input_dev,
+ BTN_TOOL_FINGER, 1);
+ input_sync(g_raydium_ts->input_dev);
+ g_raydium_ts->last_x_pos[u8_i] = g_raydium_ts->x_pos[u8_i];
+ g_raydium_ts->last_y_pos[u8_i] = g_raydium_ts->y_pos[u8_i];
+ } else {
+ g_raydium_ts->x_pos[u8_i] = g_raydium_ts->last_x_pos[u8_i];
+ g_raydium_ts->y_pos[u8_i] = g_raydium_ts->last_y_pos[u8_i];
+ }
+ }
+ }
+
+ if ((gst_slot[0].need_update == 0) &&
+ (gst_slot[1].need_update == 0)) {
+ for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
+ if (test_bit(u8_i, ids))
+ continue;
+ input_mt_slot(g_raydium_ts->input_dev, u8_i);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, false);
+ }
+ input_report_key(g_raydium_ts->input_dev, BTN_TOUCH, 0);
+ input_report_key(g_raydium_ts->input_dev, BTN_TOOL_FINGER, 0);
+ input_sync(g_raydium_ts->input_dev);
+ }
+#else
+ for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
+ if (gst_slot[u8_i].need_update) {
+ u8_offset = gst_slot[u8_i].pt_report_offset * LEN_PT;
+ g_raydium_ts->x_pos[u8_i] = p_u8_buf[POS_X_L + u8_offset] |
+ p_u8_buf[POS_X_H + u8_offset] << BYTE_SHIFT;
+ g_raydium_ts->y_pos[u8_i] = p_u8_buf[POS_Y_L + u8_offset] |
+ p_u8_buf[POS_Y_H + u8_offset] << BYTE_SHIFT;
+ g_raydium_ts->pressure = p_u8_buf[POS_PRESSURE_L + u8_offset] |
+ p_u8_buf[POS_PRESSURE_H + u8_offset] << BYTE_SHIFT;
+ i16_wx = p_u8_buf[POS_WX_L + u8_offset] |
+ p_u8_buf[POS_WX_H + u8_offset] << BYTE_SHIFT;
+ i16_wy = p_u8_buf[POS_WY_L + u8_offset] |
+ p_u8_buf[POS_WY_H + u8_offset] << BYTE_SHIFT;
+
+ input_mt_slot(g_raydium_ts->input_dev, u8_i);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, true);
+ __set_bit(u8_i, ids);
+
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_POSITION_X, g_raydium_ts->x_pos[u8_i]);
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_POSITION_Y, g_raydium_ts->y_pos[u8_i]);
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_PRESSURE, g_raydium_ts->pressure);
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_TOUCH_MAJOR, max(i16_wx, i16_wy));
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_TOUCH_MINOR, min(i16_wx, i16_wy));
+
+ u8_touch_count++;
+ }
+ }
+ input_report_key(g_raydium_ts->input_dev,
+ BTN_TOUCH, u8_touch_count > 0);
+ input_report_key(g_raydium_ts->input_dev,
+ BTN_TOOL_FINGER, u8_touch_count > 0);
+
+ for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
+ if (test_bit(u8_i, ids))
+ continue;
+ input_mt_slot(g_raydium_ts->input_dev, u8_i);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, false);
+ }
+
+ input_sync(g_raydium_ts->input_dev);
+#endif
+ return 0;
+}
+int raydium_read_touchdata(unsigned char *p_u8_tp_status, unsigned char *p_u8_buf)
+{
+ int i32_ret = 0;
+ unsigned char u8_points_amount;
+ static unsigned char u8_seq_no;
+ unsigned char u8_retry;
+
+ u8_retry = 3;
+
+ mutex_lock(&g_raydium_ts->lock);
+ while (u8_retry != 0) {
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0) {
+ msleep(250);
+ u8_retry--;
+ } else
+ break;
+ }
+ if (u8_retry == 0) {
+ pr_err("[touch]%s: failed to set page, hw reset\n", __func__);
+
+ goto reset_error;
+ }
+
+ memset(p_u8_buf, 0, MAX_REPORT_PACKET_SIZE);
+ memset(p_u8_tp_status, 0, MAX_TCH_STATUS_PACKET_SIZE);
+
+ /*read touch point information*/
+ i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
+ RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR,
+ p_u8_tp_status, MAX_TCH_STATUS_PACKET_SIZE);
+ if (i32_ret < 0) {
+ pr_err("[touch]%s: failed to read data: %d\n",
+ __func__, __LINE__);
+ goto exit_error;
+ }
+#ifdef ESD_SOLUTION_EN
+ if (p_u8_tp_status[POS_FW_STATE] != 0x1A &&
+ p_u8_tp_status[POS_FW_STATE] != 0xAA) {
+ if (g_u8_resetflag == true) {
+ pr_err("[touch]%s -> filter irq, FW state = 0x%x\n",
+ __func__, p_u8_tp_status[POS_FW_STATE]);
+ i32_ret = -1;
+ g_u8_resetflag = false;
+ goto exit_error;
+ }
+ pr_err("[touch]%s -> abnormal irq, FW state = 0x%x\n",
+ __func__, p_u8_tp_status[POS_FW_STATE]);
+ i32_ret = -1;
+ goto reset_error;
+
+ }
+#endif
+ /* inform IC to prepare next report*/
+ if (u8_seq_no == p_u8_tp_status[POS_SEQ]) {
+ pr_err("%s -> report not updated.\n", __func__);
+ goto exit_error;
+ }
+ u8_points_amount = p_u8_tp_status[POS_PT_AMOUNT];
+
+ if (u8_points_amount > MAX_TOUCH_NUM)
+ goto exit_error;
+
+ /*read touch point report*/
+ /*PDA2 only support word mode*/
+ if (u8_points_amount != 0)
+ i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
+ RAYDIUM_PDA2_TCH_RPT_ADDR, p_u8_buf,
+ u8_points_amount * LEN_PT);
+
+ if (i32_ret < 0) {
+ pr_err("[touch]%s: failed to read data: %d\n",
+ __func__, __LINE__);
+ goto exit_error;
+ }
+
+ u8_seq_no = p_u8_tp_status[POS_SEQ];
+ p_u8_tp_status[POS_SEQ] = 0;
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR, p_u8_tp_status, 1);
+ if (i32_ret < 0) {
+ pr_err("[touch]%s: write data failed: %d\n", __func__, i32_ret);
+ goto exit_error;
+ }
+
+ raydium_touch_report(p_u8_buf, u8_points_amount);
+
+exit_error:
+ mutex_unlock(&g_raydium_ts->lock);
+
+ return i32_ret;
+
+reset_error:
+ mutex_unlock(&g_raydium_ts->lock);
+#ifdef ESD_SOLUTION_EN
+ u8_retry = 3;
+ while (u8_retry != 0) {
+ i32_ret = raydium_hw_reset_fun(g_raydium_ts->client);
+ if (i32_ret < 0) {
+ msleep(100);
+ u8_retry--;
+ } else
+ break;
+ }
+#endif
+ return i32_ret;
+}
+
+static void raydium_work_handler(struct work_struct *work)
+{
+ int i32_ret = 0;
+ unsigned char u8_tp_status[MAX_TCH_STATUS_PACKET_SIZE];
+ unsigned char u8_buf[MAX_REPORT_PACKET_SIZE];
+
+#ifdef GESTURE_EN
+ unsigned char u8_i;
+
+ if ((g_raydium_ts->blank == FB_BLANK_VSYNC_SUSPEND ||
+ g_raydium_ts->blank == FB_BLANK_POWERDOWN) &&
+ (g_u8_resetflag == false)) {
+ input_mt_slot(g_raydium_ts->input_dev, 0);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, 1);
+ input_report_abs(g_raydium_ts->input_dev, ABS_MT_POSITION_X, 100);
+ input_report_abs(g_raydium_ts->input_dev, ABS_MT_POSITION_Y, 100);
+ input_sync(g_raydium_ts->input_dev);
+ usleep_range(9500, 10500);
+ input_mt_slot(g_raydium_ts->input_dev, 0);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, 0);
+ input_mt_report_pointer_emulation(g_raydium_ts->input_dev, false);
+ input_sync(g_raydium_ts->input_dev);
+ input_report_key(g_raydium_ts->input_dev, KEY_POWER, true);
+ usleep_range(9500, 10500);
+ input_sync(g_raydium_ts->input_dev);
+
+ input_report_key(g_raydium_ts->input_dev, KEY_POWER, false);
+ input_sync(g_raydium_ts->input_dev);
+#ifdef ESD_SOLUTION_EN
+ g_u8_checkflag = true;
+#endif
+ pr_info("[touch]display wake up with g_u8_resetflag false\n");
+ } else {
+
+ if (g_u8_i2c_mode == PDA2_MODE) {
+ i32_ret = raydium_read_touchdata(u8_tp_status, u8_buf);
+ if (i32_ret < 0) {
+ pr_info("[touch]%s, read_touchdata error, ret:%d\n",
+ __func__, i32_ret);
+ return;
+ }
+ }
+ /*when display on can use palm to suspend*/
+ if (g_raydium_ts->blank == FB_BLANK_UNBLANK) {
+ if (u8_tp_status[POS_GES_STATUS] == RAD_PALM_ENABLE) {
+ if (g_raydium_ts->is_palm == 0) {
+ /* release all touches*/
+ for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs;
+ u8_i++) {
+ input_mt_slot(g_raydium_ts->input_dev,
+ u8_i);
+ input_mt_report_slot_state(
+ g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, false);
+ }
+ input_mt_report_pointer_emulation(
+ g_raydium_ts->input_dev,
+ false);
+ /*press sleep key*/
+ input_report_key(g_raydium_ts->input_dev,
+ KEY_SLEEP, true);
+ input_sync(g_raydium_ts->input_dev);
+
+ pr_info("[touch]palm_status = %d.\n",
+ u8_tp_status[POS_GES_STATUS]);
+
+ g_raydium_ts->is_palm = 1;
+ /*goto exit;*/
+ }
+ } else if ((u8_tp_status[POS_GES_STATUS]
+ == RAD_PALM_DISABLE)
+ && (g_raydium_ts->is_palm == 1)) {
+ pr_info("[touch]leave palm mode.\n");
+ input_report_key(g_raydium_ts->input_dev,
+ KEY_SLEEP, false);
+ input_sync(g_raydium_ts->input_dev);
+
+ /*raydium_irq_control(raydium_ts, DISABLE);*/
+ g_raydium_ts->is_palm = 0;
+ /*goto exit;*/
+ }
+ } else if (g_raydium_ts->blank == FB_BLANK_VSYNC_SUSPEND ||
+ g_raydium_ts->blank == FB_BLANK_POWERDOWN) {
+ /*need check small area*/
+ if (u8_tp_status[POS_GES_STATUS] == RAD_WAKE_UP) {
+ input_mt_slot(g_raydium_ts->input_dev, 0);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, 1);
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_POSITION_X, 100);
+ input_report_abs(g_raydium_ts->input_dev,
+ ABS_MT_POSITION_Y, 100);
+ input_sync(g_raydium_ts->input_dev);
+ usleep_range(9500, 10500);
+ input_mt_slot(g_raydium_ts->input_dev, 0);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER, 0);
+ input_mt_report_pointer_emulation(
+ g_raydium_ts->input_dev,
+ false);
+ input_sync(g_raydium_ts->input_dev);
+ input_report_key(g_raydium_ts->input_dev, KEY_POWER, true);
+ usleep_range(9500, 10500);
+ input_sync(g_raydium_ts->input_dev);
+
+ input_report_key(g_raydium_ts->input_dev, KEY_POWER, false);
+ input_sync(g_raydium_ts->input_dev);
+ pr_info("[touch]display wake up with g_u8_resetflag true\n");
+ /*goto exit;*/
+ }
+ }
+ }
+#else
+ if (g_u8_i2c_mode == PDA2_MODE) {
+ i32_ret = raydium_read_touchdata(u8_tp_status, u8_buf);
+ if (i32_ret < 0) {
+ pr_info("[touch]%s, read_touchdata error, ret:%d\n",
+ __func__, i32_ret);
+ }
+ }
+#endif
+}
+
+/*The raydium device will signal the host about TRIGGER_FALLING.
+ *Processed when the interrupt is asserted.
+ */
+static irqreturn_t raydium_ts_interrupt(int irq, void *dev_id)
+{
+ bool result = false;
+
+ /*For bootloader wrt/erase flash and software reset interrupt*/
+ if ((g_u8_raydium_flag & ENG_MODE) != 0) {
+ disable_irq_nosync(g_raydium_ts->irq);
+ g_raydium_ts->irq_enabled = false;
+ pr_info("[touch]RAD_ENG_MODE\n");
+ g_u8_raydium_flag |= INT_FLAG;
+ } else {
+ if (!work_pending(&g_raydium_ts->work)) {
+ /* Clear interrupts*/
+ result = queue_work(g_raydium_ts->workqueue,
+ &g_raydium_ts->work);
+
+ if (result == false) {
+ /*queue_work fail*/
+ pr_err("[touch]queue_work fail.\n");
+ }
+
+
+ } else {
+ /*work pending*/
+ mutex_lock(&g_raydium_ts->lock);
+ if (raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0) < 0) {
+
+ pr_err("[touch]%s: failed to set page in work_pending\n",
+ __func__);
+ }
+ mutex_unlock(&g_raydium_ts->lock);
+
+ pr_info("[touch]work_pending\n");
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static int raydium_check_i2c_ready(unsigned short *u16_i2c_data)
+{
+ unsigned char u8_buf[4];
+ int i32_ret = -1;
+
+ mutex_lock(&g_raydium_ts->lock);
+
+ if (g_u8_i2c_mode == PDA2_MODE) {
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ *(unsigned int *)u8_buf =
+ (RAD_I2C_PDA_MODE_ENABLE << 24) |
+ ((RAD_CHK_I2C_CMD & (~MASK_8BIT)) >> 8);
+ /*using byte mode to read 4 bytes*/
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_PDA_CFG_ADDR,
+ u8_buf,
+ 4);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_ENABLE_PDA);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ i32_ret = raydium_i2c_pda2_read(
+ g_raydium_ts->client,
+ (unsigned char)(RAD_CHK_I2C_CMD & MASK_8BIT),
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_error;
+ if (u8_buf[3] != 0xF3) {
+ pr_info("[touch]PDA2 read i2c fail\n");
+ g_u8_i2c_mode = PDA_MODE;
+ i32_ret = raydium_i2c_pda_read(g_raydium_ts->client,
+ RAD_CHK_I2C_CMD, u8_buf,
+ 4);
+ if (i32_ret < 0)
+ goto exit_error;
+ }
+
+ } else {
+ i32_ret = raydium_i2c_pda_read(g_raydium_ts->client,
+ RAD_CHK_I2C_CMD, u8_buf,
+ 4);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ }
+
+ *u16_i2c_data = u8_buf[3] << 8 | u8_buf[2];
+
+ pr_info("[touch]RAD check I2C : 0x%02X%02X\n", u8_buf[3], u8_buf[2]);
+
+exit_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ return i32_ret;
+}
+
+#if defined(CONFIG_PM)
+static void raydium_ts_do_suspend(void)
+{
+ unsigned char u8_i = 0;
+ g_u8_resetflag = false;
+ if (g_raydium_ts->is_suspend == 1) {
+ pr_info("[touch]Already in suspend state\n");
+ return;
+ }
+
+ /*#ifndef GESTURE_EN*/
+ raydium_irq_control(DISABLE);
+ /*#endif*/
+
+ /*clear workqueue*/
+ if (!cancel_work_sync(&g_raydium_ts->work))
+ pr_info("[touch]workqueue is empty!\n");
+
+ pr_info("[touch]%s.\n", __func__);
+
+ /* release all touches */
+ for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
+ input_mt_slot(g_raydium_ts->input_dev, u8_i);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER,
+ false);
+ }
+ input_mt_report_pointer_emulation(g_raydium_ts->input_dev, false);
+ input_sync(g_raydium_ts->input_dev);
+#ifdef ENABLE_DUMP_DATA
+ if (!g_u8_dumpcount)
+ timeout = jiffies + 2*HZ;
+ if (g_u8_dumpcount < 5)
+ g_u8_dumpcount++;
+ if (g_u8_palm_flag || (time_is_before_jiffies(timeout))) {
+ g_u8_dumpcount = 0;
+ g_u8_palm_flag = false;
+ }
+ if (g_u8_dumpcount == 5) {
+ g_u8_dump_flag = true;
+ g_u8_dumpcount = 0;
+ }
+#endif
+
+#ifdef GESTURE_EN
+ if (device_may_wakeup(&g_raydium_ts->client->dev)) {
+ pr_info("[touch]Device may wakeup\n");
+ if (!enable_irq_wake(g_raydium_ts->irq))
+ g_raydium_ts->irq_wake = 1;
+
+ } else
+ pr_info("[touch]Device not wakeup\n");
+ raydium_irq_control(ENABLE);
+#endif
+
+ g_raydium_ts->is_suspend = 1;
+}
+
+static void raydium_ts_do_resume(void)
+{
+#ifdef ESD_SOLUTION_EN
+ int i32_ret = 0;
+ unsigned char u8_retry = 0;
+#endif
+ unsigned char u8_w_data[4];
+
+ pr_info("[touch]%s, %d.\n", __func__, g_raydium_ts->is_suspend);
+ if (g_raydium_ts->is_suspend == 0) {
+ pr_info("[touch]Already in resume state\n");
+ return;
+ }
+
+ /* clear interrupts*/
+ mutex_lock(&g_raydium_ts->lock);
+ if (raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0) < 0) {
+ pr_err("[ raydium ]%s: failed to set page\n", __func__);
+ mutex_unlock(&g_raydium_ts->lock);
+ return;
+ }
+ /* clear seq num*/
+ u8_w_data[POS_SEQ] = 0;
+ if (raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR, u8_w_data, 1) < 0) {
+ pr_err("[ raydium ]%s: failed to clear seq\n", __func__);
+ mutex_unlock(&g_raydium_ts->lock);
+ return;
+ }
+
+ mutex_unlock(&g_raydium_ts->lock);
+
+ /* clear workqueue*/
+ if (!cancel_work_sync(&g_raydium_ts->work))
+ pr_info("[ raydium ]workqueue is empty!\n");
+#ifdef ESD_SOLUTION_EN
+ if (g_u8_checkflag == true) {
+ i32_ret = raydium_esd_check();
+ if (i32_ret < 0) {
+ u8_retry = 3;
+ while (u8_retry != 0) {
+ i32_ret = raydium_hw_reset_fun(g_raydium_ts->client);
+ if (i32_ret < 0) {
+ msleep(100);
+ u8_retry--;
+ } else
+ break;
+ }
+
+ }
+ g_u8_checkflag = false;
+ }
+#endif
+ raydium_irq_control(ENABLE);
+#ifdef ENABLE_DUMP_DATA
+ if (g_u8_dump_flag) {
+ schedule_delayed_work(&g_raydium_ts->dump_work, HZ);
+ g_u8_dump_flag = false;
+ }
+#endif
+#ifdef GESTURE_EN
+ if (device_may_wakeup(&g_raydium_ts->client->dev)) {
+ pr_info("[touch]Device may wakeup\n");
+ if (g_raydium_ts->irq_wake) {
+ disable_irq_wake(g_raydium_ts->irq);
+ g_raydium_ts->irq_wake = 0;
+ }
+ } else
+ pr_info("[touch]Device not wakeup\n");
+#endif
+
+ g_raydium_ts->is_suspend = 0;
+}
+
+static int raydium_ts_suspend(struct device *dev)
+{
+ raydium_ts_do_suspend();
+ return 0;
+}
+
+static int raydium_ts_resume(struct device *dev)
+{
+ raydium_ts_do_resume();
+ return 0;
+}
+
+static const struct dev_pm_ops raydium_ts_pm_ops = {
+#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
+ .suspend = raydium_ts_suspend,
+ .resume = raydium_ts_resume,
+#endif /*end of CONFIG_PM*/
+};
+
+/*used for touch lock feature*/
+static int raydium_ts_open(struct input_dev *input_dev)
+{
+ int i32_ret = 0;
+
+ pr_info("[touch]%s()+\n", __func__);
+
+ pr_info("[touch]ts->blank:%x\n", g_raydium_ts->blank);
+
+ if (g_raydium_ts->is_sleep == 1) {
+ mutex_lock(&g_raydium_ts->lock);
+ if (gpio_is_valid(g_raydium_ts->rst_gpio)) {
+
+ g_u8_resetflag = true;
+ gpio_set_value(g_raydium_ts->rst_gpio, 1);
+ gpio_set_value(g_raydium_ts->rst_gpio, 0);
+ msleep(RAYDIUM_RESET_INTERVAL_MSEC);/*5ms*/
+ gpio_set_value(g_raydium_ts->rst_gpio, 1);
+ msleep(RAYDIUM_RESET_DELAY_MSEC);/*100ms*/
+ g_u8_i2c_mode = PDA2_MODE;
+ }
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+ g_raydium_ts->is_sleep = 0;
+ pr_info("[touch]disable touch lock.\n");
+ }
+ return i32_ret;
+}
+
+static void raydium_ts_close(struct input_dev *input_dev)
+{
+ int i32_ret = 0;
+ unsigned char u8_i = 0;
+ unsigned char u8_wbuffer[1];
+
+ pr_info("[touch]%s()+\n", __func__);
+
+ if (g_raydium_ts->is_sleep == 1) {
+ pr_info("[touch]touch lock already enabled.\n");
+ return;
+ }
+
+ raydium_irq_control(DISABLE);
+
+ for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
+ input_mt_slot(g_raydium_ts->input_dev, u8_i);
+ input_mt_report_slot_state(g_raydium_ts->input_dev,
+ MT_TOOL_FINGER,
+ false);
+ }
+ input_mt_report_pointer_emulation(g_raydium_ts->input_dev, false);
+ input_sync(g_raydium_ts->input_dev);
+ mutex_lock(&g_raydium_ts->lock);
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0) {
+ pr_err("[touch]ret:%d\n", i32_ret);
+ goto exit_i2c_error;
+ }
+ u8_wbuffer[0] = RAYDIUM_HOST_CMD_PWR_SLEEP;
+ i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_wbuffer,
+ 1);
+ if (i32_ret < 0) {
+ pr_err("[touch]ret:%d\n", i32_ret);
+ goto exit_i2c_error;
+ }
+
+ mutex_unlock(&g_raydium_ts->lock);
+ g_raydium_ts->is_sleep = 1;
+ pr_info("[touch]enable touch lock.\n");
+ return;
+
+exit_i2c_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+}
+
+#else
+static int raydium_ts_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int raydium_ts_resume(struct device *dev)
+{
+ return 0;
+}
+#endif /*end of CONFIG_FB*/
+
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event,
+ void *data)
+{
+ struct fb_event *evdata = data;
+ int *blank;
+
+ if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+ g_raydium_ts && g_raydium_ts->client) {
+ blank = evdata->data;
+ g_raydium_ts->blank = (*blank);
+ switch (*blank) {
+
+ /*screen on*/
+ case FB_BLANK_UNBLANK:
+ pr_info("[touch]FB_BLANK_UNBLANK\n");
+#ifdef GESTURE_EN
+
+ /* clear palm status */
+
+ g_raydium_ts->is_palm = 0;
+#endif
+#ifdef HOST_NOTIFY_EN
+ raydium_notify_function(ACTIVE_MODE);
+#endif
+ raydium_ts_resume(&g_raydium_ts->client->dev);
+ break;
+
+ /*screen off*/
+ case FB_BLANK_POWERDOWN:
+ pr_info("[touch]FB_BLANK_POWERDOWN\n");
+#ifdef GESTURE_EN
+
+ /* clear palm status */
+
+ g_raydium_ts->is_palm = 0;
+#endif
+#ifdef HOST_NOTIFY_EN
+ raydium_notify_function(SLEEP_MODE);
+#endif
+ raydium_ts_suspend(&g_raydium_ts->client->dev);
+ break;
+
+ /*ambient mode*/
+ case FB_BLANK_VSYNC_SUSPEND:
+ pr_info("[touch]FB_BLANK_VSYNC_SUSPEND\n");
+#ifdef GESTURE_EN
+
+ /* clear palm status */
+
+ g_raydium_ts->is_palm = 0;
+#endif
+#ifdef HOST_NOTIFY_EN
+ raydium_notify_function(AMBIENT_MODE);
+#endif
+ raydium_ts_suspend(&g_raydium_ts->client->dev);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void raydium_register_notifier(void)
+{
+ memset(&g_raydium_ts->fb_notif, 0, sizeof(g_raydium_ts->fb_notif));
+ g_raydium_ts->fb_notif.notifier_call = fb_notifier_callback;
+
+ /* register on the fb notifier and work with fb*/
+ if (fb_register_client(&g_raydium_ts->fb_notif))
+ pr_err("[touch]register notifier failed\n");
+}
+
+static void raydium_unregister_notifier(void)
+{
+ fb_unregister_client(&g_raydium_ts->fb_notif);
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+static void raydium_ts_early_suspend(struct early_suspend *handler)
+{
+
+ raydium_ts_do_suspend();
+}
+
+static void raydium_ts_late_resume(struct early_suspend *handler)
+{
+ raydium_ts_do_resume();
+}
+#endif /*end of CONFIG_FB*/
+
+#ifdef CONFIG_OF
+static int raydium_get_dt_coords(struct device *dev, char *name,
+ struct raydium_ts_platform_data *pdata)
+{
+ u32 coords[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 != COORDS_ARR_SIZE) {
+ pr_err("[touch]invalid %s\n", name);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(np, name, coords, coords_size);
+ if (rc && (rc != -EINVAL)) {
+ pr_err("[touch]unable to read %s\n", name);
+ return rc;
+ }
+
+ if (!strcmp(name, "raydium,display-coords")) {
+ pdata->x_min = coords[0];
+ pdata->y_min = coords[1];
+ pdata->x_max = coords[2];
+ pdata->y_max = coords[3];
+ } else {
+ pr_err("[touch]unsupported property %s\n", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int raydium_parse_dt(struct device *dev,
+ struct raydium_ts_platform_data *pdata)
+{
+ struct device_node *np = dev->of_node;
+ int rc = 0;
+ u32 temp_val = 0;
+
+ pdata->name = RAYDIUM_NAME;
+
+ rc = raydium_get_dt_coords(dev, "raydium,display-coords", pdata);
+ if (rc)
+ return rc;
+
+
+ /* reset, irq gpio info */
+ pdata->reset_gpio = of_get_named_gpio_flags(np,
+ "raydium,reset-gpio",
+ 0,
+ &pdata->reset_gpio_flags);
+ if (pdata->reset_gpio < 0)
+ return pdata->reset_gpio;
+
+
+ pdata->irq_gpio = of_get_named_gpio_flags(np,
+ "raydium,irq-gpio",
+ 0,
+ &pdata->irq_gpio_flags);
+ if (pdata->irq_gpio < 0)
+ return pdata->irq_gpio;
+
+
+ rc = of_property_read_u32(np,
+ "raydium,hard-reset-delay-ms", &temp_val);
+ if (!rc)
+ pdata->hard_rst_dly = temp_val;
+ else
+ return rc;
+
+
+ rc = of_property_read_u32(np,
+ "raydium,soft-reset-delay-ms", &temp_val);
+ if (!rc)
+ pdata->soft_rst_dly = temp_val;
+ else
+ return rc;
+
+
+ rc = of_property_read_u32(np, "raydium,num-max-touches", &temp_val);
+ if (!rc)
+ pdata->num_max_touches = temp_val;
+ else
+ return rc;
+#ifdef FW_MAPPING_BYID_EN
+ rc = of_property_read_u32(np, "raydium,fw_id", &temp_val);
+ if (!rc)
+ pdata->fw_id = temp_val;
+ else
+ return rc;
+#endif
+ return 0;
+}
+#else
+static int raydium_parse_dt(struct device *dev,
+ struct raydium_ts_platform_data *pdata)
+{
+ return -ENODEV;
+}
+#endif /*end of CONFIG_OF*/
+
+static void raydium_input_set(struct input_dev *input_dev)
+{
+ int ret = 0;
+ unsigned char i;
+
+ input_dev->name = "raydium_ts";/*name need same with .idc*/
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &g_raydium_ts->client->dev;
+ input_dev->open = raydium_ts_open;/*touch lock*/
+ input_dev->close = raydium_ts_close;
+ input_set_drvdata(input_dev, g_raydium_ts);
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ pr_info("[touch]set abs prarams x[%d], y[%d]\n",
+ g_raydium_ts->x_max, g_raydium_ts->y_max);
+
+ /* Multitouch input params setup */
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+ g_raydium_ts->x_max, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+ g_raydium_ts->y_max, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, PRESS_MAX, 0, 0);
+ input_set_abs_params(input_dev,
+ ABS_MT_TOUCH_MAJOR, 0, WIDTH_MAX, 0, 0);
+ input_set_abs_params(input_dev,
+ ABS_MT_TOUCH_MINOR, 0, WIDTH_MAX, 0, 0);
+
+ ret = input_mt_init_slots(input_dev, MAX_TOUCH_NUM,
+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+ if (ret)
+ pr_err("[touch]failed to initialize MT slots: %d\n", ret);
+
+ for (i = 0; i < (MAX_TOUCH_NUM * 2); i++)
+ gst_slot[i] = gst_slot_init;
+
+}
+static int raydium_set_resolution(void)
+{
+ unsigned char u8_buf[4];
+ int i32_ret = -1;
+ unsigned int u32_x, u32_y;
+
+ mutex_lock(&g_raydium_ts->lock);
+
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
+ RAYDIUM_PDA2_DISPLAY_INFO_ADDR,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ u32_x = u8_buf[3] << 8 | u8_buf[2];
+ u32_y = u8_buf[1] << 8 | u8_buf[0];
+
+ pr_info("[touch]RAD display info x:%d, y:%d\n", u32_x, u32_y);
+
+ if (u32_x > 300 && u32_y > 300 &&
+ u32_x < 600 && u32_y < 600) {
+ g_raydium_ts->x_max = u32_x - 1;
+ g_raydium_ts->y_max = u32_y - 1;
+ }
+
+exit_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ return i32_ret;
+}
+
+static int raydium_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct raydium_ts_platform_data *pdata =
+ (struct raydium_ts_platform_data *)client->dev.platform_data;
+
+ struct input_dev *input_dev;
+ unsigned short u16_i2c_data;
+ int ret = 0;
+
+ pr_info("[touch] probe\n");
+
+ if (client->dev.of_node) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct raydium_ts_platform_data),
+ GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&client->dev,
+ "[touch]failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ ret = raydium_parse_dt(&client->dev, pdata);
+ if (ret) {
+ dev_err(&client->dev,
+ "[touch]device tree parsing failed\n");
+ goto parse_dt_failed;
+ }
+ } else
+ pdata = client->dev.platform_data;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ ret = -ENODEV;
+ goto exit_check_functionality_failed;
+ }
+
+ g_raydium_ts = devm_kzalloc(&client->dev,
+ sizeof(struct raydium_ts_data),
+ GFP_KERNEL);
+ if (!g_raydium_ts) {
+ pr_err("[touch]failed to allocate input driver data\n");
+ return -ENOMEM;
+ }
+
+ raydium_variable_init();
+
+ mutex_init(&g_raydium_ts->lock);
+
+ i2c_set_clientdata(client, g_raydium_ts);
+ g_raydium_ts->irq_enabled = false;
+ g_raydium_ts->irq_wake = false;
+
+ g_raydium_ts->irq_gpio = pdata->irq_gpio;
+ g_raydium_ts->rst_gpio = pdata->reset_gpio;
+ client->irq = g_raydium_ts->irq_gpio;
+ g_raydium_ts->u8_max_touchs = pdata->num_max_touches;
+ g_raydium_ts->client = client;
+ g_raydium_ts->x_max = pdata->x_max - 1;
+ g_raydium_ts->y_max = pdata->y_max - 1;
+ g_raydium_ts->is_suspend = 0;
+ g_raydium_ts->is_sleep = 0;
+#ifdef GESTURE_EN
+ g_raydium_ts->is_palm = 0;
+#endif
+ g_raydium_ts->fw_version = 0;
+ device_init_wakeup(&client->dev, 1);
+
+#ifdef MSM_NEW_VER
+ ret = raydium_ts_pinctrl_init();
+ if (!ret && g_raydium_ts->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(g_raydium_ts->ts_pinctrl,
+ g_raydium_ts->pinctrl_state_active);
+ if (ret < 0)
+ pr_err("[touch]failed to set pin to active state\n");
+ }
+#endif /*end of MSM_NEW_VER*/
+
+ ret = raydium_gpio_configure(true);
+ if (ret < 0) {
+ pr_err("[touch]failed to configure the gpios\n");
+ goto err_gpio_req;
+ }
+ /*modify dtsi to 360*/
+ msleep(pdata->soft_rst_dly);
+
+ /*print touch i2c ready*/
+ ret = raydium_check_i2c_ready(&u16_i2c_data);
+ if (ret < 0) {
+ pr_err("[touch]Check I2C failed\n");
+ ret = -ENODEV;
+ goto exit_check_i2c;
+ }
+
+ /*input device initialization*/
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ ret = -ENOMEM;
+ pr_err("[touch]failed to allocate input device\n");
+ goto exit_input_dev_alloc_failed;
+ }
+
+ raydium_set_resolution();
+
+ g_raydium_ts->input_dev = input_dev;
+ raydium_input_set(input_dev);
+
+ ret = input_register_device(input_dev);
+ if (ret) {
+ pr_err("[touch]failed to register input device: %s\n",
+ dev_name(&client->dev));
+ goto exit_input_register_device_failed;
+ }
+
+#ifdef GESTURE_EN
+ input_set_capability(input_dev, EV_KEY, KEY_SLEEP);
+ input_set_capability(input_dev, EV_KEY, KEY_POWER);
+#endif
+
+ /*suspend/resume routine*/
+#if defined(CONFIG_FB)
+ raydium_register_notifier();
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ /*Early-suspend level*/
+ g_raydium_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ g_raydium_ts->early_suspend.suspend = raydium_ts_early_suspend;
+ g_raydium_ts->early_suspend.resume = raydium_ts_late_resume;
+ register_early_suspend(&g_raydium_ts->early_suspend);
+#endif/*end of CONFIG_FB*/
+
+#ifdef CONFIG_RM_SYSFS_DEBUG
+ raydium_create_sysfs(client);
+#endif/*end of CONFIG_RM_SYSFS_DEBUG*/
+
+ INIT_WORK(&g_raydium_ts->work, raydium_work_handler);
+
+ g_raydium_ts->workqueue = create_singlethread_workqueue("raydium_ts");
+#ifdef ENABLE_DUMP_DATA
+ INIT_DELAYED_WORK(&g_raydium_ts->dump_work, raydium_dump_data_work);
+#endif
+ /*irq_gpio = 13 irqflags = 108*/
+ pr_info("[touch]pdata irq : %d\n", g_raydium_ts->irq_gpio);
+ pr_info("[touch]client irq : %d, pdata flags : %d\n",
+ client->irq, pdata->irqflags);
+
+ g_raydium_ts->irq = gpio_to_irq(pdata->irq_gpio);
+ ret = request_threaded_irq(g_raydium_ts->irq, NULL, raydium_ts_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_NO_SUSPEND,
+ client->dev.driver->name, g_raydium_ts);
+
+ if (ret < 0) {
+ pr_err("[touch]raydium_probe: request irq failed\n");
+ goto exit_irq_request_failed;
+ }
+
+ g_raydium_ts->irq_desc = irq_to_desc(g_raydium_ts->irq);
+ g_raydium_ts->irq_enabled = true;
+
+ /*disable_irq then enable_irq for avoid Unbalanced enable for IRQ */
+
+ /*raydium_irq_control(ts, ENABLE);*/
+
+ pr_info("[touch]RAD Touch driver ver :0x%X\n", g_u32_driver_version);
+
+ /*fw update check*/
+ ret = raydium_fw_update_check(u16_i2c_data);
+ if (ret < 0) {
+ pr_err("[touch]FW update check failed\n");
+ ret = -ENODEV;
+ goto exit_irq_request_failed;
+ }
+ return 0;
+
+exit_irq_request_failed:
+#if defined(CONFIG_FB)
+ raydium_unregister_notifier();
+#endif/*end of CONFIG_FB*/
+
+ cancel_work_sync(&g_raydium_ts->work);
+ input_unregister_device(input_dev);
+
+exit_input_register_device_failed:
+ input_free_device(input_dev);
+
+exit_input_dev_alloc_failed:
+exit_check_i2c:
+ 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_req:
+#ifdef MSM_NEW_VER
+ if (g_raydium_ts->ts_pinctrl) {
+ if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_release)) {
+ devm_pinctrl_put(g_raydium_ts->ts_pinctrl);
+ g_raydium_ts->ts_pinctrl = NULL;
+ } else {
+ ret = pinctrl_select_state(g_raydium_ts->ts_pinctrl,
+ g_raydium_ts->pinctrl_state_release);
+ if (ret)
+ pr_err("[touch]pinctrl_select_state failed\n");
+ }
+ }
+#endif/*end of MSM_NEW_VER*/
+
+parse_dt_failed:
+exit_check_functionality_failed:
+ return ret;
+
+}
+
+static int raydium_ts_remove(struct i2c_client *client)
+{
+
+#if defined(CONFIG_FB)
+ raydium_unregister_notifier();
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ unregister_early_suspend(&g_raydium_ts->early_suspend);
+#endif/*end of CONFIG_FB*/
+ input_unregister_device(g_raydium_ts->input_dev);
+ input_free_device(g_raydium_ts->input_dev);
+ gpio_free(g_raydium_ts->rst_gpio);
+
+#ifdef CONFIG_RM_SYSFS_DEBUG
+ raydium_release_sysfs(client);
+#endif /*end of CONFIG_RM_SYSFS_DEBUG*/
+
+ free_irq(client->irq, g_raydium_ts);
+
+ if (gpio_is_valid(g_raydium_ts->rst_gpio))
+ gpio_free(g_raydium_ts->rst_gpio);
+
+ if (gpio_is_valid(g_raydium_ts->irq_gpio))
+ gpio_free(g_raydium_ts->irq_gpio);
+
+ cancel_work_sync(&g_raydium_ts->work);
+ destroy_workqueue(g_raydium_ts->workqueue);
+
+
+ kfree(g_raydium_ts);
+
+ i2c_set_clientdata(client, NULL);
+ return 0;
+}
+
+static const struct i2c_device_id raydium_ts_id[] = {
+ {RAYDIUM_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, raydium_ts_id);
+
+#ifdef CONFIG_OF
+static struct of_device_id raydium_match_table[] = {
+ { .compatible = "raydium,raydium-ts",},
+ { },
+};
+#else
+#define raydium_match_table NULL
+#endif/*end of CONFIG_OF*/
+
+static struct i2c_driver raydium_ts_driver = {
+ .probe = raydium_ts_probe,
+ .remove = raydium_ts_remove,
+ .id_table = raydium_ts_id,
+ .driver = {
+ .name = RAYDIUM_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = raydium_match_table,
+#if defined(CONFIG_PM)
+ .pm = &raydium_ts_pm_ops,
+#endif/*end of CONFIG_PM*/
+ },
+};
+
+static int __init raydium_ts_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&raydium_ts_driver);
+ return ret;
+}
+
+static void __exit raydium_ts_exit(void)
+{
+ i2c_del_driver(&raydium_ts_driver);
+}
+
+module_init(raydium_ts_init);
+module_exit(raydium_ts_exit);
+
+MODULE_AUTHOR("Raydium");
+MODULE_DESCRIPTION("Raydium TouchScreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/raydium_wt030/raydium_driver.h b/drivers/input/touchscreen/raydium_wt030/raydium_driver.h
new file mode 100644
index 0000000..415e0af
--- /dev/null
+++ b/drivers/input/touchscreen/raydium_wt030/raydium_driver.h
@@ -0,0 +1,375 @@
+/* drivers/input/touchscreen/raydium_wt030/raydium_driver.h
+ *
+ * Raydium TouchScreen driver.
+ *
+ * Copyright (c) 2010 Raydium tech Ltd.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_RAYDIUM_H
+#define __LINUX_RAYDIUM_H
+#define RAYDIUM_NAME "raydium_ts"
+#define COORDS_ARR_SIZE 4
+#define I2C_VTG_MIN_UV 1800000
+#define I2C_VTG_MAX_UV 1800000
+#define RAD_MAIN_VERSION 0x01
+#define RAD_MINOR_VERSION 0x07
+#define RAD_CUSTOMER_VERSION 0x0100
+
+#if defined(CONFIG_TOUCHSCREEN_RM_TS)
+/* IC timing control arguments */
+#define RAYDIUM_POWERON_DELAY_USEC 500
+#define RAYDIUM_RESET_INTERVAL_MSEC 5
+#define RAYDIUM_RESET_RESTORE_USEC 200
+#define RAYDIUM_RESET_DELAY_MSEC 100
+
+/* I2C bus slave address(ID) */
+#define RAYDIUM_I2C_EID (0x5A)
+#define RAYDIUM_I2C_NID (0x39)
+
+/* I2C R/W configuration literal */
+#define RAYDIUM_I2C_WRITE I2C_SMBUS_WRITE
+#define RAYDIUM_I2C_READ I2C_SMBUS_READ
+#define SYN_I2C_RETRY_TIMES 2
+#define MAX_WRITE_PACKET_SIZE 64
+#define MAX_READ_PACKET_SIZE 64
+
+/* PDA address and bit definition*/
+#define RAD_READ_FT_DATA_CMD 0x2000019C
+/* 1byte, disable:0x00 ; enable:0x20*/
+#define RAD_GESTURE_STATE_CMD 0x200005F4
+#define RAD_GESTURE_DISABLE 0x00
+#define RAD_GESTURE_ENABLE 0x20
+/* 4bytes, [0]:ready ; [1]:type ; [2]:direction*/
+#define RAD_GESTURE_RESULT_CMD 0x200005F0
+#define RAD_CHK_I2C_CMD 0x500009BC
+#define RAD_PDA2_CTRL_CMD 0x50000628
+#define RAD_ENABLE_PDA2 0x04
+#define RAD_ENABLE_SI2 0x02
+
+/* PDA literal */
+#define MASK_8BIT 0xFF
+#define RAD_I2C_PDA_ADDRESS_LENGTH 4
+#define PDA_MODE 1
+#define PDA2_MODE 2
+#define RAD_I2C_PDA_MODE_DISABLE 0x00
+#define RAD_I2C_PDA_MODE_ENABLE 0x80
+/* Using byte mode due to data might be not word-aligment */
+#define RAD_I2C_PDA_MODE_WORD_MODE 0x40
+#define RAD_I2C_PDA_2_MODE_DISABLE 0x20
+#define RAD_PALM_DISABLE 0x00
+#define RAD_PALM_ENABLE 0x01
+#define RAD_WAKE_UP 0x02
+#define RAYDIUM_TEST_FW 0x80
+#define RAYDIUM_TEST_PARA 0x40
+#define RAYDIUM_BOOTLOADER 0x20
+#define RAYDIUM_FIRMWARE 0x10
+#define RAYDIUM_PARA 0x08
+#define RAYDIUM_COMP 0x04
+#define RAYDIUM_BASELINE 0x02
+#define RAYDIUM_INIT 0x01
+#define FAIL 0
+#define ERROR -1
+#define SUCCESS 1
+#define DISABLE 0
+#define ENABLE 1
+
+/* PDA2 setting */
+/* Page 0 ~ Page A */
+#define MAX_PAGE_AMOUNT 11
+
+/* PDA2 address and setting definition*/
+#define RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR 0x00 /* only in Page 0 */
+#define RAYDIUM_PDA2_TCH_RPT_ADDR 0x01 /* only in Page 0 */
+#define RAYDIUM_PDA2_HOST_CMD_ADDR 0x02 /* only in Page 0 */
+#define RAYDIUM_PDA2_PALM_AREA_ADDR 0x03 /* only in Page 0 */
+#define RAYDIUM_PDA2_GESTURE_RPT_ADDR 0x04 /* only in Page 0 */
+#define RAYDIUM_PDA2_PALM_STATUS_ADDR 0x05 /* only in Page 0 */
+#define RAYDIUM_PDA2_FW_VERSION_ADDR 0x06 /* only in Page 0 */
+#define RAYDIUM_PDA2_PANEL_VERSION_ADDR 0x07 /* only in Page 0 */
+#define RAYDIUM_PDA2_DISPLAY_INFO_ADDR 0x08 /* only in Page 0 */
+#define RAYDIUM_PDA2_PDA_CFG_ADDR 0x09 /* only in Page 0 */
+#define RAYDIUM_PDA2_RAWDATA_ADDR 0x0B /* only in Page 0 */
+/* Page 0 ~ Page 9 will be directed to Page 0 */
+#define RAYDIUM_PDA2_PAGE_ADDR 0x0A
+#define RAYDIUM_PDA2_PAGE_0 0x00
+/* temporary switch to PDA once */
+#define RAYDIUM_PDA2_ENABLE_PDA 0x0A
+/* permanently switch to PDA mode */
+#define RAYDIUM_PDA2_2_PDA (MAX_PAGE_AMOUNT + 2)
+
+/* Raydium host cmd */
+#define RAYDIUM_HOST_CMD_NO_OP 0x00
+#define RAYDIUM_HOST_CMD_PWR_SLEEP 0x30
+#define RAYDIUM_HOST_CMD_DISPLAY_MODE 0x33
+#define RAYDIUM_HOST_CMD_CALIBRATION 0x5C
+#define RAYDIUM_HOST_CMD_TP_MODE 0x60
+#define RAYDIUM_HOST_CMD_FT_MODE 0x61
+
+/* PDA2 literal */
+/* entry byte + target page byte */
+#define RAYDIUM_I2C_PDA2_PAGE_LENGTH 2
+
+
+/* Touch report */
+#define MAX_TOUCH_NUM 2
+#define MAX_REPORT_PACKET_SIZE 35
+#define MAX_TCH_STATUS_PACKET_SIZE 4
+#define PRESS_MAX 0xFFFF
+#define WIDTH_MAX 0xFFFF
+#define BYTE_SHIFT 8
+
+/* FW update literal */
+#define RAYDIUM_FW_BIN_PATH_LENGTH 256
+
+#define RAD_BOOT_1X_SIZE 0x800
+#define RAD_INIT_1X_SIZE 0x200
+#define RAD_FW_1X_SIZE 0x5000
+#define RAD_PARA_1X_SIZE 0xE4
+#define RAD_TESTFW_1X_SIZE 0x5600
+
+#define RAD_BOOT_2X_SIZE 0x800
+#define RAD_INIT_2X_SIZE 0x200
+#define RAD_FW_2X_SIZE 0x6200
+#define RAD_PARA_2X_SIZE 0x15C
+#define RAD_TESTFW_2X_SIZE (RAD_FW_2X_SIZE + RAD_PARA_2X_SIZE + 4)
+
+#define RAD_CMD_UPDATE_BIN 0x80
+#define RAD_CMD_UPDATE_END 0x81
+#define RAD_CMD_BURN_FINISH 0x82
+
+/* FT APK literal */
+#define RAD_HOST_CMD_POS 0x00
+#define RAD_FT_CMD_POS 0x01
+#define RAD_FT_CMD_LENGTH 0x02
+
+/* FT APK data type */
+#define RAYDIUM_FT_UPDATE 0x01
+
+/*Raydium system flag*/
+#define INT_FLAG 0x01
+#define ENG_MODE 0x02
+
+/* define display mode */
+#define ACTIVE_MODE 0x00
+#define AMBIENT_MODE 0x01
+#define SLEEP_MODE 0x02
+
+/* Enable sysfs */
+#define CONFIG_RM_SYSFS_DEBUG
+
+/* Gesture switch */
+#define GESTURE_EN
+
+/* Enable FW update */
+/* #define FW_UPDATE_EN */
+/* #define FW_MAPPING_EN */
+#define HOST_NOTIFY_EN
+#define MSM_NEW_VER
+
+/* enable ESD */
+/* #define ESD_SOLUTION_EN */
+/* #define ENABLE_DUMP_DATA */
+/* #define ENABLE_FLASHLOG_BACKUP */
+#ifdef ENABLE_DUMP_DATA
+#define DATA_MAP_5_5 0
+#endif
+
+
+
+#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
+#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend"
+#define PINCTRL_STATE_RELEASE "pmx_ts_release"
+
+#if defined(CONFIG_TOUCHSCREEN_RM_TS_SELFTEST)
+#define RAD_SELFTEST
+#endif
+
+struct raydium_ts_data {
+ unsigned int irq;
+ unsigned int irq_gpio;
+ unsigned int rst_gpio;
+ unsigned int x_max;
+ unsigned int y_max;
+#ifdef FILTER_POINTS
+ unsigned int x_pos[2];
+ unsigned int y_pos[2];
+ unsigned int last_x_pos[2];
+ unsigned int last_y_pos[2];
+#else
+ unsigned int x_pos[2];
+ unsigned int y_pos[2];
+#endif
+ unsigned int pressure;
+ unsigned int is_suspend;
+ unsigned int is_sleep;
+#ifdef GESTURE_EN
+ unsigned int is_palm;
+#endif
+ unsigned char u8_max_touchs;
+
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct mutex lock;
+ struct work_struct work;
+ struct workqueue_struct *workqueue;
+ struct irq_desc *irq_desc;
+ bool irq_enabled;
+ bool irq_wake;
+
+#if defined(CONFIG_FB)
+ struct notifier_block fb_notif;
+ int blank;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ struct early_suspend early_suspend;
+#endif /*end of CONFIG_FB*/
+
+ /*struct regulator *vdd;*/
+ struct regulator *vcc_i2c;
+ unsigned int fw_version;
+ unsigned short id;
+ char *vcc_name;
+#ifdef MSM_NEW_VER
+ struct pinctrl *ts_pinctrl;
+ struct pinctrl_state *pinctrl_state_active;
+ struct pinctrl_state *pinctrl_state_suspend;
+ struct pinctrl_state *pinctrl_state_release;
+#endif /*end of MSM_NEW_VER*/
+
+#ifdef ENABLE_DUMP_DATA
+ struct delayed_work dump_work;
+
+#endif /*end of ENABLE_DUMP_DATA*/
+
+};
+struct raydium_platform_data {
+ char *vdd_name;
+ int irq_gpio_number;
+ int reset_gpio_number;
+ int x_max;
+ int y_max;
+};
+
+struct raydium_ts_platform_data {
+ char *name;
+ u32 irqflags;
+ u32 irq_gpio;
+ u32 irq_gpio_flags;
+ u32 reset_gpio;
+ u32 reset_gpio_flags;
+ u32 x_max;
+ u32 y_max;
+ u32 x_min;
+ u32 y_min;
+ u32 hard_rst_dly;
+ u32 soft_rst_dly;
+ u32 num_max_touches;
+ u32 fw_id;
+};
+
+/* TODO: Using struct+memcpy instead of array+offset*/
+enum raydium_pt_report_status {
+ POS_SEQ = 0,/*1:touch, 0:no touch*/
+ POS_PT_AMOUNT,
+ POS_GES_STATUS,
+ POS_FW_STATE,
+};
+
+enum raydium_pt_report_idx {
+ POS_PT_ID = 0,
+ POS_X_L,
+ POS_X_H,
+ POS_Y_L,
+ POS_Y_H,
+ POS_PRESSURE_L,
+ POS_PRESSURE_H,
+ POS_WX_L,
+ POS_WX_H,
+ POS_WY_L,
+ POS_WY_H,
+ LEN_PT = 11
+};
+
+extern int raydium_read_touchdata(unsigned char *tp_status, unsigned char *buf);
+extern unsigned char raydium_mem_table_setting(void);
+extern int wait_fw_state(struct i2c_client *client, unsigned int u32_addr,
+ unsigned int u32_state, unsigned long u32_delay_us,
+ unsigned short u16_retry);
+extern int wait_irq_state(struct i2c_client *client,
+ unsigned int u32_retry_time,
+ unsigned int u32_delay_us);
+extern void raydium_irq_control(bool enable);
+
+extern int raydium_i2c_mode_control(struct i2c_client *client,
+ unsigned char u8_mode);
+extern int raydium_i2c_pda_read(struct i2c_client *client,
+ unsigned int u32_addr, unsigned char *u8_r_data,
+ unsigned short u16_length);
+extern int raydium_i2c_pda_write(struct i2c_client *client,
+ unsigned int u32_addr, unsigned char *u8_w_data,
+ unsigned short u16_length);
+extern int raydium_i2c_pda2_read(struct i2c_client *client,
+ unsigned char u8_addr,
+ unsigned char *u8_r_data,
+ unsigned short u16_length);
+extern int raydium_i2c_pda2_write(struct i2c_client *client,
+ unsigned char u8_addr,
+ unsigned char *u8_w_data,
+ unsigned short u16_length);
+extern int raydium_i2c_pda2_set_page(struct i2c_client *client,
+ unsigned int is_suspend,
+ unsigned char u8_page);
+extern unsigned char raydium_selftest_stop_mcu(struct i2c_client *client);
+extern int raydium_burn_comp(struct i2c_client *client);
+extern int raydium_burn_fw(struct i2c_client *client);
+extern int raydium_fw_upgrade_with_bin_file(struct i2c_client *client,
+ char *arguments,
+ size_t count,
+ struct device *dev);
+extern int raydium_load_test_fw(struct i2c_client *client);
+extern int raydium_fw_update_check(unsigned short u16_i2c_data);
+extern int raydium_i2c_pda_set_address(unsigned int u32_address,
+ unsigned char u8_mode);
+extern unsigned char raydium_mem_table_init(unsigned short u16_id);
+extern unsigned char raydium_id_init(unsigned char u8_type);
+
+#ifdef RAD_SELFTEST
+extern int raydium_do_selftest(void);
+#endif
+int raydium_esd_check(void);
+
+extern struct attribute *raydium_attributes[];
+extern const struct attribute_group raydium_attr_group;
+
+extern unsigned char g_u8_raydium_flag;
+extern unsigned char g_u8_addr;
+extern unsigned char g_u8_i2c_mode;
+extern unsigned char g_u8_upgrade_type;
+extern unsigned char g_u8_raw_data_type;
+extern unsigned int g_u32_raw_data_len; /* 72 bytes*/
+extern unsigned int g_u32_length;
+extern unsigned long g_u32_addr;
+extern unsigned char *g_rad_fw_image, *g_rad_init_image;
+extern unsigned char *g_rad_boot_image, *g_rad_para_image;
+extern unsigned char *g_rad_testfw_image, *g_rad_testpara_image;
+extern unsigned char g_u8_table_setting, g_u8_table_init;
+extern unsigned int g_u32_driver_version;
+extern unsigned char g_u8_resetflag;
+extern struct raydium_ts_data *g_raydium_ts;
+
+#endif
+#endif /*__LINUX_RAYDIUM_H*/
+
+MODULE_AUTHOR("Raydium");
+MODULE_DESCRIPTION("Raydium TouchScreen driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/touchscreen/raydium_wt030/raydium_fw_update.c b/drivers/input/touchscreen/raydium_wt030/raydium_fw_update.c
new file mode 100644
index 0000000..6cd9bd7
--- /dev/null
+++ b/drivers/input/touchscreen/raydium_wt030/raydium_fw_update.c
@@ -0,0 +1,1844 @@
+/* drivers/input/touchscreen/raydium_wt030/raydium_fw_update.c
+ *
+ * Raydium TouchScreen driver.
+ *
+ * Copyright (c) 2010 Raydium tech Ltd.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/unistd.h>
+#include <linux/uaccess.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/device.h>
+#include <asm/traps.h>
+#include <linux/firmware.h>
+#include "raydium_driver.h"
+#include "rad_fw_image_20.h"
+#if defined(FW_MAPPING_EN)
+#include "rad_fw_image_21.h"
+#endif
+
+#ifdef ENABLE_FLASHLOG_BACKUP
+unsigned char raydium_turn_on_flash_2X(struct i2c_client *client)
+{
+ unsigned int u32_read = 0;
+ unsigned char u8_buf[4];
+ /*Turn on Flash*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ if (raydium_i2c_pda_write(client, 0x50000624, u8_buf, 4) == ERROR)
+ return ERROR;
+
+ u8_buf[0] = 0x20;
+ if (raydium_i2c_pda_write(client, 0x50000914, u8_buf, 4) == ERROR)
+ return ERROR;
+
+ return SUCCESS;
+}
+
+unsigned char raydium_read_fpc_flash(struct i2c_client *client,
+ unsigned int u32_addr, unsigned char *u8_r_data)
+{
+ unsigned int u32_read;
+ unsigned char u8_buf[4];
+
+ pr_info("[touch]raydium_read_fpc_flash\n");
+
+ if (raydium_i2c_pda_read(client, 0x40000000, u8_buf, 4) == ERROR)
+ return ERROR;
+
+ u8_buf[0] |= 0x40;
+ if (raydium_i2c_pda_write(client, 0x40000000, u8_buf, 4) == ERROR)
+ return ERROR;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ if (raydium_i2c_pda_write(client, 0x50000624, u8_buf, 4) == ERROR)
+ return ERROR;
+
+ u8_buf[0] = (u32_addr & 0x000000FF);
+ u8_buf[1] = ((u32_addr & 0x0000FF00) >> 8);
+ u8_buf[2] = ((u32_addr & 0x00FF0000) >> 16);
+ u8_buf[3] = ((u32_addr & 0xFF000000) >> 24);
+
+ if (raydium_i2c_pda_write(client, 0x50000910, u8_buf, 4) == ERROR)
+ return ERROR;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x40;
+
+ if (raydium_i2c_pda_write(client, 0x50000914, u8_buf, 4) == ERROR)
+ return ERROR;
+
+ usleep_range(950, 1050);
+
+ if (raydium_i2c_pda_read(client, 0x5000093C, u8_r_data, 4) == ERROR)
+ return ERROR;
+
+ return SUCCESS;
+}
+
+unsigned char raydium_read_flash_log(void)
+{
+ unsigned char u8_buf[4];
+ unsigned int u32_readbuf;
+ unsigned char u8_ret = 0;
+ unsigned char u8_logcount = 0;
+ unsigned int u32_temp = 0;
+ unsigned char u8_i = 0, u8_j = 0;
+
+ raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend , RAYDIUM_PDA2_2_PDA);
+ g_u8_i2c_mode = PDA_MODE;
+ pr_info("[touch]Disable PDA2_MODE\n");
+
+ if ((g_raydium_ts->id & 0x2000) != 0)
+ raydium_turn_on_flash_2X(g_raydium_ts->client);
+
+ for (u8_i = 0; u8_i < 4; u8_i++) {
+ u32_temp = (0x9000 + (u8_i*4));
+ raydium_read_fpc_flash(g_raydium_ts->client, u32_temp, &u32_readbuf);
+ if (u8_i == 0 && u32_readbuf == 0xFFFFFFFF) {
+ pr_info("[touch]Raydium flash no log\n");
+ return FAIL;
+ }
+ pr_info("[touch]Raydium flash 0x%x = 0x%x\n",
+ u32_temp, u32_readbuf);
+ u32_readbuf = u32_readbuf & (~u32_readbuf + 1);
+ pr_info("[touch]Raydium flash reverse = 0x%x\n",
+ u32_readbuf);
+ u32_temp = 1;
+ u8_j = 0;
+ while (u32_readbuf != u32_temp) {
+ u8_j++;
+ u32_temp <<= 1;
+ if (u8_j == 32)
+ break;
+ }
+ if (u8_i == 0) {
+ if ((u8_j > 0) && (u8_j < 32)) {
+ u8_logcount = u8_i*32 + u8_j;
+ pr_info("[touch]logcount = Log%d\n",
+ (u8_logcount-1));
+ break;
+ }
+ } else {
+ if (u8_j < 32) {
+ u8_logcount = u8_i*32 + u8_j;
+ pr_info("[touch]logcount = Log%d\n",
+ (u8_logcount-1));
+ break;
+ }
+ }
+ }
+
+ if (u8_logcount != 0) {
+ u32_temp = (0x9014 + (u8_logcount-1) * 48);
+ raydium_read_fpc_flash(g_raydium_ts->client, u32_temp, u8_buf);
+ pr_info("[touch]Rad log fw version 0x%x.0x%x.0x%x.0x%x\n",
+ u8_buf[0], u8_buf[1], u8_buf[2], u8_buf[3]);
+ if ((g_raydium_ts->id & 0x2000) != 0)
+ g_raydium_ts->id = 0x2000 | ((u8_buf[0] & 0xF) << 8) | u8_buf[1];
+
+ return SUCCESS;
+ }
+ return FAIL;
+}
+#endif
+unsigned char raydium_mem_table_init(unsigned short u16_id)
+{
+ unsigned int u8_ret = 0;
+
+ pr_info("[touch]Raydium table init 0x%x\n", u16_id);
+
+ if ((u16_id & 0x2000) != 0) {
+ g_rad_boot_image = kzalloc(RAD_BOOT_2X_SIZE, GFP_KERNEL);
+ g_rad_init_image = kzalloc(RAD_INIT_2X_SIZE, GFP_KERNEL);
+ g_rad_fw_image = kzalloc(RAD_FW_2X_SIZE, GFP_KERNEL);
+ g_rad_para_image = kzalloc(RAD_PARA_2X_SIZE + 4, GFP_KERNEL);
+ g_rad_testfw_image = kzalloc(RAD_TESTFW_2X_SIZE, GFP_KERNEL);
+ g_rad_testpara_image = kzalloc(RAD_PARA_2X_SIZE + 4,
+ GFP_KERNEL);
+ g_u8_table_init = SUCCESS;
+ u8_ret = SUCCESS;
+ }
+
+ return u8_ret;
+}
+
+unsigned char raydium_mem_table_setting(void)
+{
+ unsigned char u8_ret = SUCCESS;
+#ifdef ENABLE_FLASHLOG_BACKUP
+ unsigned char u8_buf[4];
+ static unsigned char u8_readflash;
+#endif
+
+ pr_info("[touch]Raydium ID is 0x%x\n", g_raydium_ts->id);
+
+ switch (g_raydium_ts->id) {
+ case RAD_20:
+ memcpy(g_rad_boot_image, u8_rad_boot_20, RAD_BOOT_2X_SIZE);
+ memcpy(g_rad_init_image, u8_rad_init_20, RAD_INIT_2X_SIZE);
+ memcpy(g_rad_fw_image, u8_rad_fw_20, RAD_FW_2X_SIZE);
+ memcpy(g_rad_testfw_image, u8_rad_testfw_20, RAD_FW_2X_SIZE);
+ memcpy(g_rad_testfw_image + RAD_FW_2X_SIZE,
+ u8_rad_testpara_20, RAD_PARA_2X_SIZE + 4);
+ if (g_rad_boot_image[0x82] >= 4) {
+ memcpy(g_rad_para_image,
+ u8_rad_para_20,
+ RAD_PARA_2X_SIZE + 4);
+ memcpy(g_rad_testpara_image,
+ u8_rad_testpara_20,
+ RAD_PARA_2X_SIZE + 4);
+ } else {
+ memcpy(g_rad_para_image,
+ u8_rad_para_20,
+ RAD_PARA_2X_SIZE);
+ memcpy(g_rad_testpara_image,
+ u8_rad_testpara_20,
+ RAD_PARA_2X_SIZE);
+ }
+ break;
+#if defined(FW_MAPPING_EN)
+ case RAD_21:
+ memcpy(g_rad_boot_image, u8_rad_boot_21, RAD_BOOT_2X_SIZE);
+ memcpy(g_rad_init_image, u8_rad_init_21, RAD_INIT_2X_SIZE);
+ memcpy(g_rad_fw_image, u8_rad_fw_21, RAD_FW_2X_SIZE);
+ memcpy(g_rad_testfw_image, u8_rad_testfw_21, RAD_FW_2X_SIZE);
+ memcpy(g_rad_testfw_image + RAD_FW_2X_SIZE,
+ u8_rad_testpara_21,
+ RAD_PARA_2X_SIZE + 4);
+ if (g_rad_boot_image[0x82] >= 4) {
+ memcpy(g_rad_para_image,
+ u8_rad_para_21,
+ RAD_PARA_2X_SIZE + 4);
+ memcpy(g_rad_testpara_image,
+ u8_rad_testpara_21,
+ RAD_PARA_2X_SIZE + 4);
+ } else {
+ memcpy(g_rad_para_image,
+ u8_rad_para_21,
+ RAD_PARA_2X_SIZE);
+ memcpy(g_rad_testpara_image,
+ u8_rad_testpara_21,
+ RAD_PARA_2X_SIZE);
+ }
+ break;
+#endif
+ default:
+ pr_info("[touch]mapping ic setting use default fw\n");
+#ifdef ENABLE_FLASHLOG_BACKUP
+ if (!u8_readflash) {
+ u8_ret = raydium_read_flash_log();
+ u8_readflash = true;
+
+ raydium_i2c_pda_read(g_raydium_ts->client,
+ RAD_PDA2_CTRL_CMD,
+ u8_buf,
+ 4);
+ u8_buf[0] |= RAD_ENABLE_PDA2 | RAD_ENABLE_SI2;
+ raydium_i2c_pda_write(g_raydium_ts->client,
+ RAD_PDA2_CTRL_CMD,
+ u8_buf,
+ 4);
+ raydium_i2c_pda_set_address(0x50000628, DISABLE);
+
+ g_u8_i2c_mode = PDA2_MODE;
+ pr_info("[touch]Enable PDA2_MODE\n");
+ raydium_mem_table_setting();
+ } else {
+ if ((g_raydium_ts->id & 0x2000) != 0) {
+ memcpy(g_rad_boot_image,
+ u8_rad_boot_20,
+ RAD_BOOT_2X_SIZE);
+ memcpy(g_rad_init_image,
+ u8_rad_init_20,
+ RAD_INIT_2X_SIZE);
+ memcpy(g_rad_fw_image,
+ u8_rad_fw_20,
+ RAD_FW_2X_SIZE);
+ memcpy(g_rad_testfw_image,
+ u8_rad_testfw_20,
+ RAD_FW_2X_SIZE);
+ memcpy(g_rad_testfw_image + RAD_FW_2X_SIZE,
+ u8_rad_testpara_20,
+ RAD_PARA_2X_SIZE + 4);
+ if (g_rad_boot_image[0x82] >= 4) {
+ memcpy(g_rad_para_image,
+ u8_rad_para_20,
+ RAD_PARA_2X_SIZE + 4);
+ memcpy(g_rad_testpara_image,
+ u8_rad_testpara_20,
+ RAD_PARA_2X_SIZE + 4);
+ } else {
+ memcpy(g_rad_para_image,
+ u8_rad_para_20,
+ RAD_PARA_2X_SIZE);
+ memcpy(g_rad_testpara_image,
+ u8_rad_testpara_20,
+ RAD_PARA_2X_SIZE);
+ }
+ g_raydium_ts->id = RAD_20;
+ }
+ }
+ u8_ret = SUCCESS;
+ break;
+#else
+ if ((g_raydium_ts->id & 0x2000) != 0) {
+ memcpy(g_rad_boot_image,
+ u8_rad_boot_20,
+ RAD_BOOT_2X_SIZE);
+ memcpy(g_rad_init_image,
+ u8_rad_init_20,
+ RAD_INIT_2X_SIZE);
+ memcpy(g_rad_fw_image,
+ u8_rad_fw_20,
+ RAD_FW_2X_SIZE);
+ memcpy(g_rad_testfw_image,
+ u8_rad_testfw_20,
+ RAD_FW_2X_SIZE);
+ memcpy(g_rad_testfw_image + RAD_FW_2X_SIZE,
+ u8_rad_testpara_20,
+ RAD_PARA_2X_SIZE + 4);
+ if (g_rad_boot_image[0x82] >= 4) {
+ memcpy(g_rad_para_image,
+ u8_rad_para_20,
+ RAD_PARA_2X_SIZE + 4);
+ memcpy(g_rad_testpara_image,
+ u8_rad_testpara_20,
+ RAD_PARA_2X_SIZE + 4);
+ } else {
+ memcpy(g_rad_para_image,
+ u8_rad_para_20,
+ RAD_PARA_2X_SIZE);
+ memcpy(g_rad_testpara_image,
+ u8_rad_testpara_20,
+ RAD_PARA_2X_SIZE);
+ }
+ g_raydium_ts->id = RAD_20;
+ }
+ u8_ret = SUCCESS;
+ break;
+#endif
+ }
+
+ g_u8_table_setting = 0;
+ return u8_ret;
+}
+
+unsigned char raydium_id_init(unsigned char u8_type)
+{
+ unsigned int u8_ret = SUCCESS;
+ u8_ret = 0;
+
+
+ switch (u8_type) {
+ case 0:
+ g_raydium_ts->id = RAD_20;
+ u8_ret = SUCCESS;
+ break;
+#if defined(FW_MAPPING_EN)
+ case 1:
+ g_raydium_ts->id = RAD_21;
+ u8_ret = SUCCESS;
+ break;
+#endif
+ }
+
+
+ return u8_ret;
+}
+
+static unsigned int bits_reverse(unsigned int u32_num, unsigned int bit_num)
+{
+ unsigned int reverse = 0, u32_i;
+
+ for (u32_i = 0; u32_i < bit_num; u32_i++) {
+ if (u32_num & (1 << u32_i))
+ reverse |= 1 << ((bit_num - 1) - u32_i);
+ }
+ return reverse;
+}
+
+static unsigned int rc_crc32(const char *buf, unsigned int u32_len,
+ unsigned int u32_crc)
+{
+ unsigned int u32_i;
+ unsigned char u8_flash_byte, u8_current, u8_j;
+
+ for (u32_i = 0; u32_i < u32_len; u32_i++) {
+ u8_flash_byte = buf[u32_i];
+ u8_current = (unsigned char)bits_reverse(u8_flash_byte, 8);
+ for (u8_j = 0; u8_j < 8; u8_j++) {
+ if ((u32_crc ^ u8_current) & 0x01)
+ u32_crc = (u32_crc >> 1) ^ 0xedb88320;
+ else
+ u32_crc >>= 1;
+ u8_current >>= 1;
+ }
+ }
+ return u32_crc;
+}
+
+int wait_fw_state(struct i2c_client *client, unsigned int u32_addr,
+ unsigned int u32_state, unsigned long u32_delay_us,
+ unsigned short u16_retry)
+{
+ unsigned char u8_buf[4];
+ unsigned int u32_read_data;
+ unsigned int u32_min_delay_us = u32_delay_us - 500;
+ unsigned int u32_max_delay_us = u32_delay_us + 500;
+
+ do {
+ if (raydium_i2c_pda_read(client, u32_addr, u8_buf, 4) == ERROR)
+ return ERROR;
+
+ memcpy(&u32_read_data, u8_buf, 4);
+ u16_retry--;
+ usleep_range(u32_min_delay_us, u32_max_delay_us);
+ } while ((u32_read_data != u32_state) && (u16_retry != 0));
+
+ if (u32_read_data != u32_state) {
+ pr_err("[touch]confirm data error : 0x%x\n", u32_read_data);
+ return ERROR;
+ }
+
+ return SUCCESS;
+}
+
+int wait_irq_state(struct i2c_client *client, unsigned int retry_time,
+ unsigned int u32_delay_us)
+{
+ int i32_ret = SUCCESS;
+ unsigned int u32_retry;
+ unsigned int u32_irq_value;
+ unsigned int u32_min_delay_us = u32_delay_us - 500;
+ unsigned int u32_max_delay_us = u32_delay_us + 500;
+
+ u32_retry = retry_time;
+ u32_irq_value = 0;
+ while (u32_retry != 0 && u32_irq_value != 1) {
+ u32_irq_value = gpio_get_value(g_raydium_ts->irq_gpio);
+ usleep_range(u32_min_delay_us, u32_max_delay_us);
+ u32_retry--;
+ }
+ pr_info("[touch]irq_value is %d\n", u32_irq_value);
+
+ if (u32_retry == 0) {
+ pr_err("[touch]%s, FW not ready, retry error!\n", __func__);
+ i32_ret = ERROR;
+ }
+
+ return i32_ret;
+}
+
+int raydium_do_software_reset(struct i2c_client *client)
+{
+ int i32_ret = SUCCESS;
+
+ unsigned char u8_buf[4];
+
+ /*SW reset*/
+ g_u8_resetflag = true;
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x01;
+ pr_info("[touch]SW reset\n");
+ i32_ret = raydium_i2c_pda_write(client, 0x40000004, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit;
+
+ if ((g_raydium_ts->id & 0x2000) != 0)
+ msleep(25);
+exit:
+ return i32_ret;
+}
+
+static int raydium_check_fw_ready(struct i2c_client *client)
+{
+ int i32_ret = SUCCESS;
+ unsigned int u32_retry = 400;
+ unsigned char u8_buf[4];
+
+ u8_buf[1] = 0;
+ while (u8_buf[1] != 0x40 && u32_retry != 0) {
+ i32_ret = raydium_i2c_pda_read(client, 0x50000918, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit;
+
+ u32_retry--;
+ usleep_range(4500, 5500);
+ }
+
+ if (u32_retry == 0) {
+ pr_err("[touch]%s, FW not ready, retry error!\n", __func__);
+ i32_ret = ERROR;
+ } else {
+ pr_info("[touch]%s, FW is ready!!\n", __func__);
+ usleep_range(4500, 5500);
+ }
+
+exit:
+ return i32_ret;
+}
+
+int set_skip_load(struct i2c_client *client)
+{
+ int i32_ret = SUCCESS;
+ unsigned int u32_retry_time = 1000;
+ unsigned char u8_buf[4];
+
+ /*Skip load*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x10;
+ u8_buf[1] = 0x08;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000918, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_do_software_reset(client);
+ if (i32_ret < 0)
+ pr_err("[touch]%s, SW reset error!\n", __func__);
+
+ i32_ret = wait_fw_state(client, 0x20000214, 0x82, 2000, u32_retry_time);
+ if (i32_ret < 0)
+ pr_err("[touch]%s, wait_fw_state error!\n", __func__);
+
+exit_upgrade:
+ return i32_ret;
+}
+
+/*check pram crc32*/
+static int raydium_check_pram_crc_2X(struct i2c_client *client,
+ unsigned int u32_addr,
+ unsigned int u32_len)
+{
+ int i32_ret = SUCCESS;
+ unsigned int u32_crc_addr = u32_addr + u32_len;
+ unsigned int u32_end_addr = u32_crc_addr - 1;
+ unsigned int u32_crc_result, u32_read_data;
+ unsigned int u32_retry = 400;
+ unsigned char u8_buf[4], u8_retry = 3;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = (unsigned char)(u32_addr & 0xFF);
+ u8_buf[1] = (unsigned char)((u32_addr & 0xFF00) >> 8);
+ u8_buf[2] = (unsigned char)(u32_end_addr & 0xFF);
+ u8_buf[3] = (unsigned char)((u32_end_addr & 0xFF00) >> 8);
+
+ i32_ret = raydium_i2c_pda_write(client, 0x50000974, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_i2c_pda_read(client, 0x5000094C, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ u8_buf[3] |= 0x81;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000094C, u8_buf, 4);
+
+ while (u8_buf[3] != 0x80 && u32_retry != 0) {
+ i32_ret = raydium_i2c_pda_read(client, 0x5000094C, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ u32_retry--;
+ usleep_range(4500, 5500);
+ }
+ if (u32_retry == 0) {
+ pr_err("[touch]%s, Cal CRC not ready, retry error!\n",
+ __func__);
+ i32_ret = ERROR;
+ }
+
+ i32_ret = raydium_i2c_pda_read(client, 0x50000978, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ memcpy(&u32_crc_result, u8_buf, 4);
+ i32_ret = raydium_i2c_pda_read(client, u32_crc_addr, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ memcpy(&u32_read_data, u8_buf, 4);
+
+ while (u32_read_data != u32_crc_result && u8_retry > 0) {
+ i32_ret = raydium_i2c_pda_read(client, 0x50000978, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ memcpy(&u32_crc_result, u8_buf, 4);
+ usleep_range(1500, 2500);
+ u8_retry--;
+ }
+ if (u32_read_data != u32_crc_result) {
+ pr_err("[touch]check pram crc fail!!\n");
+ pr_err("[touch]u32_read_data 0x%x\n", u32_read_data);
+ pr_err("[touch]u32_crc_result 0x%x\n", u32_crc_result);
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ } else if (u8_retry != 3) {
+ pr_err("[touch]check pram crc pass!!\n");
+ pr_err("[touch]u8_retry : %d\n", u8_retry);
+ pr_err("[touch]u32_read_data 0x%x\n", u32_read_data);
+ pr_err("[touch]u32_crc_result 0x%x\n", u32_crc_result);
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+exit_upgrade:
+ return i32_ret;
+}
+
+/* upgrade firmware with image file */
+static int raydium_write_to_pram_2X(struct i2c_client *client,
+ unsigned int u32_fw_addr,
+ unsigned char u8_type)
+{
+ int i32_ret = ERROR;
+ unsigned int u32_fw_size = 0;
+ unsigned char *p_u8_firmware_data = NULL;
+ unsigned int u32_write_offset = 0;
+ unsigned short u16_write_length = 0;
+
+ switch (u8_type) {
+ case RAYDIUM_INIT:
+ u32_fw_size = 0x200;
+ p_u8_firmware_data = g_rad_init_image;
+ break;
+
+ case RAYDIUM_PARA:
+ u32_fw_size = 0x160;
+ p_u8_firmware_data = g_rad_para_image;
+ break;
+
+ case RAYDIUM_FIRMWARE:
+ u32_fw_size = 0x6200;
+ p_u8_firmware_data = g_rad_fw_image;
+ break;
+
+ case RAYDIUM_BOOTLOADER:
+ u32_fw_size = 0x800;
+ p_u8_firmware_data = g_rad_boot_image;
+ break;
+
+ case RAYDIUM_TEST_FW:
+ u32_fw_size = 0x6360;
+ p_u8_firmware_data = g_rad_testfw_image;
+ break;
+ }
+
+ u32_write_offset = 0;
+ while (u32_write_offset < u32_fw_size) {
+ if ((u32_write_offset + MAX_WRITE_PACKET_SIZE) < u32_fw_size)
+ u16_write_length = MAX_WRITE_PACKET_SIZE;
+ else
+ u16_write_length =
+ (unsigned short)(u32_fw_size - u32_write_offset);
+
+ i32_ret = raydium_i2c_pda_write(
+ client,
+ (u32_fw_addr + u32_write_offset),
+ (p_u8_firmware_data + u32_write_offset),
+ u16_write_length);
+ if (i32_ret < 0)
+ goto exit_upgrate;
+
+ u32_write_offset += (unsigned long)u16_write_length;
+ }
+ u32_fw_addr += u32_write_offset;
+
+exit_upgrate:
+ if (i32_ret < 0) {
+ pr_err("[touch]upgrade failed\n");
+ return i32_ret;
+ }
+ pr_info("[touch]upgrade success\n");
+ return 0;
+}
+
+/* upgrade firmware with image file */
+static int raydium_fw_upgrade_with_image(struct i2c_client *client,
+ unsigned int u32_fw_addr,
+ unsigned char u8_type)
+{
+ int i32_ret = ERROR;
+ unsigned int u32_fw_size = 0;
+ unsigned char *p_u8_firmware_data = NULL;
+ unsigned int u32_write_offset = 0;
+ unsigned short u16_write_length = 0;
+ unsigned int u32_checksum = 0xFFFFFFFF;
+
+ switch (u8_type) {
+ case RAYDIUM_INIT:
+ u32_fw_size = 0x1fc;
+ p_u8_firmware_data = g_rad_init_image;
+ break;
+ case RAYDIUM_PARA:
+ if ((g_raydium_ts->id & 0x2000) != 0)
+ u32_fw_size = 0x158;
+ p_u8_firmware_data = g_rad_para_image;
+ break;
+ case RAYDIUM_FIRMWARE:
+ if ((g_raydium_ts->id & 0x2000) != 0)
+ u32_fw_size = 0x61fc;
+ p_u8_firmware_data = g_rad_fw_image;
+ break;
+ case RAYDIUM_BOOTLOADER:
+ if ((g_raydium_ts->id & 0x2000) != 0)
+ u32_fw_size = 0x7FC;
+ p_u8_firmware_data = g_rad_boot_image;
+ break;
+ case RAYDIUM_TEST_FW:
+ if ((g_raydium_ts->id & 0x2000) != 0)
+ u32_fw_size = 0x635C;
+ p_u8_firmware_data = g_rad_testfw_image;
+ break;
+ }
+
+#if 1
+ pr_info("[touch]CRC 0x%08X\n",
+ *(unsigned int *)(p_u8_firmware_data + u32_fw_size));
+
+ u32_checksum = rc_crc32(p_u8_firmware_data,
+ u32_fw_size, u32_checksum);
+ u32_checksum = bits_reverse(u32_checksum, 32);
+ memcpy((p_u8_firmware_data + u32_fw_size), &u32_checksum, 4);
+ pr_info("[touch]CRC result 0x%08X\n", u32_checksum);
+#endif
+ u32_fw_size += 4;
+
+ u32_write_offset = 0;
+ while (u32_write_offset < u32_fw_size) {
+ if ((u32_write_offset + MAX_WRITE_PACKET_SIZE) < u32_fw_size)
+ u16_write_length = MAX_WRITE_PACKET_SIZE;
+ else
+ u16_write_length =
+ (unsigned short)
+ (u32_fw_size - u32_write_offset);
+
+ i32_ret = raydium_i2c_pda_write(
+ client,
+ (u32_fw_addr + u32_write_offset),
+ (p_u8_firmware_data + u32_write_offset),
+ u16_write_length);
+ if (i32_ret < 0)
+ goto exit_upgrate;
+
+ u32_write_offset += (unsigned long)u16_write_length;
+ }
+ u32_fw_addr += u32_write_offset;
+
+exit_upgrate:
+ if (i32_ret < 0) {
+ pr_err("[touch]upgrade failed\n");
+ return i32_ret;
+ }
+ pr_info("[touch]upgrade success\n");
+ return 0;
+}
+static int raydium_boot_upgrade_2X(struct i2c_client *client)
+{
+ int i32_ret = SUCCESS;
+ unsigned char u8_buf[4];
+
+ /*set mcu hold*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x20;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000918, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ u8_buf[0] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client, 0x40000004, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ msleep(25);
+
+ /*WRT boot-loader to PRAM first*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x50000900, u8_buf, 4);
+
+ /*Sending bootloader*/
+ i32_ret = raydium_write_to_pram_2X(client, 0x0000,
+ RAYDIUM_BOOTLOADER);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_check_pram_crc_2X(client, 0x000, 0x7FC);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*release mcu hold*/
+ /*Skip load*/
+ i32_ret = set_skip_load(client);
+ if (i32_ret < 0)
+ pr_err("[touch]%s, set skip_load error!\n", __func__);
+
+exit_upgrade:
+ return i32_ret;
+}
+
+/* Raydium fireware upgrade flow */
+static int raydium_fw_upgrade_2X(struct i2c_client *client,
+ unsigned char u8_type,
+ unsigned char u8_check_crc)
+{
+ int i32_ret = 0;
+ unsigned char u8_buf[4];
+ unsigned short u16_retry = 1000;
+
+ /*##### wait for boot-loader start #####*/
+ pr_info("[touch]Type is %x\n", u8_type);
+
+ /*read Boot version*/
+ if (raydium_i2c_pda_read(client, 0x80, u8_buf, 4) == ERROR)
+ return ERROR;
+ pr_info("[touch]Boot version is %x\n", u8_buf[2]);
+
+ if (u8_buf[2] >= 4) {
+ if (u8_type != RAYDIUM_COMP) {
+ /*set mcu hold*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x20;
+ i32_ret = raydium_i2c_pda_write(client,
+ 0x50000918,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ u8_buf[0] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client,
+ 0x40000004,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ msleep(25);
+ }
+
+ /*#start write data to PRAM*/
+ if (u8_type == RAYDIUM_FIRMWARE) {
+ /* unlock PRAM */
+ u8_buf[0] = 0x27;
+ i32_ret = raydium_i2c_pda_write(client,
+ 0x50000900,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_write_to_pram_2X(client, 0x800,
+ RAYDIUM_FIRMWARE);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_write_to_pram_2X(client, 0x6a00,
+ RAYDIUM_PARA);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_check_pram_crc_2X(client, 0x800,
+ 0x635C);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ } else if (u8_type == RAYDIUM_BOOTLOADER) {
+ /* unlock PRAM */
+ u8_buf[0] = 0x0E;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000900,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_write_to_pram_2X(client, 0x0800,
+ RAYDIUM_BOOTLOADER);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_write_to_pram_2X(client, 0x1000,
+ RAYDIUM_INIT);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_check_pram_crc_2X(client, 0x800,
+ 0x7FC);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_check_pram_crc_2X(client, 0x1000,
+ 0x1FC);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ }
+
+ if (u8_type != RAYDIUM_COMP) {
+ /*release mcu hold*/
+ /*Skip load*/
+ i32_ret = set_skip_load(client);
+ if (i32_ret < 0)
+ pr_err("[touch]%s, set skip_load error!\n",
+ __func__);
+ }
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000204, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000208, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x2000020C, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000218, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#confirm in burn mode*/
+ if (wait_fw_state(client, 0x20000214, 255,
+ 2000, u16_retry) == ERROR) {
+ pr_err("[touch]Error, confirm in burn mode\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*Clear BL_CRC*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x10;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000918, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = u8_type;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000904, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#set PRAM length (at 'h5000_090C)*/
+ if (u8_type == RAYDIUM_COMP) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x60;
+ u8_buf[1] = 0x6b;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000908,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x9c;
+ u8_buf[1] = 0x02;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000090C,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ } else if (u8_type == RAYDIUM_FIRMWARE) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x00;
+ u8_buf[1] = 0x08;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000908,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x5c;
+ u8_buf[1] = 0x63;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000090C,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ } else if (u8_type == RAYDIUM_BOOTLOADER) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x00;
+ u8_buf[1] = 0x08;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000908,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x00;
+ u8_buf[1] = 0x0A;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000090C,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ }
+
+ /*#set sync_data(0x20000200) = 0 as WRT data finish*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000200, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#wait for input unlock key*/
+ if (wait_fw_state(client, 0x20000210, 168, 1000,
+ u16_retry) == ERROR) {
+ pr_err("[touch]Error, wait for input unlock key\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*#unlock key*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xd7;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000938, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xa5;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000934, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x50000934, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xa5;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000934, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x50000938, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x50000624, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#wrt return data as unlock value*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xa8;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000214, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*pr_info("[touch]ready burn flash\n");*/
+
+ /*#clr sync_data(0x20000200) = 0 as finish*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000200, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /* wait erase/wrt finish
+ * confirm burning_state result (gu8I2CSyncData.burning_state =
+ * BURNING_WRT_FLASH_FINISH at 0x2000020C)
+ */
+ if (wait_fw_state(client, 0x2000020c, 6, 2000,
+ u16_retry) == ERROR) {
+ pr_err("[touch]Error, wait erase/wrt finish\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+ pr_info("[touch]Burn flash ok\n");
+
+ if (u8_check_crc) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000200,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#wait software reset finish*/
+ msleep(25);
+
+ /* wait sw reset finished 0x20000214 = 0x82 */
+ if (wait_fw_state(client, 0x20000214, 130, 2000,
+ u16_retry) == ERROR) {
+ pr_err("[touch]Error, wait sw reset finished\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*#set test_mode = 1*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000218,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#wait crc check finish*/
+ if (wait_fw_state(client, 0x20000208, 2,
+ 2000, u16_retry)
+ == ERROR) {
+ pr_err("[touch]Error, wait crc check finish\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*#crc check pass 0x20000214 = 0x81*/
+ if (wait_fw_state(client, 0x20000214, 0x81,
+ 2000, u16_retry)
+ == ERROR) {
+ pr_err("[touch]Error, confirm crc result\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+ }
+
+ } else {
+ /*#set main state as burning mode, normal init state*/
+ /* #sync_data:200h
+ * main_state:204h
+ * normal_state:208h
+ * burning_state:20Ch
+ */
+ /* #sync_data:210h
+ * cmd_type:210h
+ * ret_data:214h
+ * test_mode:218h
+ */
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000204, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000208, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x2000020C, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000218, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#confirm in burn mode*/
+ if (wait_fw_state(client, 0x50000900, 63,
+ 2000, u16_retry) == ERROR) {
+ pr_err("[touch]Error, confirm in burn mode\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*Clear BL_CRC*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x10;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000918, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#write PRAM relative data*/
+ /*#set PRAM type (at 0x50000904), wrt param code*/
+ /* #init_code:0x01,
+ * baseline:0x02
+ * COMP:0x04
+ * param:0x08
+ * FW:0x10
+ * bootloader:0x20
+ */
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = u8_type;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000904, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#set PRAM addr (at 'h5000_0908)*/
+ /* #init_code:0x800
+ * Baseline:0xA00
+ * COMP:0xCD4
+ * para:0xF1C
+ * FW:0x1000
+ * BOOT:0x5000
+ */
+ /*#set PRAM length (at 'h5000_090C)*/
+ if (u8_type == RAYDIUM_INIT) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x00;
+ u8_buf[1] = 0x6e;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000908,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x00;
+ u8_buf[1] = 0x02;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000090C,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ } else if (u8_type == RAYDIUM_BASELINE) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xcc;
+ u8_buf[1] = 0x6c;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000908,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x30;
+ u8_buf[1] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000090C,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ } else if (u8_type == RAYDIUM_COMP) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x60;
+ u8_buf[1] = 0x6b;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000908,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x9c;
+ u8_buf[1] = 0x02;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000090C,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ } else if (u8_type == RAYDIUM_PARA) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x00;
+ u8_buf[1] = 0x6a;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000908,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x5c;
+ u8_buf[1] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000090C,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ } else if (u8_type == RAYDIUM_FIRMWARE) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x00;
+ u8_buf[1] = 0x08;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000908,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x5c;
+ u8_buf[1] = 0x63;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000090C,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ } else if (u8_type == RAYDIUM_BOOTLOADER) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x00;
+ u8_buf[1] = 0x08;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000908,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x00;
+ u8_buf[1] = 0x0A;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000090C,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ }
+
+ /*#set sync_data(0x20000200) = 0 as WRT data finish*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000200, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#Wait bootloader check addr and PRAM unlock*/
+ /*#Confirm ret_data at 0x20000214 is SET_ADDR_READY*/
+ if (wait_fw_state(client, 0x20000214, 161,
+ 2000, u16_retry) == ERROR) {
+ pr_err("[touch]Error, SET_ADDR_READY\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*#Confirm cmd_type at 0x20000210 is WRT_PRAM_DATA*/
+ if (wait_fw_state(client, 0x20000210, 163,
+ 1000, u16_retry) == ERROR) {
+ pr_err("[touch]Error, WRT_PRAM_DATA\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*#start write data to PRAM*/
+ if (u8_type == RAYDIUM_INIT) {
+ i32_ret = raydium_fw_upgrade_with_image(client, 0x6E00,
+ RAYDIUM_INIT);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ } else if (u8_type == RAYDIUM_PARA) {
+ i32_ret = raydium_fw_upgrade_with_image(client, 0x6a00,
+ RAYDIUM_PARA);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ } else if (u8_type == RAYDIUM_FIRMWARE) {
+ i32_ret = raydium_fw_upgrade_with_image(client, 0x800,
+ RAYDIUM_FIRMWARE);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_fw_upgrade_with_image(client, 0x6a00,
+ RAYDIUM_PARA);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+
+ } else if (u8_type == RAYDIUM_BOOTLOADER) {
+ i32_ret = raydium_fw_upgrade_with_image(client, 0x0800,
+ RAYDIUM_BOOTLOADER);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_fw_upgrade_with_image(client, 0x1000,
+ RAYDIUM_INIT);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ }
+
+ /*
+ *set sync_data(0x20000200) = 0 as WRT data finish
+ *bootloader check checksum
+ */
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000200, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*
+ * wait(checksum okay) ACK cmd
+ * (gu8I2CSyncData.cmd_type=0xa5 at 0x20000210)
+ */
+ if (wait_fw_state(client, 0x20000210,
+ 165, 2000, u16_retry) == ERROR) {
+ pr_err("[touch]Error, WRT_CHECKSUM_OK\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*#confirm ACK cmd result(ret_data=0xa5 at 0x20000214)*/
+ if (wait_fw_state(client, 0x20000214,
+ 165, 1000, u16_retry) == ERROR) {
+ pr_err("[touch]Error, confirm ACK cmd result\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*
+ * set ACK return data = 0x5A
+ * adb shell "echo 20000210 1 A5 > /sys/bus/i2c/drivers/
+ * raydium_ts/1-0039 raydium_i2c_pda_access"
+ * above command can be ignored, due to previous while loop
+ * has check its value.
+ */
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xa5;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000210, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x5a;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000214, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#clr sync_data(0x20000200) = 0 as finish*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000200, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#wait for input unlock key*/
+ if (wait_fw_state(client, 0x20000210,
+ 168, 1000, u16_retry) == ERROR) {
+ pr_err("[touch]Error, wait for input unlock key\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*#unlock key*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xd7;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000938, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xa5;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000934, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x50000934, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xa5;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000934, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x50000938, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x50000624, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#wrt return data as unlock value*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0xa8;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000214, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*pr_info("[touch]ready burn flash\n");*/
+
+ /*#clr sync_data(0x20000200) = 0 as finish*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000200, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /* wait erase/wrt finish
+ * confirm burning_state result (gu8I2CSyncData.burning_state =
+ * BURNING_WRT_FLASH_FINISH at 0x2000020C)
+ */
+ if (wait_fw_state(client, 0x2000020c,
+ 6, 2000, u16_retry) == ERROR) {
+ dev_err(&g_raydium_ts->client->dev,
+ "[touch]Error, wait erase/wrt finish\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+ pr_info("[touch]Burn flash ok\n");
+
+
+ if (u8_type == RAYDIUM_BOOTLOADER) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x10;
+ u8_buf[1] = 0x08;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000918,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ }
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000200, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#wait software reset finish*/
+ msleep(25);
+
+ /* wait sw reset finished 0x20000214 = 0x82 */
+ if (wait_fw_state(client, 0x20000214,
+ 130, 2000, u16_retry) == ERROR) {
+ pr_err("[touch]Error, wait sw reset finished\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ if (u8_type == RAYDIUM_BASELINE || u8_type == RAYDIUM_COMP ||
+ u8_type == RAYDIUM_FIRMWARE || u8_check_crc == 1) {
+ /*#set test_mode = 1*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x01;
+ i32_ret = raydium_i2c_pda_write(client, 0x20000218,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*#wait crc check finish*/
+ if (wait_fw_state(client, 0x20000208, 2,
+ 2000, u16_retry) == ERROR) {
+ pr_err("[touch]Error, wait crc check finish\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ /*#crc check pass 0x20000214 = 0x81*/
+ if (wait_fw_state(client, 0x20000214, 0x81,
+ 2000, u16_retry)
+ == ERROR) {
+ pr_err("[touch]Error, confirm crc result\n");
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+ }
+ }
+
+ /*#run to next step*/
+ pr_info("[touch]Type 0x%x => Pass\n", u8_type);
+
+ if (u8_check_crc) {
+ /*#clr sync para*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ i32_ret = raydium_i2c_pda_write(client, 0x20000210, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_i2c_pda_write(client, 0x20000214, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_i2c_pda_write(client, 0x20000218, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+
+ i32_ret = raydium_i2c_pda_write(client, 0x20000200, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ usleep_range(4500, 5500);
+ raydium_i2c_pda_set_address(0x50000628, DISABLE);
+
+ g_u8_i2c_mode = PDA2_MODE;
+
+ pr_info("[touch]Burn FW finish!\n");
+ }
+
+exit_upgrade:
+ return i32_ret;
+}
+
+int raydium_burn_fw(struct i2c_client *client)
+{
+ int i32_ret = 0;
+
+ g_u8_resetflag = true;
+ if ((g_raydium_ts->id & 0x2000) != 0) {
+ pr_info("[touch]start burn function!\n");
+ i32_ret = raydium_boot_upgrade_2X(client);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_fw_upgrade_2X(client, RAYDIUM_BOOTLOADER, 0);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_fw_upgrade_2X(client, RAYDIUM_FIRMWARE, 1);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ }
+
+exit_upgrade:
+ return i32_ret;
+}
+
+int raydium_fw_update_check(unsigned short u16_i2c_data)
+{
+
+ unsigned char u8_rbuffer[4];
+
+ unsigned int u32_fw_version, u32_image_version;
+ int i32_ret = ERROR;
+
+#ifdef FW_UPDATE_EN
+ unsigned char u8_mode_change;
+#endif
+ mutex_lock(&g_raydium_ts->lock);
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
+ RAYDIUM_PDA2_FW_VERSION_ADDR,
+ u8_rbuffer,
+ 4);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ mutex_unlock(&g_raydium_ts->lock);
+
+ u32_fw_version = (u8_rbuffer[0] << 24) | (u8_rbuffer[1] << 16) |
+ (u8_rbuffer[2] << 8) | u8_rbuffer[3];
+ pr_info("[touch]RAD FW ver 0x%.8x\n", u32_fw_version);
+
+ g_raydium_ts->fw_version = u32_fw_version;
+
+ g_raydium_ts->id = ((u16_i2c_data & 0xF) << 12) |
+ ((u8_rbuffer[0] & 0xF) << 8) | u8_rbuffer[1];
+
+ raydium_mem_table_init(g_raydium_ts->id);
+ if (raydium_mem_table_setting()) {
+
+ u32_image_version = (g_rad_para_image[0x0004] << 24) |
+ (g_rad_para_image[0x0005] << 16) |
+ (g_rad_para_image[0x0006] << 8) |
+ g_rad_para_image[0x0007];
+
+ pr_info("[touch]RAD Image FW ver : 0x%x\n", u32_image_version);
+ } else {
+ pr_info("[touch]Mem setting failed, Stop fw upgrade!\n");
+ return FAIL;
+ }
+
+#ifdef FW_UPDATE_EN
+ if (u32_fw_version != u32_image_version) {
+ pr_info("[touch]FW need update.\n");
+ raydium_irq_control(DISABLE);
+ if ((g_u8_raydium_flag & ENG_MODE) == 0) {
+ g_u8_raydium_flag |= ENG_MODE;
+ u8_mode_change = 1;
+ }
+ i32_ret = raydium_burn_fw(g_raydium_ts->client);
+ if (i32_ret < 0)
+ pr_err("[touch]FW update fail:%d\n", i32_ret);
+
+ if (u8_mode_change) {
+ g_u8_raydium_flag &= ~ENG_MODE;
+ u8_mode_change = 0;
+ }
+ raydium_irq_control(ENABLE);
+ mutex_lock(&g_raydium_ts->lock);
+ i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
+ RAYDIUM_PDA2_FW_VERSION_ADDR,
+ u8_rbuffer,
+ 4);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ mutex_unlock(&g_raydium_ts->lock);
+ u32_fw_version = (u8_rbuffer[0] << 24) |
+ (u8_rbuffer[1] << 16) |
+ (u8_rbuffer[2] << 8) |
+ u8_rbuffer[3];
+ pr_info("[touch]RAD FW ver is 0x%x\n",
+ u32_fw_version);
+ g_raydium_ts->fw_version = u32_fw_version;
+ } else
+ pr_info("[touch]FW is the latest version.\n");
+#endif
+
+
+ return i32_ret;
+
+exit_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ return i32_ret;
+}
+int raydium_burn_comp(struct i2c_client *client)
+{
+ int i32_ret = FAIL;
+
+ i32_ret = set_skip_load(client);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+
+ if ((g_raydium_ts->id & 0x2000) != 0) {
+ i32_ret = raydium_fw_upgrade_2X(client, RAYDIUM_COMP, 1);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ }
+ i32_ret = SUCCESS;
+
+exit_upgrade:
+ return i32_ret;
+}
+
+int raydium_load_test_fw(struct i2c_client *client)
+{
+ int i32_ret = SUCCESS;
+ unsigned char u8_buf[4];
+ unsigned int u32_crc_result, u32_read_data;
+
+ /*set mcu hold*/
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x20;
+ raydium_i2c_pda_write(client, 0x50000918, u8_buf, 4);
+ raydium_i2c_pda_read(client, 0x40000004, u8_buf, 4);
+ u8_buf[0] |= 0x01;
+ raydium_i2c_pda_write(client, 0x40000004, u8_buf, 4);
+ msleep(25);
+
+
+ i32_ret = raydium_i2c_pda_read(client, 0x40000000, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ u8_buf[3] |= 0x40;
+ i32_ret = raydium_i2c_pda_write(client, 0x40000000, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_ret = raydium_i2c_pda_read(client, 0x40000014, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ u8_buf[0] |= 0x04;
+ u8_buf[1] |= 0x04;
+ i32_ret = raydium_i2c_pda_write(client, 0x40000014, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ pr_info("[touch]Raydium WRT test_fw to PRAM\n");
+
+ i32_ret = raydium_i2c_pda_write(client, 0x50000900, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ /*Sending test fw*/
+ if ((g_raydium_ts->id & 0x2000) != 0) {
+ i32_ret = raydium_fw_upgrade_with_image(client,
+ 0x800, RAYDIUM_TEST_FW);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ }
+
+ /*check pram crc data*/
+ if ((g_raydium_ts->id & 0x2000) != 0) {
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[1] = 0x08;
+ u8_buf[2] = 0x5B;
+ u8_buf[3] = 0x6B;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000974, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_i2c_pda_read(client, 0x5000094C, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ u8_buf[3] |= 0x81;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000094C, u8_buf, 4);
+ usleep_range(9500, 10500);
+ i32_ret = raydium_i2c_pda_read(client, 0x50000978, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ memcpy(&u32_crc_result, u8_buf, 4);
+ i32_ret = raydium_i2c_pda_read(client, 0x6B5C, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ memcpy(&u32_read_data, u8_buf, 4);
+ if (u32_read_data != u32_crc_result) {
+ pr_err("[touch]check pram fw crc fail!!\n");
+ pr_err("[touch]u32_crc_result 0x%x\n", u32_crc_result);
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ memset(u8_buf, 0, sizeof(u8_buf));
+ u8_buf[0] = 0x60;
+ u8_buf[1] = 0x6B;
+ u8_buf[2] = 0xFB;
+ u8_buf[3] = 0x6D;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000974, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_i2c_pda_read(client, 0x5000094C, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ u8_buf[3] |= 0x81;
+ i32_ret = raydium_i2c_pda_write(client, 0x5000094C, u8_buf, 4);
+ usleep_range(1000, 2000);
+ i32_ret = raydium_i2c_pda_read(client, 0x50000978, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ memcpy(&u32_crc_result, u8_buf, 4);
+ i32_ret = raydium_i2c_pda_read(client, 0x6DFC, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ memcpy(&u32_read_data, u8_buf, 4);
+ if (u32_read_data != u32_crc_result) {
+ pr_err("[touch]check pram CB crc fail!!\n");
+ pr_err("[touch]u32_crc_result 0x%x\n", u32_crc_result);
+ i32_ret = ERROR;
+ goto exit_upgrade;
+ }
+
+ i32_ret = raydium_i2c_pda_read(client, 0x80, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ if (u8_buf[2] > 2) {
+ pr_err("[touch]bootloader version %x,!!\n", u8_buf[2]);
+ memset(u8_buf, 0, sizeof(u8_buf));
+
+ u8_buf[1] = 0x04;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000918,
+ u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ }
+ }
+
+ /*Skip load*/
+ pr_info("[touch]Raydium skip load\n");
+ i32_ret = raydium_i2c_pda_read(client, 0x50000918, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ u8_buf[0] = 0x10;
+ i32_ret = raydium_i2c_pda_write(client, 0x50000918, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_do_software_reset(client);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ i32_ret = raydium_i2c_pda_read(client, 0x50000918, u8_buf, 4);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+ pr_info("[touch]0x5000918 = 0x%x, 0x%x, 0x%x, 0x%x\n",
+ u8_buf[0], u8_buf[1], u8_buf[2], u8_buf[3]);
+ i32_ret = raydium_check_fw_ready(client);
+
+exit_upgrade:
+ return i32_ret;
+}
+
+MODULE_AUTHOR("Raydium");
+MODULE_DESCRIPTION("Raydium TouchScreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/raydium_wt030/raydium_sysfs.c b/drivers/input/touchscreen/raydium_wt030/raydium_sysfs.c
new file mode 100644
index 0000000..9f08b38
--- /dev/null
+++ b/drivers/input/touchscreen/raydium_wt030/raydium_sysfs.c
@@ -0,0 +1,1454 @@
+/* drivers/input/touchscreen/raydium_wt030/raydium_sysfs.c
+ *
+ * Raydium TouchScreen driver.
+ *
+ * Copyright (c) 2010 Raydium tech Ltd.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/unistd.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include "raydium_driver.h"
+
+static ssize_t raydium_touch_calibration_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned char u8_rbuffer[1];
+ unsigned short u16_len = 0;
+ int i32_ret = -1;
+ unsigned char u8_retry = 0;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ if (g_raydium_ts->is_suspend)
+ pr_info("[touch]RAD is_suspend at %s\n", __func__);
+
+ raydium_irq_control(DISABLE);
+ mutex_lock(&g_raydium_ts->lock);
+
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ u8_rbuffer[0] = RAYDIUM_HOST_CMD_CALIBRATION;
+ i32_ret = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_rbuffer, 1);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ do {
+ if (u8_rbuffer[0] == RAYDIUM_HOST_CMD_NO_OP)
+ break;
+
+ msleep(1000);
+
+ i32_ret = raydium_i2c_pda2_read(client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_rbuffer, 1);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ pr_info("[touch]RAD %s return 0x%02x!!\n",
+ __func__, u8_rbuffer[0]);
+ } while (u8_retry++ < (SYN_I2C_RETRY_TIMES * 2));
+
+ memcpy(p_i8_buf, u8_rbuffer, 1);
+
+ u16_len = strlen(p_i8_buf);
+ i32_ret = u16_len + 1;
+
+exit_i2c_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+
+ return i32_ret;
+}
+
+static ssize_t raydium_i2c_pda_access_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned char u8_rbuffer[4];
+ unsigned short u16_len = 0;
+ int i32_ret = -1;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ if (g_u32_length > 4)
+ return -EINVAL;
+ memset(u8_rbuffer, 0x00, 4);
+ mutex_lock(&g_raydium_ts->lock);
+ i32_ret = raydium_i2c_pda_read(client,
+ g_u32_addr,
+ u8_rbuffer,
+ g_u32_length);
+ mutex_unlock(&g_raydium_ts->lock);
+ if (i32_ret < 0)
+ return i32_ret;
+
+ snprintf(p_i8_buf, PAGE_SIZE, "0x%08X : 0x%02X%02X%02X%02X\n",
+ (unsigned int)g_u32_addr, u8_rbuffer[3], u8_rbuffer[2],
+ u8_rbuffer[1], u8_rbuffer[0]);
+ u16_len = strlen(p_i8_buf);
+
+ return u16_len + 1;
+}
+
+static ssize_t raydium_check_i2c_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned char u8_rbuffer[4];
+ unsigned short u16_len = 0;
+ int i32_ret = -1;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ if (g_raydium_ts->is_suspend)
+ pr_info("[touch]RAD is_suspend at %s\n", __func__);
+ raydium_irq_control(DISABLE);
+ mutex_lock(&g_raydium_ts->lock);
+
+ if (g_u8_i2c_mode == PDA2_MODE) {
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ /*using byte mode to read 4 bytes*/
+ *(unsigned long *)u8_rbuffer = (RAD_I2C_PDA_MODE_ENABLE << 24)
+ | ((RAD_CHK_I2C_CMD &
+ (~MASK_8BIT)) >> 8);
+
+ i32_ret = raydium_i2c_pda2_write(client,
+ RAYDIUM_PDA2_PDA_CFG_ADDR,
+ u8_rbuffer,
+ 4);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_ENABLE_PDA);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ i32_ret = raydium_i2c_pda2_read(client,
+ (unsigned char)(RAD_CHK_I2C_CMD & MASK_8BIT),
+ u8_rbuffer, 4);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ } else {
+ i32_ret = raydium_i2c_pda_read(client, RAD_CHK_I2C_CMD,
+ u8_rbuffer, 4);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ }
+
+ snprintf(p_i8_buf, PAGE_SIZE, "[touch]RAD Touch check i2c: %02X%02X\n",
+ u8_rbuffer[3], u8_rbuffer[2]);
+ u16_len = strlen(p_i8_buf);
+ i32_ret = u16_len + 1;
+
+exit_i2c_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+ return i32_ret;
+}
+
+static ssize_t raydium_hw_reset_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ int i32_ret = SUCCESS;
+
+
+ pr_info("[touch]HW reset\n");
+ g_u8_resetflag = true;
+ if ((g_u8_raydium_flag & ENG_MODE) == 0)
+ raydium_irq_control(DISABLE);
+
+ /*HW reset*/
+ if (gpio_is_valid(g_raydium_ts->rst_gpio)) {
+ gpio_set_value(g_raydium_ts->rst_gpio, 1);
+ gpio_set_value(g_raydium_ts->rst_gpio, 0);
+ msleep(RAYDIUM_RESET_INTERVAL_MSEC);
+ gpio_set_value(g_raydium_ts->rst_gpio, 1);
+ }
+
+ g_u8_i2c_mode = PDA2_MODE;
+
+ i32_ret = wait_irq_state(client, 1000, 2000);
+ if (i32_ret != ERROR) {
+ msleep(25);
+ }
+
+ if ((g_u8_raydium_flag & ENG_MODE) == 0)
+ raydium_irq_control(ENABLE);
+
+ snprintf(p_i8_buf, PAGE_SIZE, "Raydium HW Reset : %d\n", i32_ret);
+ pr_info("%s\n", p_i8_buf);
+ return strlen(p_i8_buf) + 1;
+}
+
+static ssize_t raydium_reset_control_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ unsigned char u8_high;
+
+ if (g_raydium_ts->is_suspend)
+ pr_info("[touch]RAD is_suspend at %s\n", __func__);
+
+ /* receive command line arguments string */
+ if (count > 2)
+ return -EINVAL;
+
+ i32_ret = kstrtou8(p_i8_buf, 16, &u8_high);
+ if (i32_ret < 0)
+ return i32_ret;
+
+ g_u8_i2c_mode = PDA2_MODE;
+ g_u8_resetflag = true;
+
+ if (u8_high) {
+ pr_info("[touch]RAD %s set reset gpio to high!!\n",
+ __func__);
+ gpio_set_value(g_raydium_ts->rst_gpio, 1);
+ } else {
+ pr_info("[touch]RAD %s set reset gpio to low!!\n",
+ __func__);
+ gpio_set_value(g_raydium_ts->rst_gpio, 0);
+ }
+ return count;
+}
+
+static ssize_t raydium_palm_status_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned short u16_len = 0;
+
+ unsigned char u8_tp_status[MAX_TCH_STATUS_PACKET_SIZE];
+ unsigned char u8_tp_buf[MAX_REPORT_PACKET_SIZE];
+
+ raydium_read_touchdata(u8_tp_status, u8_tp_buf);
+ snprintf(p_i8_buf, PAGE_SIZE, "[touch] palm_status : %d\n",
+ u8_tp_status[POS_GES_STATUS]);
+
+ u16_len = strlen(p_i8_buf);
+ return u16_len + 1;
+}
+
+
+static ssize_t raydium_palm_area_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ unsigned char w_data[1];
+ unsigned char palm_area = 0;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ /* receive command line arguments string */
+ if (count > 3)
+ return -EINVAL;
+
+ ret = kstrtou8(buf, 16, &palm_area);
+ pr_info("[touch] input palm area = %d\n", palm_area);
+
+ mutex_lock(&g_raydium_ts->lock);
+ /* unlock PARM */
+
+ ret = raydium_i2c_pda2_set_page(client, g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0);
+ if (ret < 0) {
+ mutex_unlock(&g_raydium_ts->lock);
+ goto exit_error;
+ }
+
+ w_data[0] = palm_area;
+ ret = raydium_i2c_pda2_write(client,RAYDIUM_PDA2_PALM_AREA_ADDR,
+ w_data, 1);
+ if (ret < 0) {
+ mutex_unlock(&g_raydium_ts->lock);
+ goto exit_error;
+ }
+
+ mutex_unlock(&g_raydium_ts->lock);
+
+exit_error:
+ return count;
+}
+static ssize_t raydium_palm_area_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned char u8_rbuffer[4];
+ unsigned short u16_len = 0;
+ int i32_ret = -1;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ if (g_raydium_ts->is_suspend)
+ pr_info("[touch]RAD is_suspend at %s\n", __func__);
+
+ raydium_irq_control(DISABLE);
+ mutex_lock(&g_raydium_ts->lock);
+
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ i32_ret = raydium_i2c_pda2_read(client, RAYDIUM_PDA2_PALM_AREA_ADDR,
+ u8_rbuffer, 4);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ snprintf(p_i8_buf, PAGE_SIZE, "RAD Palm area : %02X\n", u8_rbuffer[0]);
+
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+
+ u16_len = strlen(p_i8_buf);
+ i32_ret = u16_len + 1;
+ goto exit_upgrade;
+
+exit_i2c_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+
+exit_upgrade:
+ return i32_ret;
+}
+
+static ssize_t raydium_irq_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned int u32_irq_value;
+
+ u32_irq_value = gpio_get_value(g_raydium_ts->irq_gpio);
+
+ snprintf(p_i8_buf, PAGE_SIZE, "%d", u32_irq_value);
+ /*pr_info("%s\n", p_i8_buf);*/
+ return strlen(p_i8_buf) + 1;
+}
+
+
+static ssize_t raydium_touch_lock_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ unsigned char u8_mode;
+ unsigned char u8_wbuffer[1];
+
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ if (g_raydium_ts->is_suspend)
+ pr_info("[touch]RAD is_suspend at %s\n", __func__);
+
+ /* receive command line arguments string */
+ if (count > 2)
+ return -EINVAL;
+
+ i32_ret = kstrtou8(p_i8_buf, 16, &u8_mode);
+ if (i32_ret < 0)
+ return i32_ret;
+ raydium_irq_control(DISABLE);
+ mutex_lock(&g_raydium_ts->lock);
+
+ switch (u8_mode) {
+ case 0: /* Disable Touch lock */
+
+ if (g_raydium_ts->is_sleep != 1)
+ break;
+ g_u8_resetflag = true;
+ if (gpio_is_valid(g_raydium_ts->rst_gpio)) {
+ gpio_set_value(g_raydium_ts->rst_gpio, 1);
+ gpio_set_value(g_raydium_ts->rst_gpio, 0);
+ msleep(RAYDIUM_RESET_INTERVAL_MSEC);/*5ms*/
+ gpio_set_value(g_raydium_ts->rst_gpio, 1);
+ msleep(RAYDIUM_RESET_DELAY_MSEC);/*100ms*/
+ }
+ pr_info("[touch]RAD %s disable touch lock!!\n", __func__);
+
+ g_raydium_ts->is_sleep = 0;
+ break;
+
+ case 1: /* Enable Touch lock */
+
+ if (g_raydium_ts->is_sleep == 1)
+ break;
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ /*fw enter sleep mode*/
+ u8_wbuffer[0] = RAYDIUM_HOST_CMD_PWR_SLEEP;
+ i32_ret = raydium_i2c_pda2_write(client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_wbuffer,
+ 1);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ pr_info("[touch]RAD %s enable touch lock!!\n", __func__);
+ g_raydium_ts->is_sleep = 1;
+ break;
+ }
+
+exit_i2c_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+ return count;
+}
+
+static ssize_t raydium_check_driver_version_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ /*unsigned char rbuffer[4];*/
+ unsigned short u16_len = 0;
+ int i32_ret = -1;
+
+ snprintf(p_i8_buf, PAGE_SIZE, "RAD Driver Ver: 0x%X\n",
+ g_u32_driver_version);
+ /*sprintf(p_i8_buf, "RAD Driver Ver: 0x%X\n", g_u32_driver_version);*/
+
+ u16_len = strlen(p_i8_buf);
+ i32_ret = u16_len + 1;
+ return i32_ret;
+}
+
+static ssize_t raydium_check_fw_version_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned char u8_rbuffer[4];
+ unsigned short u16_len = 0;
+ int i32_ret = -1;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ unsigned int fw_version, image_version;
+
+ if (g_raydium_ts->is_suspend)
+ pr_info("[touch]RAD is_suspend at %s\n", __func__);
+
+ raydium_irq_control(DISABLE);
+ mutex_lock(&g_raydium_ts->lock);
+
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ i32_ret = raydium_i2c_pda2_read(client, RAYDIUM_PDA2_FW_VERSION_ADDR,
+ u8_rbuffer, 4);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ snprintf(p_i8_buf, PAGE_SIZE, "RAD Touch FW Ver : %02X%02X%02X%02X\n",
+ u8_rbuffer[0], u8_rbuffer[1], u8_rbuffer[2], u8_rbuffer[3]);
+
+ fw_version = (u8_rbuffer[0] << 24)
+ | (u8_rbuffer[1] << 16)
+ | (u8_rbuffer[2] << 8)
+ | u8_rbuffer[3];
+ pr_info("[touch]RAD FW ver : 0x%x\n", fw_version);
+
+ image_version = (g_rad_para_image[0x0004] << 24) |
+ (g_rad_para_image[0x0005] << 16) |
+ (g_rad_para_image[0x0006] << 8) |
+ g_rad_para_image[0x0007];
+
+ pr_info("[touch]RAD Image FW ver : 0x%x\n", image_version);
+
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+
+ if (fw_version != image_version)
+ pr_info("[touch]%s, FW need upgrade.\n", __func__);
+
+ u16_len = strlen(p_i8_buf);
+ i32_ret = u16_len + 1;
+ goto exit_upgrade;
+
+exit_i2c_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+
+exit_upgrade:
+ return i32_ret;
+}
+
+static ssize_t raydium_check_panel_version_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned char u8_rbuffer[8];
+ unsigned short u16_len = 0;
+ int i32_ret = -1;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ if (g_raydium_ts->is_suspend)
+ pr_info("[touch]RAD is_suspend at %s\n", __func__);
+ raydium_irq_control(DISABLE);
+ mutex_lock(&g_raydium_ts->lock);
+
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ i32_ret = raydium_i2c_pda2_read(client,
+ RAYDIUM_PDA2_PANEL_VERSION_ADDR,
+ u8_rbuffer, 8);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+ snprintf(p_i8_buf, PAGE_SIZE,
+ "RAD Touch Panel Version : %02X%02X%02X%02X%02X%02X\n",
+ u8_rbuffer[0], u8_rbuffer[1], u8_rbuffer[2],
+ u8_rbuffer[3], u8_rbuffer[4], u8_rbuffer[5]);
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+
+ u16_len = strlen(p_i8_buf);
+ i32_ret = u16_len + 1;
+ goto exit_upgrade;
+
+exit_i2c_error:
+ mutex_unlock(&g_raydium_ts->lock);
+ raydium_irq_control(ENABLE);
+exit_upgrade:
+ return i32_ret;
+}
+
+static ssize_t raydium_fw_upgrade_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+
+ /* receive command line arguments string */
+ if (count > 2)
+ return -EINVAL;
+
+ i32_ret = kstrtou8(p_i8_buf, 16, &g_u8_upgrade_type);
+ if (i32_ret < 0)
+ return i32_ret;
+
+ return count;
+}
+
+static ssize_t raydium_fw_upgrade_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ int i32_ret = 0, i32_result = FAIL;
+ unsigned short u16_len = 0;
+ unsigned char u8_mode_change;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ raydium_irq_control(DISABLE);
+
+ pr_info("[touch]RAD burn type is %d\n", g_u8_upgrade_type);
+
+ if ((g_u8_raydium_flag & ENG_MODE) == 0) {
+ g_u8_raydium_flag |= ENG_MODE;
+ u8_mode_change = 1;
+ }
+
+ if ((g_u8_table_setting == 1) && (g_u8_table_init == 1))
+ raydium_mem_table_setting();
+
+ if (g_u8_upgrade_type == 1) {
+ i32_ret = raydium_burn_fw(client);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_result = SUCCESS;
+ } else if (g_u8_upgrade_type == 2) {
+ i32_ret = raydium_burn_comp(client);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_result = SUCCESS;
+ } else if (g_u8_upgrade_type == 4) {
+ i32_ret = raydium_load_test_fw(client);
+ if (i32_ret < 0)
+ goto exit_upgrade;
+
+ i32_result = SUCCESS;
+ }
+
+exit_upgrade:
+ if (u8_mode_change) {
+ pr_info("[touch]g_u8_raydium_flag : %d", g_u8_raydium_flag);
+ g_u8_raydium_flag &= ~ENG_MODE;
+ u8_mode_change = 0;
+ }
+ raydium_irq_control(ENABLE);
+ g_u8_upgrade_type = 0;
+
+ snprintf(p_i8_buf, PAGE_SIZE, "FW Upgrade result : %d\n", i32_result);
+ u16_len = strlen(p_i8_buf);
+ return u16_len + 1;
+}
+static ssize_t raydium_i2c_pda2_page_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ unsigned char u8_page = 0;
+ char *temp_buf, *token, *free_temp_buf, *free_token;
+ const char *delim = " ,";
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ /* receive command line arguments string */
+ if (count < 2)
+ return -EINVAL;
+ temp_buf = kzalloc(count + 1, GFP_KERNEL);
+ if (temp_buf == NULL)
+ return -ENOMEM;
+
+ token = kzalloc(count + 1, GFP_KERNEL);
+ if (token == NULL) {
+ kfree(temp_buf);
+ return -ENOMEM;
+ }
+
+ free_temp_buf = temp_buf;
+ free_token = token;
+
+ strlcpy(temp_buf, p_i8_buf, count);
+
+ token = strsep(&temp_buf, delim);
+
+ if (temp_buf) {
+ pr_err("[touch]input error, extra auguments!n");
+ i32_ret = -EINVAL;
+ goto exit_error;
+ }
+ i32_ret = kstrtou8(token, 16, &u8_page);
+
+ if (i32_ret < 0)
+ goto exit_error;
+
+ mutex_lock(&g_raydium_ts->lock);
+
+ i32_ret = raydium_i2c_pda2_set_page(client, g_raydium_ts->is_suspend, u8_page);
+ if (i32_ret < 0)
+ goto exit_set_error;
+
+ /* TODO: Page check, Due to ISR will change page back to Page_0.
+ * Or disable IRQ during PDA2 access period
+ */
+
+exit_set_error:
+ mutex_unlock(&g_raydium_ts->lock);
+
+exit_error:
+ kfree(free_token);
+ kfree(free_temp_buf);
+ return count;
+}
+
+static ssize_t raydium_flag_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned short u16_len = 0;
+
+ snprintf(p_i8_buf, PAGE_SIZE, "%d", g_u8_raydium_flag);
+ /*pr_info("[touch]RAD flag : %d\n", g_u8_raydium_flag);*/
+ u16_len = strlen(p_i8_buf);
+
+ return u16_len + 1;
+}
+
+static ssize_t raydium_flag_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ unsigned char u8_flag = 0;
+
+ /* receive command line arguments string */
+ if (count > 2)
+ return -EINVAL;
+ i32_ret = kstrtou8(p_i8_buf, 16, &u8_flag);
+ if (i32_ret < 0)
+ return i32_ret;
+ g_u8_raydium_flag = u8_flag;
+ return count;
+}
+
+static ssize_t raydium_mem_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ unsigned char u8_type = 0;
+ unsigned int u32_image_version;
+
+ /* receive command line arguments string */
+ if (count > 2)
+ return -EINVAL;
+
+ pr_info("[touch]%s\n", __func__);
+
+ i32_ret = kstrtou8(p_i8_buf, 16, &u8_type);
+ if (i32_ret < 0)
+ return i32_ret;
+
+ if (u8_type > 3) {
+ pr_info("[touch]Input invalid value!!\n");
+ return ERROR;
+ }
+
+ if (g_rad_boot_image != NULL)
+ kfree(g_rad_boot_image);
+ if (g_rad_init_image != NULL)
+ kfree(g_rad_init_image);
+ if (g_rad_fw_image != NULL)
+ kfree(g_rad_fw_image);
+ if (g_rad_para_image != NULL)
+ kfree(g_rad_para_image);
+ if (g_rad_testfw_image != NULL)
+ kfree(g_rad_testfw_image);
+ if (g_rad_testpara_image != NULL)
+ kfree(g_rad_testpara_image);
+
+ if (!raydium_id_init(u8_type)) {
+ pr_info("[touch]Set Raydium id failed!\n");
+ return count;
+ }
+
+ raydium_mem_table_init(g_raydium_ts->id);
+ if (raydium_mem_table_setting()) {
+ u32_image_version = (g_rad_para_image[0x0004] << 24) |
+ (g_rad_para_image[0x0005] << 16) |
+ (g_rad_para_image[0x0006] << 8) |
+ g_rad_para_image[0x0007];
+
+ pr_info("[touch]RAD Image FW ver : 0x%x\n", u32_image_version);
+ } else
+ pr_info("[touch]Mem init failed!\n");
+
+ return count;
+}
+
+static ssize_t raydium_i2c_raw_data_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ char *temp_buf, *token, *free_temp_buf, *free_token;
+ const char *delim = " ,";
+ unsigned char u8_w_data[RAD_FT_CMD_LENGTH];
+
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ /* receive command line arguments string */
+ if (count < 2)
+ return -EINVAL;
+ temp_buf = kzalloc(count + 1, GFP_KERNEL);
+ if (temp_buf == NULL) {
+ pr_err("[touch]kzalloc temp_buf failed\n");
+ return -ENOMEM;
+ }
+
+ token = kzalloc(count + 1, GFP_KERNEL);
+ if (token == NULL) {
+ kfree(temp_buf);
+ return -ENOMEM;
+ }
+
+ free_temp_buf = temp_buf;
+ free_token = token;
+
+ strlcpy(temp_buf, p_i8_buf, count);
+
+ token = strsep(&temp_buf, delim);
+
+ i32_ret = kstrtou8(token, 16, &g_u8_raw_data_type);
+
+ token = strsep(&temp_buf, delim);
+ if (token) {
+ i32_ret = kstrtouint(token, 16, &g_u32_raw_data_len);
+ if (i32_ret < 0)
+ goto exit_error;
+
+
+ } else { /* without length info*/
+ i32_ret = -EINVAL;
+ goto exit_error;
+ }
+
+ if (temp_buf) { /* too much arguments*/
+ i32_ret = -E2BIG;
+ goto exit_error;
+ }
+
+ memset(u8_w_data, 0x00, RAD_FT_CMD_LENGTH);
+
+ mutex_lock(&g_raydium_ts->lock);
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ g_raydium_ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0) {
+ mutex_unlock(&g_raydium_ts->lock);
+ goto exit_error;
+ }
+
+ g_u8_resetflag = true;
+
+ u8_w_data[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP;
+ u8_w_data[RAD_FT_CMD_POS] = g_u8_raw_data_type;
+
+ i32_ret = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_w_data, RAD_FT_CMD_LENGTH);
+ mutex_unlock(&g_raydium_ts->lock);
+ if (i32_ret < 0)
+ goto exit_error;
+
+ if (g_u8_raw_data_type == 0) {
+ msleep(10);
+ g_u8_resetflag = false;
+ }
+exit_error:
+ kfree(free_token);
+ kfree(free_temp_buf);
+
+ return count;
+}
+static ssize_t raydium_i2c_raw_data_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned char u8_rbuffer[MAX_READ_PACKET_SIZE];
+ unsigned int u32_target_addr;
+ unsigned int u32_offset;
+ unsigned short u16_read_length;
+
+ int i32_ret = -1;
+ int i32_retry = 0;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct raydium_ts_data *ts =
+ (struct raydium_ts_data *)i2c_get_clientdata(client);
+ unsigned char u8_retry_limit = (ts->is_suspend) ? 30 : 3;
+
+ memset(u8_rbuffer, 0x00, MAX_READ_PACKET_SIZE);
+
+ /* make sure update flag was set*/
+ for (i32_retry = 0; i32_retry < u8_retry_limit; i32_retry++) {
+ mutex_lock(&ts->lock);
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ i32_ret = raydium_i2c_pda2_read(client,
+ RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_rbuffer,
+ RAD_FT_CMD_LENGTH);
+ mutex_unlock(&ts->lock);
+ if (i32_ret < 0)
+ goto exit_flag_error;
+
+ if ((u8_rbuffer[RAD_FT_CMD_POS] & RAYDIUM_FT_UPDATE) ==
+ RAYDIUM_FT_UPDATE)
+ break;
+
+ usleep_range(4500, 5500);
+ }
+
+ if (i32_retry == u8_retry_limit) {
+ i32_ret = -EAGAIN;
+ goto exit_flag_error;
+ }
+
+ u32_offset = 0;
+ u16_read_length = 0;
+ while (u32_offset < g_u32_raw_data_len) {
+ if ((u32_offset + MAX_READ_PACKET_SIZE) <
+ g_u32_raw_data_len)
+ u16_read_length = MAX_READ_PACKET_SIZE;
+ else
+ u16_read_length =
+ (unsigned short)(g_u32_raw_data_len - u32_offset);
+
+ u32_target_addr = RAD_READ_FT_DATA_CMD + u32_offset;
+
+ mutex_lock(&(ts->lock));
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ ts->is_suspend,
+ RAYDIUM_PDA2_PAGE_0);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ *(unsigned int *)u8_rbuffer = (RAD_I2C_PDA_MODE_ENABLE << 24)
+ | ((u32_target_addr & (~MASK_8BIT)) >> 8);
+
+ /*using byte mode to read 4 bytes*/
+ i32_ret = raydium_i2c_pda2_write(client,
+ RAYDIUM_PDA2_PDA_CFG_ADDR, u8_rbuffer, 4);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ i32_ret = raydium_i2c_pda2_set_page(client,
+ ts->is_suspend,
+ RAYDIUM_PDA2_ENABLE_PDA);
+ if (i32_ret < 0)
+ goto exit_i2c_error;
+
+ i32_ret = raydium_i2c_pda2_read(client,
+ (unsigned char)(u32_target_addr & MASK_8BIT),
+ u8_rbuffer,
+ u16_read_length);
+
+ mutex_unlock(&(ts->lock));
+ if (i32_ret < 0)
+ goto exit_flag_error;
+
+ memcpy((p_i8_buf + u32_offset), u8_rbuffer, u16_read_length);
+
+ u32_offset += u16_read_length;
+ }
+
+ /* clear update flag to get next one*/
+ u8_rbuffer[RAD_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP;
+ u8_rbuffer[RAD_FT_CMD_POS] = g_u8_raw_data_type;
+ mutex_lock(&ts->lock);
+ i32_ret = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_HOST_CMD_ADDR,
+ u8_rbuffer, RAD_FT_CMD_LENGTH);
+ mutex_unlock(&ts->lock);
+ if (i32_ret < 0)
+ goto exit_flag_error;
+
+ return g_u32_raw_data_len;
+exit_i2c_error:
+ mutex_unlock(&(ts->lock));
+exit_flag_error:
+ return i32_ret;
+}
+static ssize_t raydium_i2c_pda_access_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ char *temp_buf, *token, *free_temp_buf, *free_token;
+ const char *delim = " ,";
+ unsigned char u8_w_data[MAX_WRITE_PACKET_SIZE];
+ unsigned int u32_data_count = 0;
+ unsigned int u32_data_index = 0;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ /* receive command line arguments string */
+ if (count < 2)
+ return -EINVAL;
+
+ temp_buf = kzalloc(count + 1, GFP_KERNEL);
+ if (temp_buf == NULL)
+ return -ENOMEM;
+
+ token = kzalloc(count + 1, GFP_KERNEL);
+ if (token == NULL) {
+ kfree(temp_buf);
+ return -ENOMEM;
+ }
+
+ free_temp_buf = temp_buf;
+ free_token = token;
+
+ strlcpy(temp_buf, p_i8_buf, count);
+
+ token = strsep(&temp_buf, delim);
+
+ i32_ret = kstrtoul(token, 16, &g_u32_addr);
+
+ token = strsep(&temp_buf, delim);
+ if (token)
+ i32_ret = kstrtouint(token, 16, &u32_data_count);
+ else
+ goto exit_error;
+ if (g_u32_length > MAX_WRITE_PACKET_SIZE)
+ return -EINVAL;
+ g_u32_length = u32_data_count;
+
+ memset(u8_w_data, 0x00, MAX_WRITE_PACKET_SIZE);
+
+ if (temp_buf && u32_data_count) {
+ u32_data_index = 0;
+ while (u32_data_count) {
+ token = strsep(&temp_buf, delim);
+ i32_ret = kstrtou8(token, 16,
+ &u8_w_data[u32_data_index++]);
+ if (i32_ret < 0)
+ goto exit_error;
+ u32_data_count--;
+ }
+ mutex_lock(&g_raydium_ts->lock);
+ i32_ret = raydium_i2c_pda_write(client, g_u32_addr,
+ u8_w_data, g_u32_length);
+ mutex_unlock(&g_raydium_ts->lock);
+ }
+
+exit_error:
+ kfree(free_token);
+ kfree(free_temp_buf);
+ return count;
+}
+
+static ssize_t raydium_i2c_pda2_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ unsigned char u8_mode;
+
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ if (g_raydium_ts->is_suspend)
+ pr_info("[touch]RAD is_suspend at %s\n", __func__);
+
+ /* receive command line arguments string */
+ if (count > 2)
+ return -EINVAL;
+
+ i32_ret = kstrtou8(p_i8_buf, 16, &u8_mode);
+ if (i32_ret < 0)
+ return i32_ret;
+ i32_ret = raydium_i2c_mode_control(client, u8_mode);
+ if (i32_ret < 0)
+ return i32_ret;
+
+ return count;
+}
+
+static ssize_t raydium_i2c_pda2_access_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ unsigned char u8_rbuffer[4];
+ unsigned short u16_len = 0;
+ int i32_ret = -1;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ if (g_u32_length > 4)
+ return -EINVAL;
+ memset(u8_rbuffer, 0x00, 4);
+
+ mutex_lock(&g_raydium_ts->lock);
+ i32_ret = raydium_i2c_pda2_read(client, g_u8_addr,
+ u8_rbuffer, g_u32_length);
+ mutex_unlock(&g_raydium_ts->lock);
+ if (i32_ret < 0)
+ return i32_ret;
+
+ snprintf(p_i8_buf, PAGE_SIZE, "0x%04X : 0x%02X%02X%02X%02X\n",
+ g_u8_addr, u8_rbuffer[3], u8_rbuffer[2],
+ u8_rbuffer[1], u8_rbuffer[0]);
+ u16_len = strlen(p_i8_buf);
+
+ return u16_len + 1;
+}
+
+static ssize_t raydium_i2c_pda2_access_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ char *temp_buf, *token, *free_temp_buf, *free_token;
+ const char *delim = " ,";
+ unsigned char u8_w_data[MAX_WRITE_PACKET_SIZE];
+ unsigned int u32_data_count = 0;
+ unsigned int u32_data_index = 0;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ /* receive command line arguments string */
+ if (count < 2)
+ return -EINVAL;
+ temp_buf = kzalloc(count + 1, GFP_KERNEL);
+ if (temp_buf == NULL) {
+ pr_err("[touch]kzalloc temp_buf failed\n");
+ return -ENOMEM;
+ }
+
+ token = kzalloc(count + 1, GFP_KERNEL);
+ if (token == NULL) {
+ kfree(temp_buf);
+ return -ENOMEM;
+ }
+
+ free_temp_buf = temp_buf;
+ free_token = token;
+
+ strlcpy(temp_buf, p_i8_buf, count);
+
+ token = strsep(&temp_buf, delim);
+
+ i32_ret = kstrtou8(token, 16, &g_u8_addr);
+
+ token = strsep(&temp_buf, delim);
+ if (token)
+ i32_ret = kstrtouint(token, 16, &u32_data_count);
+ else {
+ i32_ret = -EINVAL;
+ goto exit_error;
+ }
+
+ if (u32_data_count > MAX_WRITE_PACKET_SIZE) {
+ i32_ret = -EINVAL;
+ goto exit_error;
+ }
+
+ memset(u8_w_data, 0x00, MAX_WRITE_PACKET_SIZE);
+
+ g_u32_length = u32_data_count;
+
+ if (temp_buf && u32_data_count) {
+ u32_data_index = 0;
+ while (u32_data_count) {
+ token = strsep(&temp_buf, delim);
+ i32_ret = kstrtou8(token, 16,
+ &u8_w_data[u32_data_index++]);
+ if (i32_ret < 0)
+ goto exit_error;
+ u32_data_count--;
+ }
+
+ mutex_lock(&g_raydium_ts->lock);
+ i32_ret = raydium_i2c_pda2_write(client, g_u8_addr,
+ u8_w_data, g_u32_length);
+ mutex_unlock(&g_raydium_ts->lock);
+ if (i32_ret < 0)
+ goto exit_error;
+ }
+
+exit_error:
+ kfree(free_token);
+ kfree(free_temp_buf);
+ return count;
+}
+
+static ssize_t raydium_receive_fw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *p_i8_buf, size_t count)
+{
+ int i32_ret = 0;
+ const char *delim = " ,";
+ char *token, *temp_buf, *free_token, *free_temp_buf;
+ static unsigned char *p_u8_firmware_data;
+
+ unsigned char u8_cmd;
+ unsigned long u32_len;
+ static unsigned char u8_type;
+ static unsigned int u32_index;
+
+ if (count == 20) { /*check FW type*/
+ temp_buf = kzalloc(32, GFP_KERNEL);
+ if (temp_buf == NULL) {
+ pr_err("[touch]kzalloc temp_buf failed\n");
+ return -ENOMEM;
+ }
+
+ token = kzalloc(32, GFP_KERNEL);
+ if (token == NULL) {
+ kfree(temp_buf);
+ return -ENOMEM;
+ }
+
+ free_token = token;
+ free_temp_buf = temp_buf;
+
+ snprintf(temp_buf, PAGE_SIZE, "%s", p_i8_buf);
+ token = strsep(&temp_buf, delim);
+ i32_ret = kstrtou8(token, 16, &u8_cmd);
+ if (i32_ret < 0) {
+ pr_err("[touch]kstrtou8 failed\n");
+ kfree(free_token);
+ kfree(free_temp_buf);
+ }
+
+ token = strsep(&temp_buf, delim);
+ i32_ret = kstrtou8(token, 16, &u8_type);
+ if (i32_ret < 0) {
+ pr_err("[touch]kstrtou8 failed\n");
+ kfree(temp_buf);
+ kfree(token);
+ }
+
+ token = strsep(&temp_buf, delim);
+ i32_ret = kstrtoul(token, 16, &u32_len);
+ if (i32_ret < 0) {
+ pr_err("[touch]kstrtou8 failed\n");
+ kfree(temp_buf);
+ kfree(token);
+ }
+
+ pr_info("[touch]uc_cmd=0x%x, uc_type=0x%x, u16_len=0x%x\n",
+ u8_cmd, u8_type, (unsigned int)u32_len);
+
+ if (u8_cmd == RAD_CMD_UPDATE_BIN) { /*check FW length*/
+ u32_index = 0;
+ if (u8_type == RAYDIUM_BOOTLOADER) {
+ memset(g_rad_boot_image, 0, u32_len);
+ p_u8_firmware_data = g_rad_boot_image;
+ } else if (u8_type == RAYDIUM_INIT) {
+ memset(g_rad_init_image, 0, u32_len);
+ p_u8_firmware_data = g_rad_init_image;
+ } else if (u8_type == RAYDIUM_PARA) {
+ memset(g_rad_para_image, 0, u32_len);
+ p_u8_firmware_data = g_rad_para_image;
+ } else if (u8_type == RAYDIUM_FIRMWARE) {
+ memset(g_rad_fw_image, 0, u32_len);
+ p_u8_firmware_data = g_rad_fw_image;
+ } else if (u8_type == RAYDIUM_TEST_PARA) {
+ memset(g_rad_testpara_image, 0, u32_len);
+ p_u8_firmware_data = g_rad_testpara_image;
+ } else if (u8_type == RAYDIUM_TEST_FW) {
+ memset(g_rad_testfw_image, 0, u32_len);
+ p_u8_firmware_data = g_rad_testfw_image;
+ }
+
+ } else if (u8_cmd == RAD_CMD_UPDATE_END) { /*set buffer finish*/
+ if (((g_raydium_ts->id & 0x2000) == 0x2000)
+ && (u8_type == RAYDIUM_TEST_FW)) {
+ memcpy((g_rad_testfw_image + RAD_FW_2X_SIZE),
+ g_rad_testpara_image, RAD_PARA_2X_SIZE + 4);
+ }
+
+ u32_index = 0;
+ g_u8_table_setting = 0;
+
+ } else if (u8_cmd == RAD_CMD_BURN_FINISH) { /*free buffer*/
+ u8_type = 0;
+ u32_index = 0;
+ g_u8_table_setting = 1;
+ }
+
+ kfree(free_temp_buf);
+ kfree(free_token);
+ } else if (count > 10) { /*start copy FW to array*/
+ memcpy((p_u8_firmware_data + u32_index), p_i8_buf, count);
+ u32_index += count;
+ } else
+ pr_info("[touch]other case, count=%d\n", count);
+
+ return count;
+}
+#ifdef RAD_SELFTEST
+static ssize_t raydium_selftest_show(struct device *dev,
+ struct device_attribute *attr,
+ char *p_i8_buf)
+{
+ int i32_ret = SUCCESS;
+
+ pr_info("[touch]do selftest\n");
+
+ i32_ret = raydium_do_selftest();
+
+ snprintf(p_i8_buf, PAGE_SIZE, "Raydium do selftest : %d\n", i32_ret);
+
+ return strlen(p_i8_buf) + 1;
+}
+
+#endif
+/* panel calibration cmd (R)
+ * example:cat raydium_ic_verion
+ */
+static DEVICE_ATTR(raydium_touch_calibration, 0644,
+ raydium_touch_calibration_show,
+ NULL);
+
+/* check the i2c (R)
+ * example:cat raydium_check_i2c
+ */
+static DEVICE_ATTR(raydium_check_i2c, 0644,
+ raydium_check_i2c_show,
+ NULL);
+
+/* upgrade configurate and algo firmware from app.bin (W)
+ * example:echo "offset num_of_bin length *_app.bin [length *_app.bin]"
+ * > raydium_fw_upgrade_mode
+ */
+static DEVICE_ATTR(raydium_fw_upgrade, 0644,
+ raydium_fw_upgrade_show,
+ raydium_fw_upgrade_store);
+
+/* change I2C communication mode (W)
+ * example:echo 1 > raydium_i2c_pda2_mode ==> enable pda2 mode
+ * echo 0 > raydium_i2c_pda2_mode ==> disable pda2 mode
+ */
+static DEVICE_ATTR(raydium_i2c_pda2_mode, 0644,
+ NULL,
+ raydium_i2c_pda2_mode_store);
+
+/* I2C pda mode (R/W)
+ * example: cat raydium_i2c_pda_access ==> read pda address provided by the
+ * following cmd
+ * echo ADDRinHEX [DATAinHEX] > raydium_i2c_pda_access ==> write
+ * pda address [data]
+ */
+static DEVICE_ATTR(raydium_i2c_pda_access, 0644,
+ raydium_i2c_pda_access_show,
+ raydium_i2c_pda_access_store);
+
+/* I2C pda2 mode (R/W)
+ * example: cat raydium_i2c_pda2_access ==> read pda2 address provided by
+ * the following cmd
+ * echo ADDRinHEX [DATAinHEX] > raydium_i2c_pda2_access ==>
+ * write pda2 address [data]
+ */
+static DEVICE_ATTR(raydium_i2c_pda2_access, 0644,
+ raydium_i2c_pda2_access_show,
+ raydium_i2c_pda2_access_store);
+
+/* I2C pda2 mode page (W)
+ * example: echo PAGEinHEX > raydium_i2c_pda2_page ==> write pda2 page
+ */
+static DEVICE_ATTR(raydium_i2c_pda2_page, 0644,
+ NULL,
+ raydium_i2c_pda2_page_store);
+
+/* I2C read/set FT raw data (R/W)
+ * example: cat raydium_i2c_raw_data ==> read raw data with specific length
+ * of corresponding type provided by the following cmd
+ * echo DataTypeinHEX RawDataLengthinHEX > raydium_i2c_raw_data
+ * ==> set raw data type and its length
+ */
+static DEVICE_ATTR(raydium_i2c_raw_data, 0644,
+ raydium_i2c_raw_data_show,
+ raydium_i2c_raw_data_store);
+
+/* Read interrupt flag cmd (R)
+ * example:cat raydium_flag
+ */
+static DEVICE_ATTR(raydium_flag, 0644,
+ raydium_flag_show,
+ raydium_flag_store);
+
+/* Read interrupt flag cmd (R)
+ * example:cat raydium_int_flag
+ */
+static DEVICE_ATTR(raydium_int_flag, 0644,
+ raydium_flag_show,
+ raydium_flag_store);
+
+/* Read selftest flag cmd (R)
+ * example:cat raydium_int_flag
+ */
+static DEVICE_ATTR(raydium_selftest_flag, 0644,
+ raydium_flag_show,
+ raydium_flag_store);
+
+/* Touch lock (W)
+ * example: echo 1 > raydium_i2c_touch_lock ==> enable touch lock
+ * echo 0 > raydium_i2c_touch_lock ==> disable touch lock
+ */
+static DEVICE_ATTR(raydium_i2c_touch_lock, 0644,
+ NULL,
+ raydium_touch_lock_store);
+
+/* show the fw version (R)
+ * example:cat raydium_fw_version
+ */
+static DEVICE_ATTR(raydium_check_fw_version, 0644,
+ raydium_check_fw_version_show,
+ NULL);
+
+/* show the driver version (R)
+ * example:cat raydium_check_driver_version
+ */
+static DEVICE_ATTR(raydium_check_driver_version, 0644,
+ raydium_check_driver_version_show,
+ NULL);
+/* show the panel version (R)
+ * example:cat raydium_panel_version
+ */
+static DEVICE_ATTR(raydium_check_panel_version, 0644,
+ raydium_check_panel_version_show,
+ NULL);
+
+static DEVICE_ATTR(raydium_hw_reset, 0644,
+ raydium_hw_reset_show,
+ NULL);
+
+static DEVICE_ATTR(raydium_irq_state, 0644,
+ raydium_irq_state_show,
+ NULL);
+static DEVICE_ATTR(raydium_palm_status, 0644,
+ raydium_palm_status_show,
+ NULL);
+static DEVICE_ATTR(raydium_palm_area, 0644,
+ raydium_palm_area_show,
+ raydium_palm_area_store);
+static DEVICE_ATTR(raydium_reset_control, 0644,
+ NULL,
+ raydium_reset_control_store);
+static DEVICE_ATTR(raydium_receive_fw_control, 0644,
+ NULL,
+ raydium_receive_fw_store);
+
+static DEVICE_ATTR(raydium_mem_setting, 0644,
+ NULL,
+ raydium_mem_store);
+
+#ifdef RAD_SELFTEST
+static DEVICE_ATTR(raydium_do_selftest, 0644,
+ raydium_selftest_show,
+ NULL);
+#endif
+/*add your attr in here*/
+struct attribute *raydium_attributes[] = {
+ &dev_attr_raydium_touch_calibration.attr,
+ &dev_attr_raydium_check_i2c.attr,
+ &dev_attr_raydium_i2c_pda2_mode.attr,
+ &dev_attr_raydium_i2c_pda_access.attr,
+ &dev_attr_raydium_i2c_pda2_access.attr,
+ &dev_attr_raydium_i2c_pda2_page.attr,
+ &dev_attr_raydium_i2c_raw_data.attr,
+ &dev_attr_raydium_flag.attr,
+ &dev_attr_raydium_i2c_touch_lock.attr,
+ &dev_attr_raydium_fw_upgrade.attr,
+ &dev_attr_raydium_check_fw_version.attr,
+ &dev_attr_raydium_check_panel_version.attr,
+ &dev_attr_raydium_hw_reset.attr,
+ &dev_attr_raydium_irq_state.attr,
+ &dev_attr_raydium_palm_status.attr,
+ &dev_attr_raydium_palm_area.attr,
+ &dev_attr_raydium_int_flag.attr,
+ &dev_attr_raydium_selftest_flag.attr,
+ &dev_attr_raydium_check_driver_version.attr,
+ &dev_attr_raydium_reset_control.attr,
+ &dev_attr_raydium_receive_fw_control.attr,
+ &dev_attr_raydium_mem_setting.attr,
+#ifdef RAD_SELFTEST
+ &dev_attr_raydium_do_selftest.attr,
+#endif
+ NULL
+};
+
+MODULE_AUTHOR("Raydium");
+MODULE_DESCRIPTION("Raydium TouchScreen driver");
+MODULE_LICENSE("GPL");