| /* drivers/input/touchscreen/raydium_ts.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/semaphore.h> |
| #include <linux/mutex.h> |
| #include <linux/module.h> |
| #include <linux/gpio.h> |
| #include <linux/syscalls.h> |
| #include <linux/unistd.h> |
| #include <asm/uaccess.h> |
| #include <linux/fs.h> |
| #include <linux/string.h> |
| #include <linux/timer.h> |
| #include <linux/regulator/consumer.h> |
| #include <linux/device.h> |
| #include <linux/of_gpio.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 |
| |
| #include "raydium_i2c_ts.h" |
| #include "RADFWImage.h" |
| |
| // TODO: Using struct+memcpy instead of array+offset |
| enum raydium_pt_report_idx { |
| POS_SEQ = 0,/*1:touch, 0:no touch*/ |
| POS_PT_AMOUNT, |
| 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, |
| LENGTH_PT = 11 |
| }; |
| |
| struct raydium_slot_status { |
| unsigned char occupied_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 |
| }; |
| |
| struct raydium_slot_status gst_slot_status[MAX_TOUCH_NUM * 2];// The first 3 elements are currently occupied. therest is new coming points |
| struct raydium_slot_status gst_slot_init_status = {0xFF, 0, 0}; |
| |
| struct raydium_ts_platform_data { |
| const 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; |
| }; |
| |
| struct raydium_ts_data { |
| unsigned int irq; |
| unsigned int rst; |
| unsigned int x_max; |
| unsigned int y_max; |
| unsigned int x_pos; |
| unsigned int y_pos; |
| unsigned int pressure; |
| unsigned int is_suspend; |
| unsigned int key_flag; |
| unsigned int is_sleep; |
| #ifdef GESTURE_EN |
| unsigned int is_palm; |
| #endif |
| |
| struct i2c_client *client; |
| struct input_dev *input_dev; |
| struct raydium_ts_platform_data *pdata; |
| 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; |
| |
| #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 |
| }; |
| |
| #if (defined(CONFIG_RM_SYSFS_DEBUG)) |
| static const struct attribute_group raydium_attr_group; |
| #endif //end of CONFIG_RM_SYSFS_DEBUG |
| |
| volatile unsigned char g_uc_raydium_flag = 0; |
| volatile unsigned char g_uc_gesture_status = 0; |
| volatile unsigned char g_uc_raydium_int_flag = 0; |
| volatile unsigned char g_uc_raydium_selftest_flag = 0; |
| volatile unsigned char g_uc_pre_palm_status = 0; |
| unsigned char u8_i2c_mode = PDA2_MODE; |
| unsigned char upgrade_type = 0; |
| unsigned char g_uc_raw_data_type = RAYDIUM_FT_UPDATE; |
| unsigned int g_ui_raw_data_length = 36 * 2; // 72 bytes |
| unsigned long g_ul_addr = RAYDIUM_CHECK_I2C_CMD; |
| unsigned int g_ui_length = 1; |
| |
| /******************************************************************************* |
| * Name: raydium_gpio_configure |
| * Brief: |
| * Input: |
| * Output: |
| * Return: |
| *******************************************************************************/ |
| static int raydium_gpio_configure(struct raydium_ts_data *data, bool on) |
| { |
| int err = 0; |
| |
| if (on) |
| { |
| if (gpio_is_valid(data->pdata->irq_gpio)) |
| { |
| err = gpio_request(data->pdata->irq_gpio, "raydium_irq_gpio"); |
| if (err) |
| { |
| dev_err(&data->client->dev, "[touch]irq gpio request failed"); |
| goto err_irq_gpio_req; |
| } |
| |
| err = gpio_direction_input(data->pdata->irq_gpio); |
| if (err) |
| { |
| dev_err(&data->client->dev, "[touch]set_direction for irq gpio failed\n"); |
| goto err_irq_gpio_dir; |
| } |
| } |
| return 0; |
| } else |
| { |
| if (gpio_is_valid(data->pdata->irq_gpio)) |
| { |
| gpio_free(data->pdata->irq_gpio); |
| } |
| return 0; |
| } |
| |
| err_irq_gpio_dir: |
| if (gpio_is_valid(data->pdata->irq_gpio)) |
| { |
| gpio_free(data->pdata->irq_gpio); |
| } |
| err_irq_gpio_req: |
| return err; |
| } |
| |
| /******************************************************************************* |
| * Name: raydium_power_on |
| * Brief: |
| * Input: |
| * Output: |
| * Return: |
| *******************************************************************************/ |
| static int raydium_power_on(struct raydium_ts_data *data, bool on) |
| { |
| int rc = 0; |
| |
| if (!on) |
| { |
| goto power_off; |
| } |
| |
| regulator_set_optimum_mode(data->vcc_i2c,100000); |
| rc = regulator_enable(data->vcc_i2c); |
| if (rc) |
| { |
| dev_err(&data->client->dev, "[touch]Regulator vcc_i2c enable failed rc=%d\n", rc); |
| } |
| return rc; |
| |
| power_off: |
| regulator_set_optimum_mode(data->vcc_i2c,100); |
| rc = regulator_disable(data->vcc_i2c); |
| if (rc) |
| { |
| dev_err(&data->client->dev, "[touch]Regulator vcc_i2c disable failed rc=%d\n", rc); |
| } |
| return rc; |
| } |
| |
| /******************************************************************************* |
| * Name: raydium_power_init |
| * Brief: |
| * Input: |
| * Output: |
| * Return: |
| *******************************************************************************/ |
| static int raydium_power_init(struct raydium_ts_data *data, bool on) |
| { |
| int rc; |
| |
| if (!on) |
| { |
| dev_err(&data->client->dev, "[touch]power_init false \n"); |
| goto pwr_deinit; |
| } |
| |
| data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c"); |
| if (IS_ERR(data->vcc_i2c)) |
| { |
| rc = PTR_ERR(data->vcc_i2c); |
| dev_err(&data->client->dev, "[touch]regulator get failed vcc_i2c rc=%d\n", rc); |
| return rc; |
| } |
| |
| if (regulator_count_voltages(data->vcc_i2c) > 0) |
| { |
| rc = regulator_set_voltage(data->vcc_i2c, I2C_VTG_MIN_UV, I2C_VTG_MAX_UV); |
| if (rc) |
| { |
| dev_err(&data->client->dev, "[touch]regulator set_vtg failed vcc_i2c rc=%d\n", rc); |
| goto reg_vcc_i2c_put; |
| } |
| } |
| return 0; |
| |
| reg_vcc_i2c_put: |
| regulator_put(data->vcc_i2c); |
| return rc; |
| |
| pwr_deinit: |
| if (regulator_count_voltages(data->vcc_i2c) > 0) |
| { |
| regulator_set_voltage(data->vcc_i2c, 0, I2C_VTG_MAX_UV); |
| } |
| regulator_put(data->vcc_i2c); |
| return 0; |
| } |
| |
| /******************************************************************************* |
| * Name: raydium_ts_pinctrl_init |
| * Brief: |
| * Input: |
| * Output: |
| * Return: |
| *******************************************************************************/ |
| #ifdef MSM_NEW_VER |
| static int raydium_ts_pinctrl_init(struct raydium_ts_data *data) |
| { |
| int retval; |
| |
| /* Get pinctrl if target uses pinctrl */ |
| data->ts_pinctrl = devm_pinctrl_get(&(data->client->dev)); |
| if (IS_ERR_OR_NULL(data->ts_pinctrl)) |
| { |
| retval = PTR_ERR(data->ts_pinctrl); |
| dev_err(&data->client->dev, "[touch]target does not use pinctrl %d\n", retval); |
| goto err_pinctrl_get; |
| } |
| |
| data->pinctrl_state_active |
| = pinctrl_lookup_state(data->ts_pinctrl, PINCTRL_STATE_ACTIVE); |
| if (IS_ERR_OR_NULL(data->pinctrl_state_active)) |
| { |
| retval = PTR_ERR(data->pinctrl_state_active); |
| dev_err(&data->client->dev, |
| "[touch]Can not lookup %s pinstate %d\n", |
| PINCTRL_STATE_ACTIVE, retval); |
| goto err_pinctrl_lookup; |
| } |
| |
| data->pinctrl_state_suspend |
| = pinctrl_lookup_state(data->ts_pinctrl, |
| PINCTRL_STATE_SUSPEND); |
| if (IS_ERR_OR_NULL(data->pinctrl_state_suspend)) |
| { |
| retval = PTR_ERR(data->pinctrl_state_suspend); |
| dev_err(&data->client->dev, |
| "[touch]Can not lookup %s pinstate %d\n", |
| PINCTRL_STATE_SUSPEND, retval); |
| goto err_pinctrl_lookup; |
| } |
| |
| data->pinctrl_state_release |
| = pinctrl_lookup_state(data->ts_pinctrl, |
| PINCTRL_STATE_RELEASE); |
| if (IS_ERR_OR_NULL(data->pinctrl_state_release)) |
| { |
| retval = PTR_ERR(data->pinctrl_state_release); |
| dev_err(&data->client->dev, |
| "[touch]Can not lookup %s pinstate %d\n", |
| PINCTRL_STATE_RELEASE, retval); |
| } |
| |
| return 0; |
| |
| err_pinctrl_lookup: |
| devm_pinctrl_put(data->ts_pinctrl); |
| err_pinctrl_get: |
| data->ts_pinctrl = NULL; |
| return retval; |
| } |
| #endif//end of MSM_NEW_VER |
| |
| static int raydium_i2c_pda_set_address(struct raydium_ts_data *data, |
| unsigned long address, unsigned char mode) |
| { |
| int retval = 0; |
| unsigned char retry; |
| unsigned char buf[RAYDIUM_I2C_PDA_ADDRESS_LENGTH]; |
| struct i2c_client *i2c = data->client; |
| |
| u8_i2c_mode = PDA_MODE; |
| |
| i2c->addr = RAYDIUM_I2C_EID; |
| buf[0] = (address & 0x0000FF00) >> 8; |
| buf[1] = (address & 0x00FF0000) >> 16; |
| buf[2] = (address & 0xFF000000) >> 24; |
| buf[3] = mode; |
| |
| for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) |
| { |
| retval = i2c_master_send(i2c, buf, RAYDIUM_I2C_PDA_ADDRESS_LENGTH); |
| if (retval != RAYDIUM_I2C_PDA_ADDRESS_LENGTH) |
| { |
| dev_err(&i2c->dev,"[touch]%s: I2C retry %d\n",__func__, retry + 1); |
| msleep(20); |
| } else |
| { |
| break; |
| } |
| } |
| |
| return (retval == RAYDIUM_I2C_PDA_ADDRESS_LENGTH) ? retval : -EIO; |
| } |
| |
| //device attribute raydium_i2c_pda2_mode used |
| static int raydium_i2c_pda_read(struct i2c_client *client, |
| unsigned long addr, unsigned char *r_data, unsigned short length) |
| { |
| int retval; |
| unsigned char retry; |
| unsigned char mode = 0x00; |
| unsigned char buf; |
| struct raydium_ts_data *data = i2c_get_clientdata(client); |
| |
| struct i2c_msg msg[] = { |
| { |
| .addr = RAYDIUM_I2C_NID, |
| .flags = RAYDIUM_I2C_WRITE, |
| .len = 1, |
| .buf = &buf, |
| }, |
| { |
| .addr = RAYDIUM_I2C_NID, |
| .flags = RAYDIUM_I2C_READ, |
| .len = length, |
| .buf = r_data, |
| }, |
| }; |
| |
| if (length == 4) |
| { |
| mode |= RAYDIUM_I2C_PDA_MODE_ENABLE | RAYDIUM_I2C_PDA_2_MODE_DISABLE | RAYDIUM_I2C_PDA_MODE_WORD_MODE; |
| } else |
| { |
| mode |= RAYDIUM_I2C_PDA_MODE_ENABLE | RAYDIUM_I2C_PDA_2_MODE_DISABLE; |
| } |
| buf = addr & MASK_8BIT; |
| |
| retval = raydium_i2c_pda_set_address(data, addr, mode); |
| if (retval != RAYDIUM_I2C_PDA_ADDRESS_LENGTH) |
| { |
| goto exit; |
| } |
| usleep_range(50, 80); |
| |
| for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) |
| { |
| if (i2c_transfer(data->client->adapter, msg, 2) == 2) |
| { |
| retval = length; |
| break; |
| } |
| dev_err(&data->client->dev,"%s: I2C retry %d\n",__func__, retry + 1); |
| msleep(20); |
| } |
| |
| if (retry == SYN_I2C_RETRY_TIMES) |
| { |
| dev_err(&data->client->dev,"%s: I2C read over retry limit\n",__func__); |
| retval = -EIO; |
| } |
| exit: |
| return retval; |
| } |
| |
| static int raydium_i2c_pda_write(struct i2c_client *client, |
| unsigned long addr, unsigned char *w_data, unsigned short length) |
| { |
| int retval; |
| unsigned char retry; |
| unsigned char mode = 0x00; |
| unsigned char buf[MAX_WRITE_PACKET_SIZE + 1]; |
| struct raydium_ts_data *data = i2c_get_clientdata(client); |
| |
| struct i2c_msg msg[] = { |
| { |
| .addr = RAYDIUM_I2C_NID, |
| .flags = RAYDIUM_I2C_WRITE, |
| .len = length + 1, |
| .buf = buf, |
| }, |
| }; |
| |
| |
| if (length > MAX_WRITE_PACKET_SIZE) |
| { |
| return -EINVAL; |
| } |
| |
| if (length == 4) |
| { |
| mode |= RAYDIUM_I2C_PDA_MODE_ENABLE | RAYDIUM_I2C_PDA_2_MODE_DISABLE | RAYDIUM_I2C_PDA_MODE_WORD_MODE; |
| } |
| else |
| { |
| mode |= RAYDIUM_I2C_PDA_MODE_ENABLE | RAYDIUM_I2C_PDA_2_MODE_DISABLE; |
| } |
| |
| buf[0] = addr & MASK_8BIT; |
| memcpy(&buf[1], w_data, length); |
| |
| retval = raydium_i2c_pda_set_address(data, addr, mode); |
| if (retval != RAYDIUM_I2C_PDA_ADDRESS_LENGTH) |
| { |
| goto exit; |
| } |
| usleep_range(50, 80); |
| |
| for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) |
| { |
| if (i2c_transfer(client->adapter, msg, 1) == 1) |
| { |
| retval = length; |
| break; |
| } |
| dev_err(&data->client->dev,"[touch]%s: I2C retry %d\n",__func__, retry + 1); |
| msleep(20); |
| } |
| |
| if (retry == SYN_I2C_RETRY_TIMES) |
| { |
| dev_err(&data->client->dev,"[touch]%s: I2C write over retry limit\n",__func__); |
| retval = -EIO; |
| } |
| exit: |
| return retval; |
| } |
| |
| static int raydium_i2c_pda2_set_page(struct i2c_client *client, unsigned char page) |
| { |
| int retval = -1; |
| unsigned char retry; |
| unsigned char buf[RAYDIUM_I2C_PDA2_PAGE_LENGTH]; |
| struct raydium_ts_data *data = i2c_get_clientdata(client); |
| |
| struct i2c_msg msg[] = { |
| { |
| .addr = RAYDIUM_I2C_NID, |
| .flags = RAYDIUM_I2C_WRITE, |
| .len = RAYDIUM_I2C_PDA2_PAGE_LENGTH, |
| .buf = buf, |
| }, |
| }; |
| |
| buf[0] = RAYDIUM_PDA2_PAGE_ADDR; |
| buf[1] = page; |
| |
| for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) |
| { |
| if (i2c_transfer(client->adapter, msg, 1) == 1) |
| { |
| retval = RAYDIUM_I2C_PDA2_PAGE_LENGTH; |
| break; |
| } |
| msleep(20); |
| } |
| |
| if (retry == SYN_I2C_RETRY_TIMES) |
| { |
| dev_err(&data->client->dev,"[touch]%s: I2C write over retry limit\n",__func__); |
| retval = -EIO; |
| } |
| |
| return retval; |
| } |
| |
| static int raydium_i2c_pda2_read(struct i2c_client *client, |
| unsigned char addr, unsigned char *r_data, unsigned short length) |
| { |
| int retval = -1; |
| unsigned char retry; |
| struct raydium_ts_data *data = i2c_get_clientdata(client); |
| |
| struct i2c_msg msg[] = { |
| { |
| .addr = RAYDIUM_I2C_NID, |
| .flags = RAYDIUM_I2C_WRITE, |
| .len = 1, |
| .buf = &addr, |
| }, |
| { |
| .addr = RAYDIUM_I2C_NID, |
| .flags = RAYDIUM_I2C_READ, |
| .len = length, |
| .buf = r_data, |
| }, |
| }; |
| u8_i2c_mode = PDA2_MODE; |
| for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) |
| { |
| if (i2c_transfer(data->client->adapter, msg, 2) == 2) |
| { |
| retval = length; |
| break; |
| } |
| msleep(20); |
| } |
| |
| if (retry == SYN_I2C_RETRY_TIMES) |
| { |
| dev_err(&data->client->dev,"[touch]%s: I2C read over retry limit\n",__func__); |
| retval = -EIO; |
| } |
| |
| return retval; |
| } |
| |
| static int raydium_i2c_pda2_write(struct i2c_client *client, |
| unsigned char addr, unsigned char *w_data, unsigned short length) |
| { |
| int retval = -1; |
| unsigned char retry; |
| unsigned char buf[MAX_WRITE_PACKET_SIZE + 1]; |
| struct raydium_ts_data *data = i2c_get_clientdata(client); |
| |
| struct i2c_msg msg[] = { |
| { |
| .addr = RAYDIUM_I2C_NID, |
| .flags = RAYDIUM_I2C_WRITE, |
| .len = length + 1, |
| .buf = buf, |
| }, |
| }; |
| |
| |
| if (length > MAX_WRITE_PACKET_SIZE) |
| { |
| return -EINVAL; |
| } |
| u8_i2c_mode = PDA2_MODE; |
| buf[0] = addr; |
| memcpy(&buf[1], w_data, length); |
| |
| for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) |
| { |
| if (i2c_transfer(client->adapter, msg, 1) == 1) |
| { |
| retval = length; |
| break; |
| } |
| msleep(20); |
| } |
| |
| if (retry == SYN_I2C_RETRY_TIMES) |
| { |
| dev_err(&data->client->dev,"[touch]%s: I2C write over retry limit\n",__func__); |
| retval = -EIO; |
| } |
| |
| return retval; |
| } |
| |
| static void raydium_irq_control(struct raydium_ts_data *ts, bool enable) |
| { |
| if (enable) |
| { |
| if (ts->irq_enabled) |
| { |
| return; |
| } |
| |
| /* Clear interrupts first */ |
| mutex_lock(&ts->lock); |
| if (raydium_i2c_pda2_set_page(ts->client, RAYDIUM_PDA2_PAGE_0) < 0) |
| { |
| dev_err(&ts->client->dev, "[touch]failed to set page %s\n", __func__); |
| } |
| mutex_unlock(&ts->lock); |
| mdelay(1); |
| enable_irq(ts->irq); |
| ts->irq_enabled = true; |
| printk(KERN_INFO "[touch]irq enable\n"); |
| } else |
| { |
| if (ts->irq_enabled) |
| { |
| disable_irq(ts->irq); |
| ts->irq_enabled = false; |
| printk(KERN_INFO "[touch]irq disable\n"); |
| } |
| } |
| } |
| |
| #ifdef CONFIG_RM_SYSFS_DEBUG |
| static int raydium_get_palm_state(struct raydium_ts_data *raydium_ts, unsigned char pre_palm_status) |
| { |
| unsigned char rbuffer[1]; |
| unsigned int ui_palm_status = 0; |
| unsigned char tp_status[MAX_TCH_STATUS_PAKAGE_SIZE]; |
| int ret = -1; |
| |
| mutex_lock(&raydium_ts->lock); |
| // Read palm state |
| ret = raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| ret = raydium_i2c_pda2_read(raydium_ts->client, RAYDIUM_PDA2_PALM_STATUS_ADDR, rbuffer, 1); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| ui_palm_status = rbuffer[0]; |
| if (ui_palm_status == RAYDIUM_PALM_MODE_ENABLE || (ui_palm_status == RAYDIUM_PALM_MODE_DISABLE && pre_palm_status == RAYDIUM_PALM_MODE_ENABLE)) |
| { |
| //clear seq num |
| tp_status[POS_SEQ] = 0; |
| ret = raydium_i2c_pda2_write(raydium_ts->client, RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR, tp_status, 1); |
| if (ret < 0) |
| { |
| dev_err(&raydium_ts->client->dev, "[touch]%s: failed to write data: %d\n",__func__, ret); |
| goto exit_error; |
| } |
| } |
| mutex_unlock(&raydium_ts->lock); |
| return ui_palm_status; |
| |
| exit_error: |
| mutex_unlock(&raydium_ts->lock); |
| return ret; |
| } |
| |
| static int raydium_set_palm_state(struct raydium_ts_data *raydium_ts, unsigned char set_palm) |
| { |
| unsigned char wbuffer[1]; |
| unsigned int ui_palm_status = 0; |
| int ret = -1; |
| |
| mutex_lock(&raydium_ts->lock); |
| // Read palm state |
| ret = raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| wbuffer[0] = set_palm; |
| ret = raydium_i2c_pda2_write(raydium_ts->client, RAYDIUM_PDA2_PALM_STATUS_ADDR, wbuffer, 1); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| mutex_unlock(&raydium_ts->lock); |
| return ui_palm_status; |
| |
| exit_error: |
| mutex_unlock(&raydium_ts->lock); |
| return ret; |
| } |
| |
| static ssize_t raydium_touch_calibration_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| unsigned char rbuffer[1]; |
| int buf_len = 0; |
| int ret = -1; |
| unsigned char 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); |
| |
| if (ts->is_suspend) |
| { |
| printk(KERN_INFO "[touch]Raydium IC is_suspend at %s\n", __func__); |
| } |
| raydium_irq_control(ts, DISABLE); |
| mutex_lock(&ts->lock); |
| |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| rbuffer[0] = RAYDIUM_HOST_CMD_CALIBRATION; |
| ret = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_HOST_CMD_ADDR, rbuffer, 1); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| |
| do { |
| if (rbuffer[0] == RAYDIUM_HOST_CMD_NO_OP) |
| { |
| break; |
| } else |
| { |
| msleep(1000); |
| } |
| ret = raydium_i2c_pda2_read(client, RAYDIUM_PDA2_HOST_CMD_ADDR, rbuffer, 1); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| printk(KERN_INFO "[touch]Raydium %s return 0x%02x!!\n", __func__, rbuffer[0]); |
| } while (retry++ < (SYN_I2C_RETRY_TIMES * 2)); |
| |
| memcpy(buf, rbuffer, 1); |
| |
| buf_len = strlen(buf); |
| ret = buf_len + 1; |
| |
| exit_i2c_error: |
| mutex_unlock(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| |
| return ret; |
| } |
| |
| static ssize_t raydium_check_i2c_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| unsigned char rbuffer[4]; |
| int buf_len = 0; |
| int ret = -1; |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| if (ts->is_suspend) |
| { |
| printk(KERN_INFO "[touch]Raydium IC is_suspend at %s\n", __func__); |
| } |
| raydium_irq_control(ts, DISABLE); |
| mutex_lock(&ts->lock); |
| |
| if (u8_i2c_mode == PDA2_MODE) |
| { |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| *(unsigned long *)rbuffer = (RAYDIUM_I2C_PDA_MODE_ENABLE << 24) | ((RAYDIUM_CHECK_I2C_CMD & (~MASK_8BIT)) >> 8); //using byte mode to read 4 bytes |
| |
| ret = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_PDA_CFG_ADDR, rbuffer, 4); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_ENABLE_PDA); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| ret = raydium_i2c_pda2_read(client, (unsigned char)(RAYDIUM_CHECK_I2C_CMD& MASK_8BIT), rbuffer, 4); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| } else |
| { |
| ret = raydium_i2c_pda_read(client, RAYDIUM_CHECK_I2C_CMD, rbuffer, 4); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| } |
| |
| sprintf(buf, "[touch]Raydium Touch check i2c : %02X%02X\n", rbuffer[3], rbuffer[2]); |
| buf_len = strlen(buf); |
| ret = buf_len + 1; |
| |
| exit_i2c_error: |
| mutex_unlock(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| return ret; |
| } |
| |
| static int raydium_i2c_mode_control(struct i2c_client *client, unsigned char mode) |
| { |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| switch (mode) |
| { |
| case 2: /* Disable INT */ |
| raydium_irq_control(ts, DISABLE); |
| printk("Raydium disable INT\n"); |
| break; |
| case 3: /* Enable INT */ |
| raydium_irq_control(ts, ENABLE); |
| printk("Raydium enable INT\n"); |
| break; |
| } |
| return 0; |
| } |
| |
| /***************************************************************************** |
| ** Function name: bits_reverse |
| ** Descriptions: MSB/LSB exchange. |
| ** parameters: num:input data, bit_num:data bit number |
| ** Returned value: reverse value |
| *****************************************************************************/ |
| static unsigned int bits_reverse(unsigned int num, unsigned int bit_num) |
| { |
| unsigned int reverse = 0, i; |
| |
| for (i = 0; i < bit_num; i++) |
| { |
| if (num & (1 << i)) |
| { |
| reverse |= 1<< ((bit_num - 1) -i); |
| } |
| } |
| return reverse; |
| } |
| /***************************************************************************** |
| ** Function name: rc_crc32 |
| ** Descriptions: 32 bits checksum calculation. |
| ** parameters: buf:start address, len:length |
| ** Returned value: checksum |
| *****************************************************************************/ |
| static unsigned int rc_crc32(const char *buf, unsigned int len, unsigned int crc) |
| { |
| unsigned int i; |
| unsigned char flash_byte, uc_current, j; |
| |
| for (i = 0; i < len; i++) |
| { |
| flash_byte = buf[i]; |
| uc_current = (unsigned char)bits_reverse(flash_byte, 8); |
| for (j = 0; j <8; j++) |
| { |
| if ((crc ^ uc_current ) & 0x01) |
| { |
| crc = (crc >> 1) ^ 0xedb88320; |
| } else |
| { |
| crc >>= 1; |
| } |
| uc_current >>= 1; |
| } |
| } |
| return crc; |
| } |
| |
| /* upgrade firmware with image file */ |
| static int raydium_fw_upgrade_with_image(struct i2c_client *client, unsigned long ul_fw_addr, unsigned char type) |
| { |
| int ret = -1; |
| unsigned long ul_fw_size = 0; |
| unsigned char *firmware_data; |
| unsigned long ul_write_offset = 0; |
| unsigned short us_write_length = 0; |
| unsigned int ui_checksum = 0xFFFFFFFF; |
| |
| firmware_data = kzalloc(RAYDIUM_FW_MAX_SIZE, GFP_KERNEL); |
| if (firmware_data == NULL ) |
| { |
| pr_err("kzalloc firmware_data failed\n"); |
| return -ENOMEM; |
| } |
| |
| memset(firmware_data, 0, ul_fw_size); |
| |
| switch (type) |
| { |
| case RAYDIUM_INIT: |
| memcpy(firmware_data, RadInitImage, 0x1FC); |
| ul_fw_size = 0x1FC; |
| break; |
| case RAYDIUM_BASELINE: |
| memcpy(firmware_data, (RadFWImage + 0xA04), 0x2CC); |
| ul_fw_size = 0x2CC; |
| break; |
| case RAYDIUM_COMP: |
| memcpy(firmware_data, (RadFWImage + 0xCD4), 0x244); |
| ul_fw_size = 0x244; |
| break; |
| case RAYDIUM_PARA: |
| memcpy(firmware_data, (RadFWImage + 0xF1C), 0xE0); |
| ul_fw_size = 0xE0; |
| break; |
| case RAYDIUM_FIRMWARE: |
| memcpy(firmware_data, (RadFWImage + 0x1000), 0x4FFC); |
| ul_fw_size = 0x4FFC; |
| break; |
| case RAYDIUM_BOOTLOADER: |
| memcpy(firmware_data, RadBootImage, 0x7FC); |
| memcpy((firmware_data + 0x800), RadInitImage, 0x1FC); |
| ul_fw_size = 0x9FC; |
| break; |
| case RAYDIUM_TEST_FW: |
| memcpy((firmware_data + 4), (RadTestFWImage + 0xA04), 0x55FC); |
| ul_fw_size = 0x55FC; |
| break; |
| } |
| |
| if (type == RAYDIUM_TEST_FW) |
| { |
| ui_checksum = rc_crc32((firmware_data + 4) , ul_fw_size, ui_checksum); |
| printk(KERN_INFO "[touch]Raydium ui_checksum : 0x%08X\n", ui_checksum); |
| ui_checksum = bits_reverse(ui_checksum, 32); |
| memcpy(firmware_data, &ui_checksum, 4); |
| } else |
| { |
| ui_checksum = rc_crc32(firmware_data, ul_fw_size, ui_checksum); |
| printk(KERN_INFO "[touch]Raydium ui_checksum : 0x%08X\n", ui_checksum); |
| ui_checksum = bits_reverse(ui_checksum, 32); |
| memcpy((firmware_data + ul_fw_size), &ui_checksum, 4); |
| } |
| printk(KERN_INFO "[touch]Raydium ui_checksum after bits reverse: 0x%08X\n", ui_checksum); |
| printk(KERN_INFO "[touch]Raydium (firmware_data + ul_fw_size): 0x%08X\n", *(unsigned int*)(firmware_data + ul_fw_size)); |
| ul_fw_size += 4; |
| |
| ul_write_offset = 0; |
| while (ul_write_offset < ul_fw_size) |
| { |
| if ((ul_write_offset + MAX_WRITE_PACKET_SIZE) < ul_fw_size) |
| { |
| us_write_length = MAX_WRITE_PACKET_SIZE; |
| } else |
| { |
| us_write_length = (unsigned short)(ul_fw_size - ul_write_offset); |
| } |
| |
| ret = raydium_i2c_pda_write(client, (ul_fw_addr + ul_write_offset), (firmware_data + ul_write_offset), us_write_length); |
| if (ret < 0) |
| { |
| goto exit_upgrate; |
| } |
| ul_write_offset += (unsigned long)us_write_length; |
| } |
| ul_fw_addr += ul_write_offset; |
| |
| exit_upgrate: |
| kfree(firmware_data); |
| if (ret < 0) |
| { |
| pr_err("[touch]upgrade firmware Failed\n"); |
| return ret; |
| } else |
| { |
| pr_err("[touch]upgrade firmware Successfully\n"); |
| return 0; |
| } |
| } |
| |
| static int raydium_do_software_reset(struct i2c_client * client) |
| { |
| int ret = SUCCESS; |
| unsigned int retry, retry_time = 1000; |
| unsigned int irq_value; |
| unsigned char buf[4]; |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| //#enable INT |
| g_uc_raydium_flag = RAYDIUM_BOOTLOADER_FLAG; |
| printk(KERN_INFO "[touch]ready to software reset => enable INT\n"); |
| raydium_irq_control(ts, ENABLE); |
| |
| //SW reset |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x01; |
| printk(KERN_INFO "[touch]Raydium SW reset\n"); |
| ret = raydium_i2c_pda_write(client, 0x40000004, buf, 4); |
| if (ret < 0) |
| { |
| goto exit; |
| } |
| retry = retry_time; |
| while (retry != 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| msleep(2); |
| retry--; |
| printk(KERN_INFO "[touch]wait software reset finish => confirm interrupt_flag result %d\n", retry); |
| } |
| |
| //#disable INT |
| if (retry == 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| printk(KERN_INFO "[touch]no interrupt => disable INT\n"); |
| raydium_irq_control(ts, DISABLE); |
| g_uc_raydium_flag = 0; |
| } |
| |
| if (g_uc_raydium_flag == RAYDIUM_INTERRUPT_FLAG) |
| { |
| retry = retry_time; |
| irq_value = 0; |
| while (retry != 0 && irq_value != 1) |
| { |
| irq_value = gpio_get_value(ts->pdata->irq_gpio); |
| printk(KERN_INFO "[touch]irq_value is %d\n", irq_value); |
| msleep(2); |
| retry--; |
| } |
| } |
| |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]%s, FW not ready, retry error!\n", __func__); |
| ret = ERROR; |
| } |
| |
| exit: |
| return ret; |
| } |
| |
| static int raydium_wait_ft_int(struct i2c_client * client) |
| { |
| int ret = SUCCESS; |
| unsigned int retry, retry_time = 1000; |
| unsigned int irq_value; |
| |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| //#enable INT |
| g_uc_raydium_flag = RAYDIUM_BOOTLOADER_FLAG; |
| |
| retry = retry_time; |
| while (retry != 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| msleep(2); |
| retry--; |
| } |
| |
| //#disable INT |
| if (retry == 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| g_uc_raydium_flag = 0; |
| } |
| |
| if (g_uc_raydium_flag == RAYDIUM_INTERRUPT_FLAG) |
| { |
| retry = retry_time; |
| irq_value = 0; |
| while (retry != 0 && irq_value != 1) |
| { |
| irq_value = gpio_get_value(ts->pdata->irq_gpio); |
| printk(KERN_INFO "[touch]irq_value is %d\n", irq_value); |
| msleep(2); |
| retry--; |
| } |
| } |
| |
| if (retry == 0) |
| { |
| printk(KERN_INFO "[touch]%s, FT Test not ready, retry error!\n", __func__); |
| ret = ERROR; |
| } else |
| { |
| raydium_irq_control(ts, ENABLE); |
| } |
| return ret; |
| } |
| |
| static int raydium_check_fw_ready(struct i2c_client * client) |
| { |
| int ret = SUCCESS; |
| unsigned int retry, retry_time = 400; |
| unsigned char buf[4]; |
| |
| buf[1] = 0; |
| retry = retry_time; |
| while (buf[1] != 0x40 && retry != 0) |
| { |
| printk(KERN_INFO "[touch]confirm boot is finish 0x%x\n", buf[1]); |
| ret = raydium_i2c_pda_read(client, 0x50000918, buf, 4); |
| if (ret < 0) |
| { |
| goto exit; |
| } |
| retry --; |
| msleep(5); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, confirm boot is finish 0x%x\n", buf[1]); |
| ret = -1; |
| goto exit; |
| } |
| |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]%s, FW not ready, retry error!\n", __func__); |
| ret = ERROR; |
| } else |
| { |
| printk(KERN_INFO "[touch]%s, FW is ready!!\n", __func__); |
| msleep(5); |
| } |
| |
| exit: |
| return ret; |
| } |
| |
| static int set_skip_load(struct i2c_client * client) |
| { |
| int ret = SUCCESS; |
| unsigned char buf[4]; |
| |
| /*Return to Bootloader in PRAM*/ |
| //Skip load |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x10; |
| buf[1]=0x08; |
| printk(KERN_INFO "[touch]Raydium skip load\n"); |
| ret = raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_do_software_reset(client); |
| |
| exit_upgrade: |
| return ret; |
| } |
| |
| static int raydium_load_test_fw(struct i2c_client * client) |
| { |
| int ret = SUCCESS; |
| unsigned char buf[4]; |
| unsigned int retry, retry_time = 200; |
| unsigned char is_MCU_HOLD; |
| unsigned int irq_value; |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| ret = raydium_i2c_pda_read(client, 0x50000918, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| is_MCU_HOLD = buf[1] & 0x20; |
| printk(KERN_INFO "[touch]is_MCU_HOLD = %d\n", is_MCU_HOLD); |
| |
| //#enable INT |
| g_uc_raydium_flag = RAYDIUM_BOOTLOADER_FLAG; |
| printk(KERN_INFO "[touch]ready to software reset => enable INT\n"); |
| raydium_irq_control(ts, ENABLE); |
| |
| //Skip load |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x10; |
| buf[1]=0x08; |
| printk(KERN_INFO "[touch]Raydium skip load\n"); |
| ret = raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x01; |
| ret = raydium_i2c_pda_write(client, 0x40000004, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| if (is_MCU_HOLD == 0) |
| { |
| retry = retry_time; |
| while (retry != 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| msleep(10); |
| retry--; |
| printk(KERN_INFO "[touch]wait software reset finish => confirm interrupt_flag result %d\n", retry); |
| } |
| |
| //#disable INT |
| if (retry == 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| printk(KERN_INFO "[touch]no interrupt => disable INT\n"); |
| raydium_irq_control(ts, DISABLE); |
| g_uc_raydium_flag = 0; |
| } |
| |
| if (g_uc_raydium_flag == RAYDIUM_INTERRUPT_FLAG) |
| { |
| retry = retry_time; |
| irq_value = 0; |
| while (retry!=0 && irq_value!=1) |
| { |
| irq_value = gpio_get_value(ts->pdata->irq_gpio); |
| printk(KERN_INFO "[touch]irq_value is %d\n", irq_value); |
| msleep(10); |
| retry--; |
| } |
| } |
| |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]%s, FW not ready, retry error!\n", __func__); |
| ret = ERROR; |
| goto exit_upgrade; |
| } |
| } else |
| { |
| msleep(100); |
| raydium_irq_control(ts, DISABLE); |
| } |
| |
| //set mcu hold |
| raydium_i2c_pda_read(client, 0x50000918, buf, 4); |
| buf[0] |= 0x20; |
| raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| raydium_i2c_pda_read(client, 0x40000004, buf, 4); |
| buf[0] |= 0x01; |
| raydium_i2c_pda_write(client, 0x40000004, buf, 4); |
| |
| /*WRT boot-loader to PRAM first*/ |
| memset(buf, 0, sizeof(buf)); |
| printk("[touch]Raydium WRT boot-loader to PRAM first\n"); |
| ret = raydium_i2c_pda_write(client, 0x50000900, buf, 4); |
| |
| /*Sending bootloader*/ |
| ret = raydium_fw_upgrade_with_image(client, 0x0000, RAYDIUM_BOOTLOADER); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| |
| //release mcu hold |
| raydium_i2c_pda_read(client, 0x50000918, buf, 4); |
| buf[0] &= ~0x20; |
| buf[0] |= 0x10; |
| raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| raydium_i2c_pda_read(client, 0x40000004, buf, 4); |
| buf[0] |= 0x01; |
| raydium_i2c_pda_write(client, 0x40000004, buf, 4); |
| msleep(50); |
| |
| ret = raydium_i2c_pda_read(client, 0x40000000, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| buf[3] |= 0x40; |
| ret = raydium_i2c_pda_write(client, 0x40000000, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_i2c_pda_read(client, 0x40000014, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| buf[0] |= 0x04; |
| buf[1] |= 0x04; |
| ret = raydium_i2c_pda_write(client, 0x40000014, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| |
| memset(buf, 0, sizeof(buf)); |
| printk(KERN_INFO "[touch]Raydium WRT test_fw to PRAM\n"); |
| |
| ret = raydium_i2c_pda_write(client, 0x50000900, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| /*Sending test fw*/ |
| ret = raydium_fw_upgrade_with_image(client, 0xA00, RAYDIUM_TEST_FW); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //Skip load |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x10; |
| printk(KERN_INFO "[touch]Raydium skip load\n"); |
| ret = raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_do_software_reset(client); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_check_fw_ready(client); |
| |
| exit_upgrade: |
| return ret; |
| } |
| |
| static int raydium_boot_upgrade(struct i2c_client * client) |
| { |
| int ret = SUCCESS; |
| unsigned char buf[4]; |
| unsigned int retry, retry_time = 200; |
| unsigned char is_MCU_HOLD; |
| unsigned int irq_value; |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| ret = raydium_i2c_pda_read(client, 0x50000918, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| is_MCU_HOLD = buf[1] & 0x20; |
| printk(KERN_INFO "[touch]is_MCU_HOLD = %d\n", is_MCU_HOLD); |
| |
| //#enable INT |
| g_uc_raydium_flag = RAYDIUM_BOOTLOADER_FLAG; |
| printk(KERN_INFO "[touch]ready to software reset => enable INT\n"); |
| raydium_irq_control(ts, ENABLE); |
| |
| /* Return to Bootloader */ |
| memset(buf, 0, sizeof(buf)); |
| buf[0] = 0x00; |
| buf[1] = 0x08; |
| raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| memset(buf, 0, sizeof(buf)); |
| buf[0] |= 0x01; |
| raydium_i2c_pda_write(client, 0x40000004, buf, 4); |
| |
| if (is_MCU_HOLD == 0) |
| { |
| retry = retry_time; |
| while (retry != 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| msleep(10); |
| retry--; |
| printk(KERN_INFO "[touch]wait software reset finish => confirm interrupt_flag result %d\n", retry); |
| } |
| |
| //#disable INT |
| if (retry == 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| printk(KERN_INFO "[touch]no interrupt => disable INT\n"); |
| raydium_irq_control(ts, DISABLE); |
| g_uc_raydium_flag = 0; |
| } |
| |
| if (g_uc_raydium_flag == RAYDIUM_INTERRUPT_FLAG) |
| { |
| retry = retry_time; |
| irq_value = 0; |
| while (retry!=0 && irq_value!=1) |
| { |
| irq_value = gpio_get_value(ts->pdata->irq_gpio); |
| printk(KERN_INFO "[touch]irq_value is %d\n", irq_value); |
| msleep(10); |
| retry--; |
| } |
| } |
| |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]%s, FW not ready, retry error!\n", __func__); |
| ret = ERROR; |
| goto exit_upgrade; |
| } |
| } else |
| { |
| raydium_irq_control(ts, DISABLE); |
| msleep(100); |
| } |
| |
| //set mcu hold |
| raydium_i2c_pda_read(client, 0x50000918, buf, 4); |
| buf[0] |= 0x20; |
| raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| raydium_i2c_pda_read(client, 0x40000004, buf, 4); |
| buf[0] |= 0x01; |
| raydium_i2c_pda_write(client, 0x40000004, buf, 4); |
| |
| /*WRT boot-loader to PRAM first*/ |
| memset(buf, 0, sizeof(buf)); |
| printk(KERN_INFO "[touch]WRT boot-loader to PRAM first\n"); |
| ret = raydium_i2c_pda_write(client, 0x50000900, buf, 4); |
| |
| /*Sending bootloader*/ |
| ret = raydium_fw_upgrade_with_image(client, 0x0000, RAYDIUM_BOOTLOADER); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| |
| //release mcu hold |
| raydium_i2c_pda_read(client, 0x50000918, buf, 4); |
| buf[0] &= ~0x20; |
| buf[0] |= 0x10; |
| raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| raydium_i2c_pda_read(client, 0x40000004, buf, 4); |
| buf[0] |= 0x01; |
| raydium_i2c_pda_write(client, 0x40000004, buf, 4); |
| msleep(50); |
| |
| ret = raydium_i2c_pda_read(client, 0x40000000, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| buf[3] |= 0x40; |
| ret = raydium_i2c_pda_write(client, 0x40000000, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_i2c_pda_read(client, 0x40000014, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| buf[0] |= 0x04; |
| buf[1] |= 0x04; |
| ret = raydium_i2c_pda_write(client, 0x40000014, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //Skip load |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x10; |
| buf[1]=0x08; |
| printk("Raydium skip load\n"); |
| ret = raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_do_software_reset(client); |
| |
| exit_upgrade: |
| return ret; |
| } |
| |
| /* Raydium fireware upgrade flow */ |
| static int raydium_fw_upgrade(struct i2c_client * client, unsigned char type, unsigned char isSkipLoad, unsigned char isCheckCRCError) |
| { |
| int ret = 0; |
| unsigned char buf[4]; |
| unsigned int retry, retry_time = 200; |
| unsigned int irq_value; |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| //##### wait for boot-loader start ##### |
| printk(KERN_INFO "[touch]type is %d\n", type); |
| //#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(buf, 0, sizeof(buf)); |
| buf[0]=0x01; |
| ret = raydium_i2c_pda_write(client, 0x20000204, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x20000208, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x2000020C, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x01; |
| ret = raydium_i2c_pda_write(client, 0x20000218, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //#confirm in burn mode |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 63 && retry != 0) |
| { |
| printk(KERN_INFO "[touch]confirm in burn mode 0x%x\n", buf[0]); |
| ret = raydium_i2c_pda_read(client, 0x50000900, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| msleep(10); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, confirm in burn mode 0x%x\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| |
| printk(KERN_INFO "[touch]VVVVVVVVVVVVVVV Type : %d ==> Start VVVVVVVVVVVVVVV\n", type); |
| |
| //Clear BL_CRC |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x10; |
| ret = raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| if (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(buf, 0, sizeof(buf)); |
| buf[0]=type; |
| ret = raydium_i2c_pda_write(client, 0x50000904, buf, 4); |
| if (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 (type == RAYDIUM_INIT) |
| { |
| printk(KERN_INFO "[touch]Set PRAM addr & length type=0x01\n"); |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x00; |
| buf[1]=0x08; |
| ret = raydium_i2c_pda_write(client, 0x50000908, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x00; |
| buf[1]=0x02; |
| ret = raydium_i2c_pda_write(client, 0x5000090C, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } else if (type == RAYDIUM_BASELINE) |
| { |
| printk(KERN_INFO "[touch]Set PRAM addr & length type=0x02\n"); |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x04; |
| buf[1]=0x0a; |
| ret = raydium_i2c_pda_write(client, 0x50000908, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0xd0; |
| buf[1]=0x02; |
| ret = raydium_i2c_pda_write(client, 0x5000090C, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } else if (type == RAYDIUM_COMP) |
| { |
| printk(KERN_INFO "[touch]Set PRAM addr & length type=0x04\n"); |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0xd4; |
| buf[1]=0x0c; |
| ret = raydium_i2c_pda_write(client, 0x50000908, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x48; |
| buf[1]=0x02; |
| ret = raydium_i2c_pda_write(client, 0x5000090C, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } else if (type == RAYDIUM_PARA) |
| { |
| printk(KERN_INFO "[touch]Set PRAM addr & length type=0x08\n"); |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x1c; |
| buf[1]=0x0f; |
| ret = raydium_i2c_pda_write(client, 0x50000908, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0xe4; |
| ret = raydium_i2c_pda_write(client, 0x5000090C, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } else if (type == RAYDIUM_FIRMWARE) |
| { |
| printk(KERN_INFO "[touch]Set PRAM addr & length type=0x10\n"); |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x1C; |
| buf[1]=0x0F; |
| ret = raydium_i2c_pda_write(client, 0x50000908, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0xE4; |
| buf[1]=0x50; |
| ret = raydium_i2c_pda_write(client, 0x5000090C, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } else if (type == RAYDIUM_BOOTLOADER) |
| { |
| printk(KERN_INFO "[touch]Set PRAM addr & length type=0x20\n"); |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x00; |
| buf[1]=0x40; |
| ret = raydium_i2c_pda_write(client, 0x50000908, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0]=0x00; |
| buf[1]=0x0A; |
| ret = raydium_i2c_pda_write(client, 0x5000090C, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } |
| |
| //#set sync_data(0x20000200) = 0 as WRT data finish |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x20000200, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //#Wait bootloader check addr and PRAM unlock |
| //#Confirm g_u8_sync_data.ret_data at 0x20000214 is SET_ADDR_READY |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 161 && retry != 0) |
| { |
| msleep(10); |
| ret = raydium_i2c_pda_read(client, 0x20000214, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| printk(KERN_INFO "[touch]Confirm g_u8_sync_data.ret_data is SET_ADDR_READY %d\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, Confirm g_u8_sync_data.ret_data is SET_ADDR_READY %d\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| |
| //#Confirm g_u8_sync_data.cmd_type at 0x20000210 is WRT_PRAM_DATA |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 163 && retry != 0) |
| { |
| msleep(10); |
| ret = raydium_i2c_pda_read(client, 0x20000210, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| printk(KERN_INFO "[touch]Confirm g_u8_sync_data.cmd_type is WRT_PRAM_DATA %d\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, Confirm g_u8_sync_data.cmd_type is WRT_PRAM_DATA %d\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| |
| //#start write data to PRAM |
| if (type == RAYDIUM_INIT) |
| { |
| ret = raydium_fw_upgrade_with_image(client, 0x800, RAYDIUM_INIT); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } else if (type == RAYDIUM_PARA) |
| { |
| ret = raydium_fw_upgrade_with_image(client, 0xF1C, RAYDIUM_PARA); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } else if (type == RAYDIUM_FIRMWARE) |
| { |
| ret = raydium_fw_upgrade_with_image(client, 0xF1C, RAYDIUM_PARA); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_fw_upgrade_with_image(client, 0x1000, RAYDIUM_FIRMWARE); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } else if (type == RAYDIUM_BOOTLOADER) |
| { |
| ret = raydium_fw_upgrade_with_image(client, 0x4000, RAYDIUM_BOOTLOADER); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } |
| |
| //#set sync_data(0x20000200) = 0 as WRT data finish, bootloader check checksum |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x20000200, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //#wait(checksum okay) ACK cmd(gu8I2CSyncData.cmd_type=0xa5 at 0x20000210) |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 165 && retry != 0) |
| { |
| msleep(10); |
| ret = raydium_i2c_pda_read(client, 0x20000210, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| printk(KERN_INFO "[touch]wait(checksum okay) ACK cmd 0x%x\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, wait(checksum okay) ACK cmd 0x%x\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| |
| //#confirm ACK cmd result(gu8I2CSyncData.ret_data=0xa5 at 0x20000214) |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 165 && retry != 0) |
| { |
| msleep(10); |
| ret = raydium_i2c_pda_read(client, 0x20000214, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| printk(KERN_INFO "[touch]confirm ACK cmd result 0x%x\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, confirm ACK cmd result 0x%x\n", buf[0]); |
| ret = -1; |
| 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(buf, 0, sizeof(buf)); |
| buf[0] = 0x5a; |
| ret = raydium_i2c_pda_write(client, 0x20000214, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //#clr sync_data(0x20000200) = 0 as finish |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x20000200, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //#wait for input unlock key |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 168 && retry != 0) |
| { |
| msleep(10); |
| ret = raydium_i2c_pda_read(client, 0x20000210, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| printk(KERN_INFO "[touch]wait for input unlock key 0x%x\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, wait for input unlock key 0x%x\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| |
| //#unlock key |
| memset(buf, 0, sizeof(buf)); |
| buf[0] = 0xd7; |
| ret = raydium_i2c_pda_write(client, 0x50000938, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0] = 0xa5; |
| ret = raydium_i2c_pda_write(client, 0x50000934, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x50000934, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| buf[0] = 0xa5; |
| ret = raydium_i2c_pda_write(client, 0x50000934, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x50000938, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //#wrt return data as unlock value |
| memset(buf, 0, sizeof(buf)); |
| buf[0] = 0xa8; |
| ret = raydium_i2c_pda_write(client, 0x20000214, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //#clr sync_data(0x20000200) = 0 as finish |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x20000200, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| msleep(500); |
| |
| //#wait erase/wrt finish |
| //#confirm burning_state result(gu8I2CSyncData.burning_state=BURNING_WRT_FLASH_FINISH at 0x2000020C) |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 6 && retry != 0) |
| { |
| msleep(10); |
| ret = raydium_i2c_pda_read(client, 0x2000020c, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| printk(KERN_INFO "[touch]confirm burning_state result %d\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, confirm burning_state result %d\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| |
| //############## Use Interrupt to wait sofware reset ############## |
| //#clr sync_data(0x20000200) = 0 as finish |
| //#Set bootloader flag |
| //#RAYDIUM_INTERRUPT_FLAG = 0x01 |
| //#RAYDIUM_BOOTLOADER_FLAG = 0x02 |
| g_uc_raydium_flag = RAYDIUM_BOOTLOADER_FLAG; |
| //#enable INT |
| printk(KERN_INFO "[touch]ready to software reset => enable INT\n"); |
| raydium_irq_control(ts, ENABLE); |
| |
| if (type == RAYDIUM_BOOTLOADER) |
| { |
| ret = raydium_i2c_pda_read(client, 0x50000918, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| buf[0] |= 0x10; |
| ret = raydium_i2c_pda_write(client, 0x50000918, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| } |
| |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x20000200, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| |
| //#wait software reset finish |
| //#confirm RAYDIUM_INTERRUPT_FLAG result (if raydium_flag = 1 => pass) |
| retry = retry_time; |
| while (retry != 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| msleep(10); |
| retry--; |
| printk(KERN_INFO "[touch]wait software reset finish => confirm interrupt_flag result %d\n", g_uc_raydium_flag); |
| } |
| |
| //#disable INT |
| if (retry == 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| printk(KERN_INFO "[touch]no interrupt => disable INT\n"); |
| raydium_irq_control(ts, DISABLE); |
| g_uc_raydium_flag = 0; |
| } |
| |
| if (g_uc_raydium_flag == RAYDIUM_INTERRUPT_FLAG) |
| { |
| retry = retry_time; |
| irq_value = 0; |
| while (retry != 0 && irq_value != 1) |
| { |
| irq_value = gpio_get_value(ts->pdata->irq_gpio); |
| printk(KERN_INFO "[touch]irq_value is %d\n", irq_value); |
| msleep(10); |
| retry--; |
| } |
| } |
| |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]%s, FW not ready, retry error!\n", __func__); |
| ret = ERROR; |
| goto exit_upgrade; |
| } |
| //################################################################# |
| |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 130 && retry != 0) |
| { |
| msleep(10); |
| ret = raydium_i2c_pda_read(client, 0x20000214, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| printk(KERN_INFO "[touch]wait software reset finished %d\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, wait software reset finished %d\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| |
| if (type == RAYDIUM_BASELINE || type == RAYDIUM_INIT || isCheckCRCError == 1) |
| { |
| //#set test_mode = 1 |
| memset(buf, 0, sizeof(buf)); |
| buf[0] = 0x01; |
| ret = raydium_i2c_pda_write(client, 0x20000218, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| //#wait crc check finish |
| //#confirm gu8I2CSyncData.normal_state=NORMAL_CRC_NOTIFY at 0x20000208 |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 2 && retry != 0) |
| { |
| msleep(10); |
| ret = raydium_i2c_pda_read(client, 0x20000208, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| printk(KERN_INFO "[touch]confirm gu8I2CSyncData.normal_state=NORMAL_CRC_NOTIFY %d\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, confirm gu8I2CSyncData.normal_state=NORMAL_CRC_NOTIFY %d\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| |
| //#crc check pass 0x20000214 = 0x81 |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 0x81 && retry != 0) |
| { |
| msleep(10); |
| ret = raydium_i2c_pda_read(client, 0x20000214, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| retry --; |
| printk(KERN_INFO "[touch]confirm crc result 0x20000214 = %d\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, confirm crc result 0x20000214 = %d\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| } |
| |
| //#run to next step |
| printk(KERN_INFO "[touch]^^^^^^^^^^^^^^^ Type: 0x%x ==> Pass ^^^^^^^^^^^^^^^\n", type); |
| |
| if (isCheckCRCError) |
| { |
| buf[0] = 0; |
| retry = retry_time; |
| while (buf[0] != 2 && retry != 0) |
| { |
| ret = raydium_i2c_pda_read(client, 0x50000918, buf, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| msleep(10); |
| buf[0] = buf[0] & 47; |
| retry --; |
| printk(KERN_INFO "[touch]BL1_CRC_ERR %d\n", buf[0]); |
| } |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]Error, BL1_CRC_ERR %d\n", buf[0]); |
| ret = -1; |
| goto exit_upgrade; |
| } |
| |
| //#clr sync para |
| memset(buf, 0, sizeof(buf)); |
| ret = raydium_i2c_pda_write(client, 0x20000210, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_i2c_pda_write(client, 0x20000214, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_i2c_pda_write(client, 0x20000218, buf, 4); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| |
| printk(KERN_INFO "[touch]Raydium HW reset\n"); |
| gpio_direction_output(ts->rst, 1); |
| gpio_direction_output(ts->rst, 0); |
| msleep(RAYDIUM_RESET_INTERVAL_MSEC); |
| gpio_direction_output(ts->rst, 1); |
| msleep(500); |
| |
| u8_i2c_mode = PDA2_MODE; |
| |
| printk(KERN_INFO "[touch]Burn FW finish!\n"); |
| } |
| |
| exit_upgrade: |
| return ret; |
| } |
| |
| |
| static int raydium_burn_fw(struct i2c_client *client) |
| { |
| int ret = 0; |
| |
| ret = raydium_boot_upgrade(client); |
| |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_fw_upgrade(client, RAYDIUM_BOOTLOADER, 0, 0); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| ret = raydium_fw_upgrade(client, RAYDIUM_FIRMWARE, 0, 1); |
| if (ret < 0) |
| { |
| goto exit_upgrade; |
| } |
| exit_upgrade: |
| return ret; |
| } |
| |
| static ssize_t raydium_fw_upgrade_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0; |
| |
| /* receive command line arguments string */ |
| if (count > 2) |
| { |
| return -EINVAL; |
| } |
| ret = kstrtou8(buf, 16, &upgrade_type); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| return count; |
| } |
| |
| static ssize_t raydium_fw_upgrade_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| int ret = 0, result = 0; |
| int buf_len = 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); |
| |
| raydium_irq_control(ts, DISABLE); |
| printk(KERN_INFO "[touch]Raydium %s burn type is %d!!\n", __func__, upgrade_type); |
| |
| if (upgrade_type == 1) |
| { |
| ret = raydium_burn_fw(client); |
| if (ret < 0) |
| { |
| result = FAIL; |
| goto exit_upgrade; |
| } |
| result = SUCCESS; |
| } else if (upgrade_type == 2) |
| { |
| ret = set_skip_load(client); |
| if (ret < 0) |
| { |
| result = FAIL; |
| goto exit_upgrade; |
| } |
| ret = raydium_fw_upgrade(client, RAYDIUM_COMP, 0, 1); |
| if (ret < 0) |
| { |
| result = FAIL; |
| goto exit_upgrade; |
| } |
| result = SUCCESS; |
| } else if (upgrade_type == 3) |
| { |
| ret = set_skip_load(client); |
| if (ret < 0) |
| { |
| result = FAIL; |
| goto exit_upgrade; |
| } |
| ret = raydium_fw_upgrade(client, RAYDIUM_BASELINE, 0, 1); |
| if (ret < 0) |
| { |
| result = FAIL; |
| goto exit_upgrade; |
| } |
| result = SUCCESS; |
| } else if (upgrade_type == 4) |
| { |
| ret = raydium_load_test_fw(client); |
| if (ret < 0) |
| { |
| result = FAIL; |
| goto exit_upgrade; |
| } |
| result = SUCCESS; |
| } |
| |
| exit_upgrade: |
| raydium_irq_control(ts, ENABLE); |
| upgrade_type = 0; |
| sprintf(buf, "FW Upgrade result : %d\n", result); |
| buf_len = strlen(buf); |
| return buf_len+1; |
| } |
| |
| |
| /* upgrade firmware with *.bin file */ |
| static int raydium_fw_upgrade_with_bin_file(struct i2c_client *client, char *arguments, size_t count) |
| { |
| int ret = 0; |
| char *temp_buf, *token, *free_temp_buf, *free_token; |
| const char *delim = " ,"; |
| unsigned long ul_fw_offset = 0; |
| unsigned char uc_fw_amount = 0; |
| mm_segment_t old_fs; |
| struct file *fw_fd = NULL; |
| unsigned long ul_fw_size = 0, ul_fw_read_size = 0; |
| char *firmware_data; |
| unsigned long ul_write_offset = 0; |
| unsigned short us_write_length = 0; |
| unsigned int ui_checksum = 0xFFFFFFFF; |
| |
| /* receive command line arguments string */ |
| if (count < 2) |
| { |
| return -EINVAL; |
| } |
| firmware_data = kzalloc(RAYDIUM_FW_MAX_SIZE, GFP_KERNEL); |
| if (firmware_data == NULL) |
| { |
| pr_err("[touch]kzalloc firmware_data failed\n"); |
| return -ENOMEM; |
| } |
| |
| temp_buf = kzalloc(RAYDIUM_FW_BIN_PATH_LENGTH+1, GFP_KERNEL); |
| if (temp_buf == NULL) |
| { |
| pr_err("[touch]kzalloc temp_buf failed\n"); |
| kfree(firmware_data); |
| return -ENOMEM; |
| } |
| |
| token = kzalloc(RAYDIUM_FW_BIN_PATH_LENGTH+1, GFP_KERNEL); |
| if (token == NULL ) |
| { |
| pr_err("[touch]kzalloc token failed\n"); |
| kfree(firmware_data); |
| kfree(temp_buf); |
| return -ENOMEM; |
| } |
| |
| free_temp_buf = temp_buf; |
| free_token = token; |
| strncpy(temp_buf, arguments, count); |
| token = strsep(&temp_buf, delim); |
| |
| ret = kstrtoul(token, 16, &ul_fw_offset); |
| if (ret < 0) |
| { |
| goto exit_upgrate; |
| } |
| |
| token = strsep(&temp_buf, delim); |
| ret = kstrtou8(token, 16, &uc_fw_amount); |
| if (ret < 0) |
| { |
| goto exit_upgrate; |
| } |
| |
| while (uc_fw_amount--) |
| { |
| if (!temp_buf) |
| { |
| break; |
| } |
| |
| token = strsep(&temp_buf, delim); |
| ret = kstrtoul(token, 16, &ul_fw_size); |
| if (ret < 0) |
| { |
| goto exit_upgrate; |
| } |
| |
| token = strsep(&temp_buf, delim); |
| |
| old_fs = get_fs(); |
| set_fs(get_ds()); |
| |
| fw_fd = filp_open(token, O_RDONLY, 0); |
| if (IS_ERR(fw_fd)) |
| { |
| pr_err("[touch]error occured while opening file %s.\n", token); |
| set_fs(old_fs); |
| kfree(firmware_data); |
| kfree(free_token); |
| kfree(free_temp_buf); |
| return -ENOENT; |
| } |
| |
| memset(firmware_data, 0, ul_fw_size); |
| ul_fw_read_size = fw_fd->f_op->read(fw_fd, firmware_data, ul_fw_size, &fw_fd->f_pos); |
| ui_checksum = rc_crc32(firmware_data, ul_fw_size, ui_checksum); |
| |
| if (uc_fw_amount == 0) |
| { |
| ui_checksum = bits_reverse(ui_checksum, 32); |
| memcpy((firmware_data + ul_fw_size), &ui_checksum, 4); |
| ul_fw_size += 4; |
| } |
| |
| set_fs(old_fs); |
| filp_close(fw_fd,NULL); |
| |
| ul_write_offset = 0; |
| while (ul_write_offset < ul_fw_size) |
| { |
| if ((ul_write_offset + MAX_WRITE_PACKET_SIZE) < ul_fw_size) |
| { |
| us_write_length = MAX_WRITE_PACKET_SIZE; |
| } |
| else |
| { |
| us_write_length = (unsigned short)(ul_fw_size - ul_write_offset); |
| } |
| ret = raydium_i2c_pda_write(client, (ul_fw_offset + ul_write_offset), (firmware_data + ul_write_offset), us_write_length); |
| if (ret < 0) |
| { |
| goto exit_upgrate; |
| } |
| ul_write_offset += (unsigned long)us_write_length; |
| } |
| ul_fw_offset += ul_write_offset; |
| } |
| |
| exit_upgrate: |
| kfree(firmware_data); |
| kfree(free_token); |
| kfree(free_temp_buf); |
| if (ret < 0) |
| { |
| pr_err("[touch]Upgrage firmware Failed\n"); |
| return ret; |
| } else { |
| pr_err("[touch]Upgrage firmware Successfully\n"); |
| return 0; |
| } |
| } |
| |
| static ssize_t raydium_upgrade_firmware_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0; |
| char fwname[RAYDIUM_FW_BIN_PATH_LENGTH]; |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| if (count > RAYDIUM_FW_BIN_PATH_LENGTH) |
| { |
| return -EINVAL; |
| } |
| memset(fwname, 0, sizeof(fwname)); |
| sprintf(fwname, "%s", buf); |
| fwname[count - 1] = '\0'; |
| |
| if (ts->is_suspend) |
| { |
| printk(KERN_INFO "[touch]Raydium IC is_suspend at %s\n", __func__); |
| } |
| |
| /* start to upgrade binary file*/ |
| mutex_lock(&ts->lock); |
| ret = raydium_fw_upgrade_with_bin_file(client, fwname, count); |
| mutex_unlock(&ts->lock); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| return count; |
| } |
| |
| static ssize_t raydium_i2c_pda2_mode_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0; |
| unsigned char mode; |
| |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| if (ts->is_suspend) |
| { |
| printk(KERN_INFO "[touch]Raydium IC is_suspend at %s\n", __func__); |
| } |
| |
| /* receive command line arguments string */ |
| if (count > 2) |
| { |
| return -EINVAL; |
| } |
| |
| ret = kstrtou8(buf, 16, &mode); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| ret = raydium_i2c_mode_control(client, mode); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| return count; |
| } |
| |
| static ssize_t raydium_i2c_pda_access_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| unsigned char rbuffer[4]; |
| int buf_len = 0; |
| int ret = -1; |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| if (g_ui_length > 4) |
| { |
| return -EINVAL; |
| } |
| memset(rbuffer, 0x00, 4); |
| mutex_lock(&ts->lock); |
| ret = raydium_i2c_pda_read(client, g_ul_addr, rbuffer, g_ui_length); |
| mutex_unlock(&ts->lock); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| sprintf(buf, "0x%08lX : 0x%02X%02X%02X%02X\n", g_ul_addr, |
| rbuffer[3], rbuffer[2], rbuffer[1], rbuffer[0]); |
| buf_len = strlen(buf); |
| |
| return buf_len+1; |
| } |
| |
| static ssize_t raydium_i2c_pda_access_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0, result = 0; |
| char *temp_buf, *token, *free_temp_buf, *free_token; |
| const char *delim = " ,"; |
| unsigned char w_data[MAX_WRITE_PACKET_SIZE]; |
| unsigned int data_count = 0; |
| unsigned int data_index = 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); |
| |
| /* receive command line arguments string */ |
| if (count < 2) |
| { |
| return -EINVAL; |
| } |
| |
| temp_buf = kzalloc(count+1, GFP_KERNEL); |
| if (temp_buf == NULL) |
| { |
| printk(KERN_INFO "[touch]kzalloc temp_buf failed\n"); |
| return -ENOMEM; |
| } |
| |
| token = kzalloc(count+1, GFP_KERNEL); |
| if (token == NULL) |
| { |
| printk(KERN_INFO "[touch]kzalloc token failed\n"); |
| kfree(temp_buf); |
| return -ENOMEM; |
| } |
| |
| free_temp_buf = temp_buf; |
| free_token = token; |
| |
| ret = (ssize_t) count; |
| |
| strncpy(temp_buf, buf, count); |
| |
| token = strsep(&temp_buf, delim); |
| |
| result = kstrtoul(token, 16, &g_ul_addr); |
| |
| token = strsep(&temp_buf, delim); |
| if (token) |
| { |
| result = kstrtouint(token, 16, &data_count); |
| } else |
| { |
| goto exit_error; |
| } |
| if (g_ui_length > MAX_WRITE_PACKET_SIZE) |
| { |
| return -EINVAL; |
| } |
| g_ui_length = data_count; |
| |
| memset(w_data, 0x00, MAX_WRITE_PACKET_SIZE); |
| |
| if (temp_buf && data_count) |
| { |
| data_index = 0; |
| while (data_count) |
| { |
| token = strsep(&temp_buf, delim); |
| result = kstrtou8(token, 16, &w_data[data_index++]); |
| if (result < 0) |
| { |
| ret = result; |
| goto exit_error; |
| } |
| data_count--; |
| } |
| mutex_lock(&ts->lock); |
| result = raydium_i2c_pda_write(client, g_ul_addr, w_data, g_ui_length); |
| mutex_unlock(&ts->lock); |
| if (result < 0) |
| { |
| ret = result; |
| } |
| } |
| |
| exit_error: |
| kfree(free_token); |
| kfree(free_temp_buf); |
| return ret; |
| } |
| |
| unsigned char g_uc_addr = RAYDIUM_PDA2_PDA_CFG_ADDR; |
| |
| static ssize_t raydium_i2c_pda2_access_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| unsigned char rbuffer[4]; |
| int buf_len = 0; |
| int ret = -1; |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| if (g_ui_length > 4) |
| { |
| return -EINVAL; |
| } |
| memset(rbuffer, 0x00, 4); |
| |
| mutex_lock(&ts->lock); |
| ret = raydium_i2c_pda2_read(client, g_uc_addr, rbuffer, g_ui_length); |
| mutex_unlock(&ts->lock); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| sprintf(buf, "0x%04X : 0x%02X%02X%02X%02X\n", g_uc_addr, |
| rbuffer[3], rbuffer[2], rbuffer[1], rbuffer[0]); |
| buf_len = strlen(buf); |
| |
| return buf_len+1; |
| } |
| |
| static ssize_t raydium_i2c_pda2_access_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0, result = 0; |
| char *temp_buf, *token, *free_temp_buf, *free_token; |
| const char *delim = " ,"; |
| unsigned char w_data[MAX_WRITE_PACKET_SIZE]; |
| unsigned int data_count = 0; |
| unsigned int data_index = 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); |
| |
| /* receive command line arguments string */ |
| if (count < 2) |
| { |
| return -EINVAL; |
| } |
| temp_buf = kzalloc(count+1, GFP_KERNEL); |
| if (temp_buf == NULL ) |
| { |
| printk(KERN_ERR "[touch]kzalloc temp_buf failed\n"); |
| return -ENOMEM; |
| } |
| |
| token = kzalloc(count+1, GFP_KERNEL); |
| if (token == NULL ) |
| { |
| printk(KERN_ERR "[touch]kzalloc token failed\n"); |
| kfree(temp_buf); |
| return -ENOMEM; |
| } |
| |
| free_temp_buf = temp_buf; |
| free_token = token; |
| |
| ret = (ssize_t) count; |
| |
| strncpy(temp_buf, buf, count); |
| |
| token = strsep(&temp_buf, delim); |
| |
| result = kstrtou8(token, 16, &g_uc_addr); |
| |
| token = strsep(&temp_buf, delim); |
| if (token) |
| { |
| result = kstrtouint(token, 16, &data_count); |
| } else |
| { |
| ret = -EINVAL; |
| goto exit_error; |
| } |
| |
| if (data_count > MAX_WRITE_PACKET_SIZE) |
| { |
| ret = -EINVAL; |
| goto exit_error; |
| } |
| |
| memset(w_data, 0x00, MAX_WRITE_PACKET_SIZE); |
| |
| g_ui_length = data_count; |
| |
| if (temp_buf && data_count) |
| { |
| data_index = 0; |
| while (data_count) |
| { |
| token = strsep(&temp_buf, delim); |
| result = kstrtou8(token, 16, &w_data[data_index++]); |
| if (result < 0) |
| { |
| ret = result; |
| goto exit_error; |
| } |
| data_count--; |
| } |
| |
| mutex_lock(&ts->lock); |
| result = raydium_i2c_pda2_write(client, g_uc_addr, w_data, g_ui_length); |
| mutex_unlock(&ts->lock); |
| if (result < 0) |
| { |
| ret = result; |
| goto exit_error; |
| } |
| } |
| |
| exit_error: |
| kfree(free_token); |
| kfree(free_temp_buf); |
| return ret; |
| } |
| |
| static ssize_t raydium_i2c_pda2_page_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0, result = 0; |
| unsigned char 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); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| /* receive command line arguments string */ |
| if (count < 2) |
| { |
| return -EINVAL; |
| } |
| temp_buf = kzalloc(count+1, GFP_KERNEL); |
| if (temp_buf == NULL) |
| { |
| printk(KERN_ERR "[touch]kzalloc temp_buf failed\n"); |
| return -ENOMEM; |
| } |
| |
| token = kzalloc(count+1, GFP_KERNEL); |
| if (token == NULL) |
| { |
| printk(KERN_ERR "[touch]kzalloc token failed\n"); |
| kfree(temp_buf); |
| return -ENOMEM; |
| } |
| |
| free_temp_buf = temp_buf; |
| free_token = token; |
| |
| ret = (ssize_t) count; |
| |
| strncpy(temp_buf, buf, count); |
| |
| token = strsep(&temp_buf, delim); |
| |
| if (temp_buf) |
| { |
| printk(KERN_ERR "[touch]Raydium input error, extra auguments!n"); |
| ret = -EINVAL; |
| goto exit_error; |
| } |
| result = kstrtou8(token, 16, &page); |
| |
| if (result < 0) |
| { |
| ret = result; |
| goto exit_error; |
| } |
| |
| raydium_irq_control(ts, DISABLE); |
| mutex_lock(&ts->lock); |
| |
| result = raydium_i2c_pda2_set_page(client, page); |
| if (result < 0) |
| { |
| ret = result; |
| 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(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| |
| exit_error: |
| kfree(free_token); |
| kfree(free_temp_buf); |
| return ret; |
| } |
| |
| static ssize_t raydium_i2c_raw_data_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| unsigned char rbuffer[MAX_READ_PACKET_SIZE]; |
| unsigned int ui_read_target_addr; |
| unsigned int ui_read_offset; |
| unsigned short us_read_length; |
| int ret = -1; |
| int 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); |
| |
| memset(rbuffer, 0x00, MAX_READ_PACKET_SIZE); |
| |
| // make sure update flag was set |
| for (retry = 0 ; retry < SYN_I2C_RETRY_TIMES ; retry++) |
| { |
| mutex_lock(&ts->lock); |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| ret = raydium_i2c_pda2_read(client, RAYDIUM_PDA2_HOST_CMD_ADDR, rbuffer, RAYDIUM_FT_CMD_LENGTH); |
| mutex_unlock(&ts->lock); |
| if (ret < 0) |
| { |
| goto exit_flag_error; |
| } |
| if ((rbuffer[RAYDIUM_FT_CMD_POS] & RAYDIUM_FT_UPDATE) == RAYDIUM_FT_UPDATE) |
| { |
| break; |
| } |
| msleep(5); |
| } |
| |
| if (retry == SYN_I2C_RETRY_TIMES) |
| { |
| ret = -EAGAIN; |
| goto exit_flag_error; |
| } |
| |
| ui_read_offset = 0; |
| us_read_length = 0; |
| while (ui_read_offset < g_ui_raw_data_length) |
| { |
| if ((ui_read_offset + MAX_READ_PACKET_SIZE) < g_ui_raw_data_length) |
| { |
| us_read_length = MAX_READ_PACKET_SIZE; |
| } |
| else |
| { |
| us_read_length = (unsigned short)(g_ui_raw_data_length - ui_read_offset); |
| } |
| ui_read_target_addr = RAYDIUM_READ_FT_DATA_CMD + ui_read_offset; |
| |
| mutex_lock(&(ts->lock)); |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| goto exit_i2c_error; |
| |
| *(unsigned long *)rbuffer = (RAYDIUM_I2C_PDA_MODE_ENABLE << 24) | ((ui_read_target_addr & (~MASK_8BIT)) >> 8); //using byte mode to read 4 bytes |
| |
| ret = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_PDA_CFG_ADDR, rbuffer, 4); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_ENABLE_PDA); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| ret = raydium_i2c_pda2_read(client, (unsigned char)(ui_read_target_addr& MASK_8BIT), rbuffer, us_read_length); |
| mutex_unlock(&(ts->lock)); |
| if (ret < 0) |
| { |
| goto exit_flag_error; |
| } |
| memcpy((buf + ui_read_offset), rbuffer, us_read_length); |
| |
| ui_read_offset += us_read_length; |
| } |
| |
| // clear update flag to get next one |
| rbuffer[RAYDIUM_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP; |
| rbuffer[RAYDIUM_FT_CMD_POS] = g_uc_raw_data_type; |
| mutex_lock(&ts->lock); |
| ret = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_HOST_CMD_ADDR, rbuffer, RAYDIUM_FT_CMD_LENGTH); |
| mutex_unlock(&ts->lock); |
| if (ret < 0) |
| { |
| goto exit_flag_error; |
| } |
| |
| return g_ui_raw_data_length; |
| exit_i2c_error: |
| mutex_unlock(&(ts->lock)); |
| exit_flag_error: |
| return ret; |
| } |
| |
| static ssize_t raydium_i2c_raw_data_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0; |
| int result = 0; |
| char *temp_buf, *token, *free_temp_buf, *free_token; |
| const char *delim = " ,"; |
| unsigned char w_data[RAYDIUM_FT_CMD_LENGTH]; |
| |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| /* receive command line arguments string */ |
| if (count < 2) |
| { |
| return -EINVAL; |
| } |
| temp_buf = kzalloc(count+1, GFP_KERNEL); |
| if (temp_buf == NULL ) |
| { |
| printk(KERN_ERR "[touch]kzalloc temp_buf failed\n"); |
| return -ENOMEM; |
| } |
| |
| token = kzalloc(count+1, GFP_KERNEL); |
| if (token == NULL ) |
| { |
| printk(KERN_ERR "[touch]kzalloc token failed\n"); |
| kfree(temp_buf); |
| return -ENOMEM; |
| } |
| |
| free_temp_buf = temp_buf; |
| free_token = token; |
| |
| ret = (ssize_t) count; |
| |
| strncpy(temp_buf, buf, count); |
| |
| token = strsep(&temp_buf, delim); |
| |
| result = kstrtou8(token, 16, &g_uc_raw_data_type); |
| |
| token = strsep(&temp_buf, delim); |
| if (token) |
| { |
| result = kstrtouint(token, 16, &g_ui_raw_data_length); |
| if (result < 0) |
| { |
| ret = result; |
| goto exit_error; |
| } |
| |
| } else // without length info |
| { |
| ret = -EINVAL; |
| goto exit_error; |
| } |
| |
| if (temp_buf) // too much arguments |
| { |
| ret = -E2BIG; |
| goto exit_error; |
| } |
| |
| memset(w_data, 0x00, RAYDIUM_FT_CMD_LENGTH); |
| |
| mutex_lock(&ts->lock); |
| result = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_PAGE_0); |
| if (result < 0) |
| { |
| mutex_unlock(&ts->lock); |
| ret = result; |
| goto exit_error; |
| } |
| |
| if (g_uc_raw_data_type > 1) |
| { |
| w_data[RAYDIUM_HOST_CMD_POS]=RAYDIUM_HOST_CMD_FT_MODE; |
| } else |
| { |
| w_data[RAYDIUM_HOST_CMD_POS]=RAYDIUM_HOST_CMD_TP_MODE; |
| } |
| result = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_HOST_CMD_ADDR, w_data, 1); |
| if (result < 0) |
| { |
| mutex_unlock(&ts->lock); |
| ret = result; |
| goto exit_error; |
| } |
| |
| w_data[RAYDIUM_HOST_CMD_POS] = RAYDIUM_HOST_CMD_NO_OP; |
| w_data[RAYDIUM_FT_CMD_POS] = g_uc_raw_data_type; |
| |
| result = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_HOST_CMD_ADDR, w_data, RAYDIUM_FT_CMD_LENGTH); |
| mutex_unlock(&ts->lock); |
| if (result < 0) |
| { |
| ret = result; |
| goto exit_error; |
| } |
| |
| exit_error: |
| kfree(free_token); |
| kfree(free_temp_buf); |
| |
| return ret; |
| } |
| static ssize_t raydium_flag_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| int buf_len = 0; |
| |
| |
| sprintf(buf, "[touch]Raydium flag : %d\n", g_uc_raydium_flag); |
| g_uc_raydium_flag &= ~RAYDIUM_INTERRUPT_FLAG; |
| buf_len = strlen(buf); |
| |
| return buf_len+1; |
| } |
| |
| static ssize_t raydium_flag_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0; |
| unsigned char flag = 0; |
| |
| /* receive command line arguments string */ |
| if (count > 2) |
| { |
| return -EINVAL; |
| } |
| ret = kstrtou8(buf, 16, &flag); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| g_uc_raydium_flag = flag; |
| return count; |
| } |
| |
| static ssize_t raydium_wait_ft_int_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| unsigned int ret; |
| ret = raydium_wait_ft_int(client); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| sprintf(buf, "Raydium raydium ftint : %d\n", ret); |
| return strlen(buf) + 1; |
| } |
| |
| static ssize_t raydium_wait_ft_int_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| return count; |
| } |
| |
| static int raydium_hw_reset_fun(struct i2c_client *client) |
| { |
| int ret = SUCCESS; |
| unsigned int retry, retry_time = 1000; |
| unsigned int irq_value; |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| //#enable INT |
| g_uc_raydium_flag = RAYDIUM_BOOTLOADER_FLAG; |
| |
| //HW reset |
| printk(KERN_INFO "[touch]Raydium HW reset\n"); |
| gpio_direction_output(ts->rst, 1); |
| gpio_direction_output(ts->rst, 0); |
| msleep(RAYDIUM_RESET_INTERVAL_MSEC); |
| gpio_direction_output(ts->rst, 1); |
| |
| u8_i2c_mode = PDA2_MODE; |
| |
| retry = retry_time; |
| while (retry != 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| msleep(2); |
| retry--; |
| printk(KERN_INFO "[touch]wait software reset finish => confirm interrupt_flag result %d\n", retry); |
| } |
| |
| //#disable INT |
| if (retry == 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| g_uc_raydium_flag = 0; |
| } |
| |
| if (g_uc_raydium_flag == RAYDIUM_INTERRUPT_FLAG) |
| { |
| retry = retry_time; |
| irq_value = 0; |
| while (retry != 0 && irq_value != 1) |
| { |
| irq_value = gpio_get_value(ts->pdata->irq_gpio); |
| printk(KERN_INFO "[touch]irq_value is %d\n", irq_value); |
| msleep(2); |
| retry--; |
| } |
| } |
| |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]%s, FW not ready, retry error!\n", __func__); |
| ret = ERROR; |
| } else |
| { |
| msleep(500); |
| raydium_irq_control(ts, ENABLE); |
| } |
| |
| printk(KERN_INFO "[touch]Raydium HW reset : %d\n", ret); |
| return ret; |
| } |
| |
| static ssize_t raydium_hw_reset_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| int ret = SUCCESS; |
| unsigned int retry, retry_time = 1000; |
| unsigned int irq_value; |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| //#enable INT |
| g_uc_raydium_flag = RAYDIUM_BOOTLOADER_FLAG; |
| |
| //HW reset |
| printk(KERN_INFO "[touch]Raydium HW reset\n"); |
| gpio_direction_output(ts->rst, 1); |
| gpio_direction_output(ts->rst, 0); |
| msleep(RAYDIUM_RESET_INTERVAL_MSEC); |
| gpio_direction_output(ts->rst, 1); |
| |
| u8_i2c_mode = PDA2_MODE; |
| |
| retry = retry_time; |
| while (retry != 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| msleep(2); |
| retry--; |
| printk(KERN_INFO "[touch]wait software reset finish => confirm interrupt_flag result %d\n", retry); |
| } |
| |
| //#disable INT |
| if (retry == 0 && g_uc_raydium_flag != RAYDIUM_INTERRUPT_FLAG) |
| { |
| g_uc_raydium_flag = 0; |
| } |
| |
| if (g_uc_raydium_flag == RAYDIUM_INTERRUPT_FLAG) |
| { |
| retry = retry_time; |
| irq_value = 0; |
| while (retry != 0 && irq_value != 1) |
| { |
| irq_value = gpio_get_value(ts->pdata->irq_gpio); |
| printk(KERN_INFO "[touch]irq_value is %d\n", irq_value); |
| msleep(2); |
| retry--; |
| } |
| } |
| |
| if (retry == 0) |
| { |
| printk(KERN_ERR "[touch]%s, FW not ready, retry error!\n", __func__); |
| ret = ERROR; |
| } else |
| { |
| if (g_uc_raydium_selftest_flag == 0) |
| { |
| msleep(500); |
| } |
| raydium_irq_control(ts, ENABLE); |
| } |
| |
| sprintf(buf, "Raydium HW Reset : %d\n", ret); |
| printk("%s\n", buf); |
| return strlen(buf) + 1; |
| } |
| |
| static ssize_t raydium_palm_status_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| int buf_len = 0; |
| unsigned int palm_status; |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| palm_status = raydium_get_palm_state(ts,0); |
| sprintf(buf, "[Raydium] palm_status : %d\n", palm_status); |
| buf_len = strlen(buf); |
| return buf_len+1; |
| } |
| |
| static ssize_t raydium_palm_status_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0; |
| unsigned char palm_value = 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); |
| |
| /* receive command line arguments string */ |
| if (count > 2) |
| { |
| return -EINVAL; |
| } |
| |
| ret = kstrtou8(buf, 16, &palm_value); |
| raydium_set_palm_state(ts, palm_value); |
| return count; |
| } |
| |
| 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); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| /* receive command line arguments string */ |
| if (count > 2) |
| { |
| return -EINVAL; |
| } |
| |
| ret = kstrtou8(buf, 16, &palm_area); |
| |
| mutex_lock(&ts->lock); |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| mutex_unlock(&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(&ts->lock); |
| goto exit_error; |
| } |
| mutex_unlock(&ts->lock); |
| |
| exit_error: |
| return count; |
| } |
| |
| static ssize_t raydium_int_flag_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| int buf_len = 0; |
| |
| sprintf(buf, "%d", g_uc_raydium_int_flag); |
| printk(KERN_INFO "[touch]Raydium int flag = %s!!\n", buf); |
| |
| buf_len = strlen(buf); |
| |
| return buf_len+1; |
| } |
| |
| static ssize_t raydium_int_flag_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0; |
| unsigned char flag = 0; |
| |
| /* receive command line arguments string */ |
| if (count > 2) |
| { |
| return -EINVAL; |
| } |
| |
| ret = kstrtou8(buf, 16, &flag); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| g_uc_raydium_int_flag = flag; |
| printk(KERN_INFO "[touch]Raydium int flag store = %d!!\n", g_uc_raydium_int_flag); |
| return count; |
| } |
| |
| static ssize_t raydium_selftest_flag_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| int buf_len = 0; |
| |
| sprintf(buf, "%d", g_uc_raydium_selftest_flag); |
| printk(KERN_INFO "[touch]Raydium selftest flag = %s!!\n", buf); |
| buf_len = strlen(buf); |
| return buf_len+1; |
| } |
| |
| static ssize_t raydium_selftest_flag_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0; |
| unsigned char flag = 0; |
| printk(KERN_INFO "[touch]Raydium %s!!\n", __func__); |
| |
| /* receive command line arguments string */ |
| if (count > 2) |
| { |
| return -EINVAL; |
| } |
| |
| ret = kstrtou8(buf, 16, &flag); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| g_uc_raydium_selftest_flag = flag; |
| |
| printk(KERN_INFO "[touch]Raydium selftest flag store = %d!!\n", g_uc_raydium_selftest_flag); |
| |
| return count; |
| } |
| |
| static ssize_t raydium_touch_lock_store(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| int ret = 0; |
| unsigned char mode; |
| unsigned char wbuffer[1]; |
| |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| if (ts->is_suspend) |
| { |
| printk(KERN_INFO "[touch]Raydium IC is_suspend at %s\n", __func__); |
| } |
| |
| /* receive command line arguments string */ |
| if (count > 2) |
| { |
| return -EINVAL; |
| } |
| |
| ret = kstrtou8(buf, 16, &mode); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| raydium_irq_control(ts, DISABLE); |
| mutex_lock(&ts->lock); |
| |
| switch (mode) |
| { |
| case 0: /* Disable Touch lock */ |
| |
| if (ts->is_sleep != 1) |
| { |
| break; |
| } |
| |
| if (gpio_is_valid(ts->rst)) |
| { |
| ret = gpio_request(ts->rst, "raydium_reset_gpio"); |
| if (ret < 0) |
| { |
| dev_err(&ts->client->dev, "[touch]reset gpio request failed\n"); |
| break; |
| } |
| gpio_direction_output(ts->rst, 1); |
| gpio_direction_output(ts->rst, 0); |
| msleep(RAYDIUM_RESET_INTERVAL_MSEC);//5ms |
| gpio_direction_output(ts->rst, 1); |
| msleep(RAYDIUM_RESET_DELAY_MSEC);//100ms |
| gpio_free(ts->rst); |
| } |
| printk(KERN_INFO "[touch]Raydium %s disable touch lock!!\n", __func__); |
| ts->is_sleep = 0; |
| break; |
| |
| case 1: /* Enable Touch lock */ |
| if (ts->is_sleep == 1) |
| { |
| break; |
| } |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| wbuffer[0] = RAYDIUM_HOST_CMD_PWR_SLEEP; //fw enter sleep mode |
| ret = raydium_i2c_pda2_write(client, RAYDIUM_PDA2_HOST_CMD_ADDR, wbuffer, 1); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| printk(KERN_INFO "[touch]Raydium %s enable touch lock!!\n", __func__); |
| ts->is_sleep = 1; |
| break; |
| } |
| |
| ret = (ssize_t) count; |
| |
| exit_i2c_error: |
| mutex_unlock(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| return ret; |
| } |
| |
| static ssize_t raydium_check_fw_version_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| unsigned char rbuffer[4]; |
| int buf_len = 0; |
| int ret = -1; |
| 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 int fw_version, image_version; |
| |
| if (ts->is_suspend) |
| { |
| printk("[touch]Raydium IC is_suspend at %s\n", __func__); |
| } |
| |
| raydium_irq_control(ts, DISABLE); |
| mutex_lock(&ts->lock); |
| |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| ret = raydium_i2c_pda2_read(client, RAYDIUM_PDA2_FW_VERSION_ADDR, rbuffer, 4); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| sprintf(buf, "Raydium Touch FW Version : %02X%02X%02X%02X\n",rbuffer[0], rbuffer[1], rbuffer[2], rbuffer[3]); |
| |
| fw_version = (rbuffer[0] << 24) | (rbuffer[1] << 16) | (rbuffer[2] << 8) | rbuffer[3]; |
| printk(KERN_ERR "[touch]Raydium IC FW version is 0x%x\n", fw_version); |
| |
| image_version = (RadFWImage[0xF21] << 24) | (RadFWImage[0xF22] << 16) | (RadFWImage[0xF23] << 8) | RadFWImage[0xF24]; |
| printk(KERN_ERR "[touch]Raydium Image FW version is 0x%x\n", image_version); |
| |
| mutex_unlock(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| |
| if (fw_version != image_version) |
| { |
| printk(KERN_INFO "[touch]%s, FW need upgrade.\n", __func__); |
| } |
| |
| buf_len = strlen(buf); |
| ret = buf_len + 1; |
| goto exit_upgrade; |
| |
| exit_i2c_error: |
| mutex_unlock(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| |
| exit_upgrade: |
| return ret; |
| } |
| |
| static ssize_t raydium_check_panel_version_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| unsigned char rbuffer[8]; |
| int buf_len = 0; |
| int ret = -1; |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| struct raydium_ts_data *ts = (struct raydium_ts_data *)i2c_get_clientdata(client); |
| |
| if (ts->is_suspend) |
| { |
| printk(KERN_INFO "[touch]Raydium IC is_suspend at %s\n", __func__); |
| } |
| raydium_irq_control(ts, DISABLE); |
| mutex_lock(&ts->lock); |
| |
| ret = raydium_i2c_pda2_set_page(client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| ret = raydium_i2c_pda2_read(client, RAYDIUM_PDA2_PANEL_VERSION_ADDR, rbuffer, 8); |
| if (ret < 0) |
| { |
| goto exit_i2c_error; |
| } |
| sprintf(buf, "Raydium Touch Panel Version : %02X%02X%02X%02X%02X%02X\n", |
| rbuffer[0], rbuffer[1], rbuffer[2], rbuffer[3], rbuffer[4], rbuffer[5]); |
| mutex_unlock(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| |
| buf_len = strlen(buf); |
| ret = buf_len + 1; |
| goto exit_upgrade; |
| |
| exit_i2c_error: |
| mutex_unlock(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| exit_upgrade: |
| return ret; |
| } |
| |
| static ssize_t fw_check_show(struct device *dev, struct device_attribute *attr, char *buf) |
| { |
| int count = 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); |
| |
| if (ts->fw_version == 0) |
| { |
| count += sprintf(buf + count, "FAIL\n"); |
| } else |
| { |
| count += sprintf(buf + count, "Pass, (fw_ver : 0x%x)\n", ts->fw_version); |
| } |
| return count; |
| } |
| |
| static unsigned char i2c_burst_read(struct i2c_client *client, int int_addr, unsigned short u16ReadLen, unsigned char* p_u8_read_data) |
| { |
| unsigned char result = ERROR; |
| unsigned short u16_already_read_len = 0; |
| char u8_read = 0; |
| unsigned char rbuffer[4]; |
| int ret = 0; |
| |
| if (u16ReadLen > 4) |
| { |
| u8_read = 4; |
| } else |
| { |
| u8_read = u16ReadLen; |
| } |
| while (u16_already_read_len < u16ReadLen) |
| { |
| ret = raydium_i2c_pda_read(client, int_addr, rbuffer, u8_read); |
| if (ret < 0) |
| { |
| return result; |
| } |
| memcpy(p_u8_read_data + u16_already_read_len, rbuffer, u8_read); |
| u16_already_read_len += u8_read; |
| } |
| result = SUCCESS; |
| return result; |
| } |
| |
| static unsigned char i2c_burst_write(struct i2c_client *client, int int_addr, unsigned short bWriteLen, unsigned char* bValue) |
| { |
| unsigned char result = ERROR; |
| int ret = 0; |
| unsigned short u16_len = 0; |
| unsigned char u8_w_len = 4; |
| |
| while (u16_len < bWriteLen) |
| { |
| ret = raydium_i2c_pda_write(client, int_addr, bValue + u16_len, u8_w_len); |
| if (ret < 0) |
| { |
| return result; |
| } |
| u16_len += u8_w_len; |
| if (u16_len + u8_w_len > bWriteLen) |
| { |
| u8_w_len = bWriteLen - u16_len; |
| } |
| } |
| result = SUCCESS; |
| return result; |
| } |
| |
| static unsigned int i2c_read_4byte(struct i2c_client *client, unsigned int addr) |
| { |
| unsigned int u32Data = 0, u16ii; |
| unsigned char u8_buf[4]; |
| |
| if (i2c_burst_read(client, addr, 4, u8_buf) == SUCCESS) |
| { |
| for (u16ii = 0; u16ii < 4 && u16ii < sizeof(u8_buf); u16ii++) |
| { |
| u32Data += (u8_buf[u16ii] << (8 * u16ii)); |
| } |
| } |
| return u32Data; |
| } |
| |
| void i2c_write(struct i2c_client *client, uint32_t addr, uint32_t data) |
| { |
| unsigned char u8_data[4]; |
| u8_data[0] = (uint8_t)(data); |
| u8_data[1] = (uint8_t)(data >> 8); |
| u8_data[2] = (uint8_t)(data >> 16); |
| u8_data[3] = (uint8_t)(data >> 24); |
| i2c_burst_write(client, addr, 4, u8_data); |
| } |
| |
| static unsigned char raydium_selftest_stop_mcu(struct i2c_client *client) |
| { |
| unsigned char wData[4]; |
| unsigned int u32_read; |
| unsigned short u16_time_out = 10; |
| unsigned int MCU_HOLD_STATUS = (0x00000001<<13); |
| |
| printk(KERN_INFO "[touch]Stop MCU\r\n"); |
| i2c_burst_read(client, 0x50000918, 4, wData); |
| wData[0] |= 0x20 | 0x10; |
| i2c_burst_write(client, 0x50000918, 4, wData); |
| memset(wData, 0, sizeof(wData)); |
| wData[0] = 0x01; |
| i2c_burst_write(client, 0x40000004, 4, wData); |
| |
| u32_read = i2c_read_4byte(client, 0x50000918); |
| while ((u32_read & MCU_HOLD_STATUS) == 0 && u16_time_out-- > 0) |
| { |
| msleep(10); |
| u32_read = i2c_read_4byte(client, 0x50000918); |
| } |
| if ((u32_read & MCU_HOLD_STATUS) == 0) |
| { |
| printk(KERN_ERR "[touch]Not Enter MCU HOLD\r\n"); |
| return ERROR; |
| } else |
| { |
| printk(KERN_INFO "[touch]Enter MCU HOLD\r\n"); |
| } |
| |
| u32_read = i2c_read_4byte(client, 0x50000610); |
| u32_read &= ~(0x7f << 8); |
| u32_read |= (1 << 7); |
| u32_read &= ~((1 << 7) | (1 << 6)); |
| u32_read |= (0xF << 8); |
| i2c_write(client, 0x50000610, u32_read); |
| |
| return SUCCESS; |
| } |
| |
| static ssize_t raydium_i2c_test_show(struct device *dev, |
| struct device_attribute *attr, |
| char *buf) |
| { |
| int ret = SUCCESS; |
| |
| unsigned char wData[64], readData[64]; |
| unsigned int writeIndex = 0, i2cWriteLen = 0, i2cReadLength = 0, readLength = 0; |
| int addr = 0x20000000; |
| unsigned int u32_test_length = 256; |
| short i16_time_out = 3; |
| unsigned char u8_is_pass = 0; |
| struct i2c_client *client = container_of(dev, struct i2c_client, dev); |
| |
| printk(KERN_INFO "[touch]##RM6D010 I2C Test##\r\n"); |
| g_ui_length = 4; |
| g_ul_addr = 0x50000918; |
| raydium_i2c_pda_access_show(dev, attr, buf); |
| //Stop MCU |
| if (raydium_selftest_stop_mcu(client) == ERROR) |
| { |
| printk(KERN_ERR "[touch]Stop MCU NG\r\n"); |
| goto NG_CASE; |
| } |
| printk(KERN_INFO "[touch]After STOP MCU!\n"); |
| for (writeIndex = 0; writeIndex < 64; writeIndex++) |
| { |
| if (writeIndex % 4 == 0) |
| { |
| wData[writeIndex] = 0x55; |
| } else if (writeIndex % 4 == 1) |
| { |
| wData[writeIndex] = 0xaa; |
| } else if (writeIndex % 4 == 2) |
| { |
| wData[writeIndex] = 0xa5; |
| } else if (writeIndex % 4 == 3) |
| { |
| wData[writeIndex] = 0x5a; |
| } |
| } |
| |
| RETRY_I2C: |
| while (i16_time_out > 0 && u8_is_pass != 1) |
| { |
| i2cWriteLen = 64; |
| writeIndex = 0; |
| printk(KERN_INFO "[touch]I2C Test Write!!!\r\n"); |
| |
| while (writeIndex < u32_test_length) |
| { |
| if (i2c_burst_write(client, addr + writeIndex, i2cWriteLen, wData) == 0) |
| { |
| printk(KERN_ERR "[touch]i2c_test Write NG(ADDR=0x%x)!!\r\n", addr + writeIndex); |
| i16_time_out--; |
| if (raydium_hw_reset_fun(client) == ERROR) |
| { |
| goto NG_CASE; |
| } |
| if (raydium_selftest_stop_mcu(client) < 0) |
| { |
| goto NG_CASE; |
| } |
| goto RETRY_I2C; |
| } |
| |
| writeIndex += i2cWriteLen; |
| |
| if ((u32_test_length - writeIndex) < i2cWriteLen) |
| { |
| i2cWriteLen = (u32_test_length - writeIndex); |
| } |
| } |
| |
| printk(KERN_INFO "[touch]I2C Test Read!!!\r\n"); |
| i2cReadLength = 64; |
| |
| while (readLength < u32_test_length) |
| { |
| if (i2c_burst_read(client, addr + readLength, i2cReadLength, readData) == 0) |
| { |
| i16_time_out--; |
| printk(KERN_ERR "[touch]i2c_test Read NG(ADDR=0x%x)!!\r\n", addr + writeIndex); |
| if (raydium_hw_reset_fun(client) == ERROR) |
| { |
| goto NG_CASE; |
| } |
| if (raydium_selftest_stop_mcu(client) < 0) |
| { |
| goto NG_CASE; |
| } |
| goto RETRY_I2C; |
| } |
| |
| for (writeIndex = 0; writeIndex < i2cReadLength; writeIndex++) |
| { |
| if (wData[writeIndex] != readData[writeIndex]) |
| { |
| printk(KERN_ERR "[touch]i2c_test Read NG [%d], W=0x%x,R=0x%x\r\n", writeIndex, wData[writeIndex], readData[writeIndex]); |
| i16_time_out--; |
| if (raydium_hw_reset_fun(client) == ERROR) |
| { |
| goto NG_CASE; |
| } |
| if (raydium_selftest_stop_mcu(client) < 0) |
| { |
| goto NG_CASE; |
| } |
| goto RETRY_I2C; |
| } |
| } |
| |
| readLength += i2cReadLength; |
| |
| if (u32_test_length - readLength < i2cReadLength) |
| { |
| i2cReadLength = u32_test_length - readLength; |
| } |
| } |
| |
| u8_is_pass = 1; |
| } |
| |
| if (!u8_is_pass) |
| { |
| goto NG_CASE; |
| } |
| ret = u8_is_pass; |
| printk(KERN_INFO "[touch]I2C Test Pass!!!\r\n"); |
| sprintf(buf, "Raydium I2C Test : %d\n", ret); |
| printk("%s\n", buf); |
| return strlen(buf) + 1; |
| |
| NG_CASE: |
| ret = 0; |
| sprintf(buf, "Raydium I2C Test : %d\n", ret); |
| printk("%s\n", buf); |
| return strlen(buf) + 1; |
| } |
| |
| /* panel calibration cmd (R) |
| * example:cat raydium_ic_verion |
| */ |
| static DEVICE_ATTR(raydium_touch_calibration, S_IRUGO|S_IWUSR, |
| raydium_touch_calibration_show, |
| NULL); |
| |
| /* check the i2c (R) |
| * example:cat raydium_check_i2c |
| */ |
| static DEVICE_ATTR(raydium_check_i2c, S_IRUGO|S_IWUSR, |
| 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, S_IRUGO|S_IWUSR, |
| raydium_fw_upgrade_show, |
| raydium_fw_upgrade_store); |
| |
| /* 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_upgrade_firmware, S_IRUGO|S_IWUSR, |
| NULL, |
| raydium_upgrade_firmware_store); |
| |
| /* change I2C comunication 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, S_IRUGO|S_IWUSR, |
| 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, S_IRUGO|S_IWUSR, |
| 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, S_IRUGO|S_IWUSR, |
| 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, S_IRUGO|S_IWUSR, |
| 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, S_IRUGO|S_IWUSR, |
| raydium_i2c_raw_data_show, |
| raydium_i2c_raw_data_store); |
| |
| /* Read interrupt flag cmd (R) |
| * example:cat raydium_flag |
| */ |
| static DEVICE_ATTR(raydium_flag, S_IRUGO|S_IWUSR, |
| raydium_flag_show, |
| raydium_flag_store); |
| |
| /* Read interrupt flag cmd (R) |
| * example:cat raydium_int_flag |
| */ |
| static DEVICE_ATTR(raydium_int_flag, S_IRUGO|S_IWUSR, |
| raydium_int_flag_show, |
| raydium_int_flag_store); |
| |
| /* Read selftest flag cmd (R) |
| * example:cat raydium_int_flag |
| */ |
| static DEVICE_ATTR(raydium_selftest_flag, S_IRUGO|S_IWUSR, |
| raydium_selftest_flag_show, |
| raydium_selftest_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, S_IRUGO|S_IWUSR, |
| NULL, |
| raydium_touch_lock_store); |
| |
| /* show the fw version (R) |
| * example:cat raydium_fw_version |
| */ |
| static DEVICE_ATTR(raydium_check_fw_version, S_IRUGO|S_IWUSR, |
| raydium_check_fw_version_show, |
| NULL); |
| |
| static DEVICE_ATTR(fw_check, S_IRUGO, fw_check_show, NULL); |
| /* show the panel version (R) |
| * example:cat raydium_panel_version |
| */ |
| static DEVICE_ATTR(raydium_check_panel_version, S_IRUGO | S_IWUSR, |
| raydium_check_panel_version_show, |
| NULL); |
| |
| static DEVICE_ATTR(raydium_hw_reset, S_IRUGO|S_IWUSR, |
| raydium_hw_reset_show, |
| NULL); |
| static DEVICE_ATTR(raydium_wait_ft_int, S_IRUGO|S_IWUSR, |
| raydium_wait_ft_int_show, |
| raydium_wait_ft_int_store); |
| static DEVICE_ATTR(raydium_palm_status, S_IRUGO|S_IWUSR, |
| raydium_palm_status_show, |
| raydium_palm_status_store); |
| |
| static DEVICE_ATTR(raydium_palm_area, S_IRUGO|S_IWUSR, |
| NULL, |
| raydium_palm_area_store); |
| static DEVICE_ATTR(raydium_i2c_test, S_IRUGO | S_IWUSR, |
| raydium_i2c_test_show, |
| NULL); |
| |
| /*add your attr in here*/ |
| static struct attribute *raydium_attributes[] = { |
| &dev_attr_raydium_touch_calibration.attr, |
| &dev_attr_raydium_check_i2c.attr, |
| &dev_attr_raydium_upgrade_firmware.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_palm_status.attr, |
| &dev_attr_raydium_int_flag.attr, |
| &dev_attr_raydium_selftest_flag.attr, |
| &dev_attr_raydium_wait_ft_int.attr, |
| &dev_attr_raydium_palm_area.attr, |
| &dev_attr_fw_check.attr, |
| &dev_attr_raydium_i2c_test.attr, |
| NULL |
| }; |
| |
| static 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) |
| { |
| dev_err(&client->dev, "[touch]failed to register sysfs\n"); |
| sysfs_remove_group(&client->dev.kobj, &raydium_attr_group); |
| return -EIO; |
| } else |
| { |
| printk(KERN_INFO "[touch]create raydium sysfs attr_group succesful\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 |
| |
| static int raydium_read_touchdata(struct raydium_ts_data *data) |
| { |
| unsigned char buf[MAX_REPORT_PAKAGE_SIZE]; |
| unsigned char tp_status[MAX_TCH_STATUS_PAKAGE_SIZE]; |
| int ret = 0; |
| unsigned char i, j, offset; |
| unsigned char u8_seq_no = 0, u8_points_amount, u8_point_id; |
| signed short s16_x, s16_y, s16_pressure, s16_wx, s16_wy; |
| |
| #ifdef GESTURE_EN |
| //display idle mode, touch idle mode |
| |
| if (data->blank == FB_BLANK_VSYNC_SUSPEND || data->blank == FB_BLANK_POWERDOWN) |
| { |
| //need check small area |
| input_mt_slot(data->input_dev, 0); |
| input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 1); |
| input_report_abs(data->input_dev, ABS_MT_POSITION_X, 100); |
| input_report_abs(data->input_dev, ABS_MT_POSITION_Y, 100); |
| input_sync(data->input_dev); |
| mdelay(10); |
| input_mt_slot(data->input_dev, 0); |
| input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, 0); |
| input_mt_report_pointer_emulation(data->input_dev, false); |
| input_sync(data->input_dev); |
| g_uc_gesture_status = RAYDIUM_GESTURE_DISABLE; |
| printk(KERN_INFO "[touch]display wake up\n"); |
| return 0; |
| } |
| else |
| { |
| #endif |
| mutex_lock(&data->lock); |
| |
| memset(buf, 0, MAX_REPORT_PAKAGE_SIZE); |
| memset(tp_status, 0, MAX_TCH_STATUS_PAKAGE_SIZE); |
| //read touch point information |
| ret = raydium_i2c_pda2_read(data->client, RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR, tp_status, MAX_TCH_STATUS_PAKAGE_SIZE); |
| if (ret < 0) |
| { |
| dev_err(&data->client->dev, "[touch]%s: failed to read data: %d\n",__func__, ret); |
| mutex_unlock(&data->lock); |
| return ret; |
| } |
| |
| // inform IC to prepare next report |
| if (u8_seq_no == tp_status[POS_SEQ]) |
| { //report not updated |
| mutex_unlock(&data->lock); |
| //printk("%s -> report not updated.\n", __func__); |
| return 0; |
| } |
| u8_points_amount = tp_status[POS_PT_AMOUNT]; |
| if (u8_points_amount > MAX_TOUCH_NUM) |
| { |
| return 0; |
| } |
| |
| //read touch point report |
| //PDA2 only support word mode |
| if (u8_points_amount != 0) |
| { |
| ret = raydium_i2c_pda2_read(data->client, RAYDIUM_PDA2_TCH_RPT_ADDR, buf, u8_points_amount * LENGTH_PT); |
| } |
| |
| if (ret < 0) |
| { |
| dev_err(&data->client->dev, "[touch]%s: failed to read data: %d\n", __func__, ret); |
| mutex_unlock(&data->lock); |
| return ret; |
| } |
| u8_seq_no = tp_status[POS_SEQ]; |
| tp_status[POS_SEQ] = 0; |
| ret = raydium_i2c_pda2_write(data->client, RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR, tp_status, 1); |
| if (ret < 0) |
| { |
| dev_err(&data->client->dev, "[touch]%s: failed to write data: %d\n",__func__, ret); |
| mutex_unlock(&data->lock); |
| return ret; |
| } |
| mutex_unlock(&data->lock); |
| //Report |
| // TODO: Using struct+memcpy instead of array+offset |
| //initialize slot update info |
| for (i = 0; i < (MAX_TOUCH_NUM * 2); i++) |
| { |
| gst_slot_status[i].need_update = 0; |
| gst_slot_status[i].pt_report_offset = 0; |
| } |
| |
| //Check incoming point info |
| for (i = 0; i < u8_points_amount; i++) |
| { |
| u8_point_id = buf[POS_PT_ID + i * LENGTH_PT]; |
| // Current |
| for (j = 0; j < MAX_TOUCH_NUM; j++) |
| { |
| if (u8_point_id == gst_slot_status[j].occupied_pt_id) |
| { |
| gst_slot_status[j].need_update = 1; |
| gst_slot_status[j].pt_report_offset = i; |
| break; |
| } |
| } |
| // New coming |
| if (j == MAX_TOUCH_NUM) |
| { |
| for (j = MAX_TOUCH_NUM; j < (MAX_TOUCH_NUM * 2); j++) |
| { |
| if (!gst_slot_status[j].need_update) |
| { |
| gst_slot_status[j].occupied_pt_id = u8_point_id; |
| gst_slot_status[j].need_update = 1; |
| gst_slot_status[j].pt_report_offset = i; |
| printk(KERN_INFO "[touch]x:%d,y:%d\n", |
| buf[POS_X_L + offset] | buf[POS_X_H + offset] << SHORT_HIGH_BYTE_SHIFT, |
| buf[POS_Y_L + offset] | buf[POS_Y_H + offset] << SHORT_HIGH_BYTE_SHIFT); |
| break; |
| } |
| } |
| } |
| } |
| |
| //Release slot with non-occupied point |
| for (i = 0; i < MAX_TOUCH_NUM; i++) |
| { |
| if (!gst_slot_status[i].need_update) |
| { |
| input_mt_slot(data->input_dev, i); |
| input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false); |
| gst_slot_status[i].occupied_pt_id = 0xFF; |
| gst_slot_status[i].pt_report_offset = 0; |
| gst_slot_status[i].need_update = 0; |
| } |
| } |
| //Assign new one to non-occupied slot |
| for (i = MAX_TOUCH_NUM; i < (MAX_TOUCH_NUM * 2); i++) |
| { |
| if (gst_slot_status[i].need_update) |
| { |
| for (j = 0; j < MAX_TOUCH_NUM; j++) |
| { |
| if (!gst_slot_status[j].need_update) |
| { |
| gst_slot_status[j] = gst_slot_status[i]; |
| gst_slot_status[i] = gst_slot_init_status; |
| break; |
| } |
| } |
| } |
| else |
| { |
| break; |
| } |
| } |
| |
| for (i = 0; i < MAX_TOUCH_NUM; i++) |
| { |
| if (gst_slot_status[i].need_update) |
| { |
| offset = gst_slot_status[i].pt_report_offset * LENGTH_PT; |
| s16_x = buf[POS_X_L + offset] | buf[POS_X_H + offset] << SHORT_HIGH_BYTE_SHIFT; |
| s16_y = buf[POS_Y_L + offset] | buf[POS_Y_H + offset] << SHORT_HIGH_BYTE_SHIFT; |
| s16_pressure = buf[POS_PRESSURE_L + offset] | buf[POS_PRESSURE_H + offset] << SHORT_HIGH_BYTE_SHIFT; |
| s16_wx = buf[POS_WX_L + offset] | buf[POS_WX_H + offset] << SHORT_HIGH_BYTE_SHIFT; |
| s16_wy = buf[POS_WY_L + offset] | buf[POS_WY_H + offset] << SHORT_HIGH_BYTE_SHIFT; |
| |
| input_mt_slot(data->input_dev, i); |
| input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, true); |
| |
| input_report_abs(data->input_dev, ABS_MT_POSITION_X, s16_x); |
| input_report_abs(data->input_dev, ABS_MT_POSITION_Y, s16_y); |
| input_report_abs(data->input_dev, ABS_MT_PRESSURE, s16_pressure); |
| input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, max(s16_wx, s16_wy)); |
| input_report_abs(data->input_dev, ABS_MT_TOUCH_MINOR, min(s16_wx, s16_wy)); |
| //printk(KERN_INFO "[touch]x:%d, y:%d\n", s16_x,s16_y); |
| } |
| } |
| |
| input_mt_sync_frame(data->input_dev); |
| input_sync(data->input_dev); |
| |
| /* |
| printk("Raydium Slot status #: %d %d ; %d %d ; %d %d ; %d %d\n", |
| gst_slot_status[0].need_update, gst_slot_status[0].occupied_pt_id, |
| gst_slot_status[1].need_update, gst_slot_status[1].occupied_pt_id, |
| gst_slot_status[2].need_update, gst_slot_status[2].occupied_pt_id, |
| gst_slot_status[3].need_update, gst_slot_status[3].occupied_pt_id); |
| */ |
| #ifdef GESTURE_EN |
| } |
| #endif |
| |
| return 0; |
| } |
| |
| static void raydium_work_handler(struct work_struct *work) |
| { |
| struct raydium_ts_data *raydium_ts = \ |
| container_of(work, struct raydium_ts_data, work); |
| int ret = 0; |
| |
| #ifdef GESTURE_EN |
| unsigned int palm_status = 0; |
| int i = 0; |
| |
| if (raydium_ts->blank == FB_BLANK_UNBLANK) //when display on can use palm to suspend |
| { |
| if (u8_i2c_mode == PDA2_MODE) |
| { |
| palm_status = raydium_get_palm_state(raydium_ts, g_uc_pre_palm_status); |
| } |
| if (palm_status == RAYDIUM_PALM_MODE_ENABLE) |
| { |
| if (raydium_ts->is_palm == 0) |
| { |
| // release all touches |
| for (i = 0; i < raydium_ts->pdata->num_max_touches; i++) |
| { |
| input_mt_slot(raydium_ts->input_dev, i); |
| input_mt_report_slot_state(raydium_ts->input_dev, MT_TOOL_FINGER, false); |
| } |
| |
| input_mt_report_pointer_emulation(raydium_ts->input_dev, false); |
| input_report_key(raydium_ts->input_dev, KEY_SLEEP, true); //press sleep key |
| input_sync(raydium_ts->input_dev); |
| |
| printk(KERN_INFO "[touch]palm_status = %d.\n", palm_status); |
| g_uc_pre_palm_status = RAYDIUM_PALM_MODE_ENABLE; |
| raydium_ts->is_palm = 1; |
| goto exit; |
| } |
| } else if ((palm_status == RAYDIUM_PALM_MODE_DISABLE) && (g_uc_pre_palm_status == RAYDIUM_PALM_MODE_ENABLE)) |
| { |
| printk(KERN_INFO "[touch]leave palm mode.\n"); |
| input_report_key(raydium_ts->input_dev, KEY_SLEEP, false); //release sleep key |
| input_sync(raydium_ts->input_dev); |
| g_uc_pre_palm_status = RAYDIUM_PALM_MODE_DISABLE; |
| raydium_ts->is_palm = 0; |
| goto exit; |
| } |
| } |
| #endif |
| |
| if (u8_i2c_mode == PDA2_MODE) |
| { |
| ret = raydium_read_touchdata(raydium_ts); |
| if (ret < 0) |
| { |
| printk(KERN_ERR "[touch]raydium_read_touchdata error, ret:%d\n", ret); |
| } |
| } |
| |
| #ifdef GESTURE_EN |
| exit: |
| #endif |
| return; |
| } |
| |
| /*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) |
| { |
| struct raydium_ts_data *raydium_ts = dev_id; |
| bool result = false; |
| |
| if (g_uc_raydium_selftest_flag == 1) |
| { |
| disable_irq_nosync(raydium_ts->irq); |
| raydium_ts->irq_enabled = false; |
| printk(KERN_INFO "[touch]g_uc_raydium_selftest_flag = 1\n"); |
| g_uc_raydium_int_flag = 1; |
| } |
| //For bootloader wrt/erase flash and software reset interrupt |
| else if ((g_uc_raydium_flag & RAYDIUM_BOOTLOADER_FLAG) != 0) |
| { |
| disable_irq_nosync(raydium_ts->irq); |
| raydium_ts->irq_enabled = false; |
| printk(KERN_INFO "[touch]g_uc_raydium_flag = %d\n", g_uc_raydium_flag); |
| g_uc_raydium_flag = RAYDIUM_INTERRUPT_FLAG; |
| } else |
| { |
| if (!work_pending(&raydium_ts->work)) |
| { |
| result = queue_work(raydium_ts->workqueue, &raydium_ts->work); |
| if (result == false) //queue_work fail |
| { |
| printk(KERN_ERR "[touch]queue_work fail.\n"); |
| } else |
| { |
| if (raydium_ts->blank == FB_BLANK_POWERDOWN) |
| { |
| disable_irq_nosync(raydium_ts->irq); |
| raydium_ts->irq_enabled = false; |
| } else |
| { |
| /* Clear interrupts*/ |
| mutex_lock(&raydium_ts->lock); |
| if (raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_PAGE_0) < 0) |
| { |
| dev_err(&raydium_ts->client->dev, "[touch]%s: failed to set page for reading gesture report\n",__func__); |
| } |
| mutex_unlock(&raydium_ts->lock); |
| } |
| } |
| } else //work pending |
| { |
| printk(KERN_INFO "[touch]work_pending\n"); |
| } |
| } |
| |
| return IRQ_HANDLED; |
| } |
| |
| static int raydium_check_i2c_ready(struct raydium_ts_data *raydium_ts) |
| { |
| unsigned char temp_buf[4]; |
| int ret = -1; |
| |
| mutex_lock(&raydium_ts->lock); |
| |
| if (u8_i2c_mode == PDA2_MODE) |
| { |
| ret = raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| |
| *(unsigned long *)temp_buf = (RAYDIUM_I2C_PDA_MODE_ENABLE << 24) | ((RAYDIUM_CHECK_I2C_CMD & (~MASK_8BIT)) >> 8); //using byte mode to read 4 bytes |
| ret = raydium_i2c_pda2_write(raydium_ts->client, RAYDIUM_PDA2_PDA_CFG_ADDR, temp_buf, 4); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| |
| ret = raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_ENABLE_PDA); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| |
| ret = raydium_i2c_pda2_read(raydium_ts->client, (unsigned char)(RAYDIUM_CHECK_I2C_CMD& MASK_8BIT), temp_buf, 4); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| } else |
| { |
| ret = raydium_i2c_pda_read(raydium_ts->client, RAYDIUM_CHECK_I2C_CMD, temp_buf, 4); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| } |
| |
| printk(KERN_ERR "[touch]Raydium Touch check I2C:0x%02X%02X\n", temp_buf[3], temp_buf[2]); |
| |
| exit_error: |
| mutex_unlock(&raydium_ts->lock); |
| return ret; |
| } |
| |
| static int raydium_fw_update_check(struct raydium_ts_data *raydium_ts) |
| { |
| |
| unsigned char rbuffer[4]; |
| unsigned int fw_version, image_version; |
| int ret = -1; |
| |
| mutex_lock(&raydium_ts->lock); |
| ret = raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| ret = raydium_i2c_pda2_read(raydium_ts->client, RAYDIUM_PDA2_FW_VERSION_ADDR, rbuffer, 4); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| mutex_unlock(&raydium_ts->lock); |
| |
| fw_version = (rbuffer[0] << 24) | (rbuffer[1] << 16) | (rbuffer[2] << 8) | rbuffer[3]; |
| printk(KERN_ERR "[touch]Raydium IC FW version is 0x%x\n", fw_version); |
| |
| raydium_ts->fw_version = fw_version; |
| |
| image_version = (RadFWImage[0xF21] << 24) | (RadFWImage[0xF22] << 16) | (RadFWImage[0xF23] << 8) | RadFWImage[0xF24]; |
| printk(KERN_ERR "[touch]Raydium Image FW version is 0x%x\n", image_version); |
| |
| if (fw_version != image_version) |
| { |
| printk(KERN_ERR "[touch]FW need update.\n"); |
| raydium_irq_control(raydium_ts, DISABLE); |
| ret = raydium_burn_fw(raydium_ts->client); |
| if (ret < 0) |
| { |
| printk(KERN_ERR "[touch]FW update fail:%d\n", ret); |
| } |
| raydium_irq_control(raydium_ts, ENABLE); |
| mutex_lock(&raydium_ts->lock); |
| ret = raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| ret = raydium_i2c_pda2_read(raydium_ts->client, RAYDIUM_PDA2_FW_VERSION_ADDR, rbuffer, 4); |
| if (ret < 0) |
| { |
| goto exit_error; |
| } |
| mutex_unlock(&raydium_ts->lock); |
| fw_version = (rbuffer[0] << 24) | (rbuffer[1] << 16) | (rbuffer[2] << 8) | rbuffer[3]; |
| printk(KERN_ERR "[touch]Raydium IC FW version is 0x%x\n", fw_version); |
| raydium_ts->fw_version = fw_version; |
| } else |
| { |
| printk(KERN_ERR "[touch]FW is the latest version.\n"); |
| } |
| |
| return ret; |
| |
| exit_error: |
| mutex_unlock(&raydium_ts->lock); |
| return ret; |
| } |
| |
| #if defined(CONFIG_PM) |
| static void raydium_ts_do_suspend(struct raydium_ts_data *ts) |
| { |
| int i = 0; |
| printk(KERN_INFO "[touch]%s, %d.\n", __func__, ts->is_suspend); |
| if (ts->is_suspend == 1) |
| { |
| printk(KERN_INFO "[touch]Already in suspend state\n"); |
| return; |
| } |
| |
| #ifndef GESTURE_EN |
| raydium_irq_control(ts, DISABLE); |
| #endif |
| /* release all touches */ |
| for (i = 0; i < ts->pdata->num_max_touches; i++) |
| { |
| input_mt_slot(ts->input_dev, i); |
| input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); |
| } |
| input_mt_report_pointer_emulation(ts->input_dev, false); |
| input_sync(ts->input_dev); |
| |
| #ifdef GESTURE_EN |
| if (device_may_wakeup(&ts->client->dev)) |
| { |
| printk(KERN_INFO "[touch]Device may wakeup\n"); |
| if (!enable_irq_wake(ts->irq)) |
| { |
| ts->irq_wake = 1; |
| } |
| } else |
| { |
| printk(KERN_INFO "[touch]Device not wakeup\n"); |
| } |
| raydium_irq_control(ts, ENABLE); |
| #endif |
| |
| ts->is_suspend = 1; |
| } |
| static void raydium_ts_do_resume(struct raydium_ts_data *ts) |
| { |
| printk(KERN_INFO "[touch]%s, %d.\n", __func__, ts->is_suspend); |
| if (ts->is_suspend == 0) |
| { |
| printk(KERN_INFO "[touch]Already in resume state\n"); |
| return; |
| } |
| |
| raydium_irq_control(ts, ENABLE); |
| |
| #ifdef GESTURE_EN |
| if (device_may_wakeup(&ts->client->dev)) |
| { |
| printk(KERN_INFO "[touch]Device may wakeup\n"); |
| if (ts->irq_wake) |
| { |
| disable_irq_wake(ts->irq); |
| ts->irq_wake = 0; |
| } |
| } else |
| { |
| printk(KERN_INFO "[touch]Device not wakeup\n"); |
| } |
| #endif |
| |
| ts->is_suspend = 0; |
| } |
| |
| static int raydium_ts_suspend(struct device *dev) |
| { |
| struct raydium_ts_data *ts = dev_get_drvdata(dev); |
| raydium_ts_do_suspend(ts); |
| return 0; |
| } |
| |
| static int raydium_ts_resume(struct device *dev) |
| { |
| struct raydium_ts_data *ts = dev_get_drvdata(dev); |
| raydium_ts_do_resume(ts); |
| 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) |
| { |
| struct raydium_ts_data *ts; |
| int ret = 0; |
| |
| printk(KERN_INFO"[touch]%s()+\n", __func__); |
| ts = input_get_drvdata(input_dev); |
| |
| printk(KERN_INFO "[touch]ts->blank:%x\n",ts->blank); |
| if (ts->is_sleep == 1) |
| { |
| //turn on i2c pull-up power |
| ret = raydium_power_on(ts, true); |
| if (ret) |
| { |
| dev_err(&ts->client->dev, "[touch]%s:power on failed",__func__); |
| } |
| |
| mutex_lock(&ts->lock); |
| if (gpio_is_valid(ts->rst)) |
| { |
| udelay(RAYDIUM_POWERON_DELAY_USEC);//500us |
| |
| ret = gpio_request(ts->rst, "raydium_reset_gpio"); |
| if (ret < 0) |
| { |
| dev_err(&ts->client->dev, "[touch]reset gpio request failed"); |
| } |
| gpio_direction_output(ts->rst, 1); |
| gpio_direction_output(ts->rst, 0); |
| msleep(RAYDIUM_RESET_INTERVAL_MSEC);//5ms |
| gpio_direction_output(ts->rst, 1); |
| msleep(RAYDIUM_RESET_DELAY_MSEC);//100ms |
| u8_i2c_mode = PDA2_MODE; |
| gpio_free(ts->rst); |
| } |
| mutex_unlock(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| ts->is_sleep = 0; |
| printk(KERN_INFO "[touch]disable touch lock.\n"); |
| } |
| |
| return ret; |
| } |
| |
| static void raydium_ts_close(struct input_dev *input_dev) |
| { |
| struct raydium_ts_data *ts; |
| int ret = 0; |
| int i = 0; |
| unsigned char wbuffer[1]; |
| |
| printk(KERN_INFO "[touch]%s()+\n", __func__); |
| ts = input_get_drvdata(input_dev); |
| |
| if (ts->is_sleep == 1) |
| { |
| printk(KERN_INFO "[touch]touch lock already enabled.\n"); |
| return; |
| } |
| |
| raydium_irq_control(ts, DISABLE); |
| |
| /* release all touches */ |
| for (i = 0; i < ts->pdata->num_max_touches; i++) |
| { |
| input_mt_slot(ts->input_dev, i); |
| input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); |
| } |
| input_mt_report_pointer_emulation(ts->input_dev, false); |
| input_sync(ts->input_dev); |
| |
| mutex_lock(&ts->lock); |
| ret = raydium_i2c_pda2_set_page(ts->client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| printk(KERN_ERR "[touch]ret:%d\n",ret); |
| goto exit_i2c_error; |
| } |
| |
| wbuffer[0] = RAYDIUM_HOST_CMD_PWR_SLEEP;//fw enter sleep mode |
| ret = raydium_i2c_pda2_write(ts->client, RAYDIUM_PDA2_HOST_CMD_ADDR, wbuffer, 1); |
| if (ret < 0) |
| { |
| printk(KERN_ERR "[touch]ret:%d\n",ret); |
| goto exit_i2c_error; |
| } |
| |
| //turn off i2c pull-up power |
| ret = raydium_power_on(ts, false); |
| if (ret) |
| { |
| dev_err(&ts->client->dev, "[touch]%s:power off failed",__func__); |
| } |
| mutex_unlock(&ts->lock); |
| |
| ts->is_sleep = 1; |
| printk(KERN_INFO "[touch]enable touch lock.\n"); |
| return; |
| |
| exit_i2c_error: |
| mutex_unlock(&ts->lock); |
| raydium_irq_control(ts, ENABLE); |
| return; |
| } |
| |
| #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; |
| #ifdef GESTURE_EN |
| int ret = 0; |
| unsigned char wbuffer[1]; |
| #endif |
| struct raydium_ts_data *raydium_ts = |
| container_of(self, struct raydium_ts_data, fb_notif); |
| |
| if (evdata && evdata->data && event == FB_EVENT_BLANK && |
| raydium_ts && raydium_ts->client) |
| { |
| blank = evdata->data; |
| raydium_ts->blank = (*blank); |
| |
| switch (*blank) |
| { |
| case FB_BLANK_UNBLANK: //screen on |
| printk(KERN_INFO "[touch]FB_BLANK_UNBLANK\n"); |
| #ifdef GESTURE_EN |
| /* clear palm status */ |
| g_uc_pre_palm_status = 0; |
| raydium_ts->is_palm = 0; |
| /* notify fw enter active mode */ |
| mutex_lock(&raydium_ts->lock); |
| ret = raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| mutex_unlock(&raydium_ts->lock); |
| goto exit_error; |
| } |
| wbuffer[0] = ACTIVE_MODE; |
| ret = raydium_i2c_pda2_write(raydium_ts->client, RAYDIUM_PDA2_DISPLAY_MODE_ADDR, wbuffer, 1); |
| if (ret < 0) |
| { |
| mutex_unlock(&raydium_ts->lock); |
| goto exit_error; |
| } |
| mutex_unlock(&raydium_ts->lock); |
| #endif |
| raydium_ts_resume(&raydium_ts->client->dev); |
| break; |
| |
| case FB_BLANK_POWERDOWN://screen off |
| printk(KERN_INFO "[touch]FB_BLANK_POWERDOWN\n"); |
| #ifdef GESTURE_EN |
| /* clear palm status */ |
| g_uc_pre_palm_status = 0; |
| raydium_ts->is_palm = 0; |
| /* notify fw enter sleep mode */ |
| mutex_lock(&raydium_ts->lock); |
| ret = raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| mutex_unlock(&raydium_ts->lock); |
| goto exit_error; |
| } |
| wbuffer[0] = SLEEP_MODE; |
| ret = raydium_i2c_pda2_write(raydium_ts->client, RAYDIUM_PDA2_DISPLAY_MODE_ADDR, wbuffer, 1); |
| if (ret < 0) |
| { |
| mutex_unlock(&raydium_ts->lock); |
| goto exit_error; |
| } |
| mutex_unlock(&raydium_ts->lock); |
| #endif |
| raydium_ts_suspend(&raydium_ts->client->dev); |
| break; |
| case FB_BLANK_VSYNC_SUSPEND://ambient mode |
| printk(KERN_INFO "[touch]FB_BLANK_VSYNC_SUSPEND\n"); |
| #ifdef GESTURE_EN |
| /* clear palm status */ |
| g_uc_pre_palm_status = 0; |
| raydium_ts->is_palm = 0; |
| /* notify fw enter ambient mode */ |
| mutex_lock(&raydium_ts->lock); |
| ret = raydium_i2c_pda2_set_page(raydium_ts->client, RAYDIUM_PDA2_PAGE_0); |
| if (ret < 0) |
| { |
| mutex_unlock(&raydium_ts->lock); |
| goto exit_error; |
| } |
| wbuffer[0] = AMBIENT_MODE; |
| ret = raydium_i2c_pda2_write(raydium_ts->client, RAYDIUM_PDA2_DISPLAY_MODE_ADDR, wbuffer, 1); |
| if (ret < 0) |
| { |
| mutex_unlock(&raydium_ts->lock); |
| goto exit_error; |
| } |
| mutex_unlock(&raydium_ts->lock); |
| #endif |
| raydium_ts_suspend(&raydium_ts->client->dev); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| #ifdef GESTURE_EN |
| exit_error: |
| #endif |
| return 0; |
| } |
| |
| static void raydium_register_notifier(struct raydium_ts_data *raydium_ts) |
| { |
| memset(&raydium_ts->fb_notif,0,sizeof(raydium_ts->fb_notif)); |
| raydium_ts->fb_notif.notifier_call = fb_notifier_callback; |
| |
| /* register on the fb notifier and work with fb*/ |
| fb_register_client(&raydium_ts->fb_notif); |
| } |
| |
| static void raydium_unregister_notifier(struct raydium_ts_data *raydium_ts) |
| { |
| fb_unregister_client(&raydium_ts->fb_notif); |
| } |
| #elif defined(CONFIG_HAS_EARLYSUSPEND) |
| static void raydium_ts_early_suspend(struct early_suspend *handler) |
| { |
| struct raydium_ts_data *raydium_ts = container_of(handler, |
| struct raydium_ts_data, |
| early_suspend); |
| |
| raydium_ts_do_suspend(raydium_ts); |
| } |
| |
| static void raydium_ts_late_resume(struct early_suspend *handler) |
| { |
| struct raydium_ts_data *raydium_ts = container_of(handler, |
| struct raydium_ts_data, |
| early_suspend); |
| |
| raydium_ts_do_resume(raydium_ts); |
| } |
| #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) |
| { |
| dev_err(dev, "[touch]invalid %s\n", name); |
| return -EINVAL; |
| } |
| |
| rc = of_property_read_u32_array(np, name, coords, coords_size); |
| if (rc && (rc != -EINVAL)) |
| { |
| dev_err(dev, "[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 { |
| dev_err(dev, "[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; |
| } |
| |
| 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, struct raydium_ts_data *ts) |
| { |
| 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 = &ts->client->dev; |
| input_dev->open = raydium_ts_open;//touch lock |
| input_dev->close = raydium_ts_close; |
| input_set_drvdata(input_dev, 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); |
| |
| /* Multitouch input params setup */ |
| input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); |
| input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 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) |
| { |
| dev_err(&ts->client->dev, "[touch]failed to initialize MT slots: %d\n", ret); |
| } |
| |
| for (i = 0; i < (MAX_TOUCH_NUM * 2); i++) |
| { |
| gst_slot_status[i]=gst_slot_init_status; |
| } |
| |
| } |
| |
| static int raydium_ts_probe(struct i2c_client *client, |
| const struct i2c_device_id *id) |
| { |
| struct raydium_ts_platform_data *pdata; |
| struct raydium_ts_data *raydium_ts; |
| struct input_dev *input_dev; |
| int ret = 0; |
| |
| 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; |
| } |
| |
| raydium_ts = devm_kzalloc(&client->dev, sizeof(struct raydium_ts_data), GFP_KERNEL); |
| if (!raydium_ts) |
| { |
| dev_err(&client->dev, "[touch]failed to allocate input driver data\n"); |
| return -ENOMEM; |
| } |
| |
| mutex_init(&raydium_ts->lock); |
| |
| i2c_set_clientdata(client, raydium_ts); |
| raydium_ts->irq = client->irq; |
| raydium_ts->irq_enabled = true; |
| raydium_ts->irq_wake = false; |
| |
| //raydium_ts->irq = pdata->irq_gpio; |
| raydium_ts->rst = pdata->reset_gpio; |
| raydium_ts->client = client; |
| raydium_ts->pdata = pdata; |
| raydium_ts->x_max = pdata->x_max - 1; |
| raydium_ts->y_max = pdata->y_max - 1; |
| raydium_ts->is_suspend = 0; |
| raydium_ts->is_sleep = 0; |
| #ifdef GESTURE_EN |
| raydium_ts->is_palm = 0; |
| #endif |
| raydium_ts->fw_version = 0; |
| |
| device_init_wakeup(&client->dev,1); |
| |
| ret = raydium_power_init(raydium_ts, true); |
| if (ret) |
| { |
| dev_err(&client->dev, "[touch]raydium_power_init failed\n"); |
| goto exit_regulator_failed; |
| } |
| |
| ret = raydium_power_on(raydium_ts, true); |
| if (ret) |
| { |
| dev_err(&client->dev, "[touch]raydium_power_on failed\n"); |
| goto pwr_deinit; |
| } |
| |
| #ifdef MSM_NEW_VER |
| ret = raydium_ts_pinctrl_init(raydium_ts); |
| if (!ret && 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(raydium_ts->ts_pinctrl, |
| raydium_ts->pinctrl_state_active); |
| if (ret < 0) |
| { |
| dev_err(&client->dev, "[touch]failed to select pin to active state\n"); |
| } |
| } |
| #endif //end of MSM_NEW_VER |
| |
| ret = raydium_gpio_configure(raydium_ts, true); |
| if (ret < 0) |
| { |
| dev_err(&client->dev,"[touch]failed to configure the gpios\n"); |
| goto err_gpio_req; |
| } |
| |
| msleep(raydium_ts->pdata->soft_rst_dly);//modify dtsi to 360 |
| |
| //print touch i2c ready |
| ret = raydium_check_i2c_ready(raydium_ts); |
| if (ret < 0) |
| { |
| dev_err(&client->dev, "[touch]Check I2C failed\n"); |
| ret = -ENODEV; |
| goto exit_check_i2c; |
| } |
| |
| //input device initialization |
| input_dev = input_allocate_device(); |
| if (!input_dev) |
| { |
| ret = -ENOMEM; |
| dev_err(&client->dev, "[touch]failed to allocate input device\n"); |
| goto exit_input_dev_alloc_failed; |
| } |
| |
| raydium_ts->input_dev = input_dev; |
| raydium_input_set(input_dev, raydium_ts); |
| |
| ret = input_register_device(input_dev); |
| if (ret) |
| { |
| dev_err(&client->dev, |
| "[touch]raydium_ts_probe: 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); |
| #endif |
| |
| //suspend/resume routine |
| #if defined(CONFIG_FB) |
| raydium_register_notifier(raydium_ts); |
| #elif defined(CONFIG_HAS_EARLYSUSPEND) |
| raydium_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; //1: Early-suspend level |
| raydium_ts->early_suspend.suspend = raydium_ts_early_suspend; |
| raydium_ts->early_suspend.resume = raydium_ts_late_resume; |
| register_early_suspend(&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(&raydium_ts->work, raydium_work_handler); |
| raydium_ts->workqueue = create_singlethread_workqueue("raydium_ts"); |
| |
| dev_err(&client->dev, "[touch]pdata irq : %d \n", raydium_ts->pdata->irq_gpio);//13 |
| dev_err(&client->dev, "[touch]client irq : %d, pdata flags : %d \n", client->irq, pdata->irqflags);//108 |
| |
| ret = request_threaded_irq(gpio_to_irq(raydium_ts->pdata->irq_gpio), NULL, raydium_ts_interrupt, |
| pdata->irqflags | IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_NO_SUSPEND, client->dev.driver->name, |
| raydium_ts); |
| if (ret < 0) |
| { |
| dev_err(&client->dev, "[touch]raydium_probe: request irq failed\n"); |
| goto exit_irq_request_failed; |
| } |
| |
| |
| raydium_ts->irq_desc = irq_to_desc(client->irq); |
| |
| //disable_irq then enable_irq for avoid Unbalanced enable for IRQ warning |
| raydium_irq_control(raydium_ts, DISABLE); |
| raydium_irq_control(raydium_ts, ENABLE); |
| |
| printk(KERN_ERR "[touch]Raydium Touch driver version :0x%04X\n", RAYDIUM_VER); |
| |
| //fw update check |
| ret = raydium_fw_update_check(raydium_ts); |
| if (ret < 0) |
| { |
| dev_err(&client->dev, "[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(raydium_ts); |
| #endif//end of CONFIG_FB |
| |
| cancel_work_sync(&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 (raydium_ts->ts_pinctrl) |
| { |
| if (IS_ERR_OR_NULL(raydium_ts->pinctrl_state_release)) |
| { |
| devm_pinctrl_put(raydium_ts->ts_pinctrl); |
| raydium_ts->ts_pinctrl = NULL; |
| } else |
| { |
| ret = pinctrl_select_state(raydium_ts->ts_pinctrl, |
| raydium_ts->pinctrl_state_release); |
| if (ret) |
| { |
| pr_err("[touch]failed to select relase pinctrl state\n"); |
| } |
| } |
| } |
| #endif//end of MSM_NEW_VER |
| raydium_power_on(raydium_ts, false); |
| |
| pwr_deinit: |
| raydium_power_init(raydium_ts, false); |
| |
| exit_regulator_failed: |
| i2c_set_clientdata(client, NULL); |
| |
| parse_dt_failed: |
| exit_check_functionality_failed: |
| return ret; |
| |
| } |
| |
| static int raydium_ts_remove(struct i2c_client *client) |
| { |
| struct raydium_ts_data *raydium_ts; |
| raydium_ts = i2c_get_clientdata(client); |
| |
| #if defined(CONFIG_FB) |
| raydium_unregister_notifier(raydium_ts); |
| #elif defined(CONFIG_HAS_EARLYSUSPEND) |
| unregister_early_suspend(&raydium_ts->early_suspend); |
| #endif//end of CONFIG_FB |
| input_unregister_device(raydium_ts->input_dev); |
| input_free_device(raydium_ts->input_dev); |
| gpio_free(raydium_ts->rst); |
| |
| #ifdef CONFIG_RM_SYSFS_DEBUG |
| raydium_release_sysfs(client); |
| #endif //end of CONFIG_RM_SYSFS_DEBUG |
| |
| free_irq(client->irq, raydium_ts); |
| |
| if (gpio_is_valid(raydium_ts->pdata->reset_gpio)) |
| { |
| gpio_free(raydium_ts->pdata->reset_gpio); |
| } |
| if (gpio_is_valid(raydium_ts->pdata->irq_gpio)) |
| { |
| gpio_free(raydium_ts->pdata->irq_gpio); |
| } |
| raydium_power_on(raydium_ts, false); |
| raydium_power_init(raydium_ts, false); |
| |
| kfree(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("<Rejion>"); |
| MODULE_DESCRIPTION("Raydium TouchScreen driver"); |
| MODULE_LICENSE("GPL"); |