Skip to content

Instantly share code, notes, and snippets.

@Nokius
Last active October 6, 2016 12:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nokius/ef22d779ca0ed146a483c2e9244c4874 to your computer and use it in GitHub Desktop.
Save Nokius/ef22d779ca0ed146a483c2e9244c4874 to your computer and use it in GitHub Desktop.
[SFOS] cancro diff touchscreen
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 1e93b43..f95ffd9 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -112,6 +112,17 @@ config TOUCHSCREEN_ATMEL_MXT
To compile this driver as a module, choose M here: the
module will be called atmel_mxt_ts.
+config TOUCHSCREEN_ATMEL_640T
+ tristate "Atmel 640T I2C Touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have Atmel T series I2C touchscreen,
+ such as 640T, connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atmel_mxt_ts.
config TOUCHSCREEN_ST_FTS
tristate "ST FTS I2C Touchscreen"
@@ -1013,23 +1024,6 @@ config TOUCHSCREEN_GT9XX
If unsure, say N.
-config TOUCHSCREEN_SWEEP2WAKE
- tristate "Sweep2Wake for touchscreens"
- select TOUCHSCREEN_PREVENT_SLEEP
- default n
-
-config TOUCHSCREEN_DOUBLETAP2WAKE
- tristate "DoubleTap2Wake for touchscreens"
- select TOUCHSCREEN_PREVENT_SLEEP
- default n
-
-
-config TOUCHSCREEN_PREVENT_SLEEP
- bool "Inihibit sleep on modified touchscreen drivers"
- default y
- help
- This disables the sleep function of modified touchscreen drivers.
-
source "drivers/input/touchscreen/gt9xx/Kconfig"
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 17872cb..c7114e8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH) += atmel_maxtouch.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ATMEL_640T) += atmel_mxt_ts_640t.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX) += synaptics_dsx/
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_BUTTON) += cyttsp_button.o
obj-$(CONFIG_TOUCHSCREEN_ST_FTS) += fts_ts.o fts_ts_i2c.o
@@ -82,10 +83,5 @@ obj-$(CONFIG_TOUCHSCREEN_MSM_LEGACY) += msm_touch.o
obj-$(CONFIG_TOUCHSCREEN_CY8C_TS) += cy8c_ts.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC) += cyttsp-i2c-qc.o
obj-$(CONFIG_TOUCHSCREEN_FT5X06) += ft5x06_ts.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o
-#obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o
-obj-$(CONFIG_TOUCHSCREEN_PREVENT_SLEEP) += wake_helpers.o
-obj-$(CONFIG_TOUCHSCREEN_SWEEP2WAKE) += sweep2wake.o
-obj-$(CONFIG_TOUCHSCREEN_DOUBLETAP2WAKE) += doubletap2wake.o
obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 6cebf50..0d6a56d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -18,7 +18,7 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
-#include <linux/i2c/atmel_mxt_ts_640t.h>
+#include <linux/i2c/atmel_mxt_ts.h>
#include <linux/debugfs.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
@@ -28,14 +28,6 @@
#include <linux/string.h>
#include <linux/of_gpio.h>
#include <asm/bootinfo.h>
-#include <mach/gpiomux.h>
-#ifdef CONFIG_FB
-#include <linux/notifier.h>
-#include <linux/fb.h>
-#endif
-#include <linux/input/sweep2wake.h>
-#include <linux/input/doubletap2wake.h>
-#include <linux/input/wake_helpers.h>
/* Version */
#define MXT_VER_20 20
@@ -46,8 +38,6 @@
#define MXT_FW_NAME "maxtouch.fw"
#define MXT_CFG_MAGIC "OBP_RAW V1"
-#define REV_D 0x32
-
/* Registers */
#define MXT_FAMILY_ID 0x00
#define MXT_VARIANT_ID 0x01
@@ -94,18 +84,13 @@
#define MXT_SPT_NOISESUPPRESSION_T48 48
#define MXT_PROCI_LENSBENDING_T65 65
#define MXT_SPT_GOLDENREF_T66 66
-#define MXT_SERIALDATACOMMAND_T68 68
#define MXT_SPT_DYMCFG_T70 70
#define MXT_SPT_DYMDATA_T71 71
#define MXT_PROCG_NOISESUPPRESSION_T72 72
#define MXT_PROCI_GLOVEDETECTION_T78 78
#define MXT_PROCI_RETRANSMISSIONCOMPENSATION_T80 80
-#define MXT_TOUCH_MORE_GESTURE_T81 81
-#define MXT_TOUCH_GESTURE_T92 92
#define MXT_TOUCH_MULTI_T100 100
-#define MXT_SPT_TOUCHSCREENHOVER_T101 101
-#define MXT_PROCG_NOISESUPSELFCAP_T108 108
-#define MXT_SPT_SELFCAPGLOBALCONFIG_T109 109
+#define MXT_SPT_SELFCAPHOVERCTECONFIG_T102 102
#define MXT_SPT_AUXTOUCHCONFIG_T104 104
/* MXT_GEN_MESSAGE_T5 object */
@@ -258,9 +243,7 @@
/* MXT_SPT_GPIOPWM_T19 */
#define MXT_GPIOPWM_CTRL 0
-#define MXT_GPIOPWM_INTPULLUP 3
#define MXT_GPIO_FORCERPT 0x7
-#define MXT_GPIO_DISABLEOUTPUT 0
/* MXT_SPT_CTECONFIG_T28 field */
#define MXT_CTE_CTRL 0
@@ -276,37 +259,28 @@
/* MXT_DEBUG_DIAGNOSTIC_T37 */
#define MXT_DIAG_PAGE_UP 0x01
#define MXT_DIAG_MULT_DELTA 0x10
-#define MXT_DIAG_SELF_REF 0xF5
+#define MXT_DIAG_MULT_REF 0x11
#define MXT_DIAG_SELF_DELTA 0xFC
#define MXT_DIAG_PAGE_SIZE 0x80
#define MXT_DIAG_TOTAL_SIZE 0x438
-#define MXT_DIAG_SELF_SIZE 0x6C
-#define MXT_DIAG_REV_ID 21
-#define MXT_LOCKDOWN_OFFSET 4
+#define MXT_DIAG_SELF_SIZE 0x5A
/* MXT_SPT_USERDATA_T38 */
#define MXT_FW_UPDATE_FLAG 0
-#define MXT_USERDATA_SIZE 8
/* MXT_PROCI_STYLUS_T47 */
#define MXT_PSTYLUS_CTRL 0
-/* MXT_PROCI_LENSBENDING_T65 */
-#define MXT_LENSBENDING_CTRL 0
-
-/* MXT_SERIALDATACOMMAND_T68 */
-#define MXT_LOCKDOWN_SIZE 8
-
/* MXT_PROCG_NOISESUPPRESSION_T72 */
-#define MXT_NOISESUP_CTRL 0
#define MXT_NOISESUP_CALCFG 1
#define MXT_NOISESUP_CFG1 2
/* MXT_PROCI_GLOVEDETECTION_T78 */
#define MXT_GLOVE_CTRL 0x00
-/* MXT_SPT_TOUCHSCREENHOVER_T101 */
-#define MXT_HOVER_CTRL 0x00
+/* MXT_SPT_SELFCAPHOVERCTECONFIG_T102 */
+#define MXT_SELF_CHGTIME 13
+#define MXT_SELF_RECALCFG 28
/* MXT_SPT_AUXTOUCHCONFIG_T104 */
#define MXT_AUXTCHCFG_XTCHTHR 2
@@ -314,11 +288,6 @@
#define MXT_AUXTCHCFG_YTCHTHR 7
#define MXT_AUXTCHCFG_INTTHRY 9
-/* MXT_SPT_SELFCAPGLOBALCONFIG_T109 */
-#define MXT_SELFCAPCFG_CTRL 0
-#define MXT_SELFCAPCFG_CMD 3
-
-
/* Defines for Suspend/Resume */
#define MXT_SUSPEND_STATIC 0
#define MXT_SUSPEND_DYNAMIC 1
@@ -389,27 +358,9 @@
#define MXT_T9_DETECT (1 << 7)
/* T100 Touch status */
-#define MXT_T100_CTRL_RPTEN (1 << 1)
-
-#define MXT_T100_EVENT_NONE 0
-#define MXT_T100_EVENT_MOVE 1
-#define MXT_T100_EVENT_UNSUP 2
-#define MXT_T100_EVENT_SUP 3
-#define MXT_T100_EVENT_DOWN 4
-#define MXT_T100_EVENT_UP 5
-#define MXT_T100_EVENT_UNSUPSUP 6
-#define MXT_T100_EVENT_UNSUPUP 7
-#define MXT_T100_EVENT_DOWNSUP 8
-#define MXT_T100_EVENT_DOWNUP 9
-
-#define MXT_T100_TYPE_RESERVED 0
-#define MXT_T100_TYPE_FINGER 1
-#define MXT_T100_TYPE_PASSIVE_STYLUS 2
-#define MXT_T100_TYPE_ACTIVE_STYLUS 3
-#define MXT_T100_TYPE_HOVERING_FINGER 4
-#define MXT_T100_TYPE_HOVERING_GLOVE 5
-
-#define MXT_T100_DETECT (1 << 7)
+#define MXT_T100_EVENT (1 << 0)
+#define MXT_T100_TYPE (1 << 4)
+#define MXT_T100_DETECT (1 << 7)
#define MXT_T100_VECT (1 << 0)
#define MXT_T100_AMPL (1 << 1)
#define MXT_T100_AREA (1 << 2)
@@ -418,7 +369,6 @@
#define MXT_T100_SUP (1 << 6)
/* T15 KeyArray */
-#define MXT_KEY_RPTEN (1 << 1)
#define MXT_KEY_ADAPTTHREN (1 << 2)
/* Touch orient bits */
@@ -462,6 +412,7 @@
#define MXT_GOLDSTS_FCALPASS (1 << 6)
#define MXT_GOLDSTS_FCALFAIL (1 << 7)
+#define MXT_GOLD_USECURR 0x80
#define MXT_GOLDCMD_NONE 0x00
#define MXT_GOLDCMD_PRIME 0x04
#define MXT_GOLDCMD_GENERATE 0x08
@@ -487,23 +438,20 @@
#define MXT_RETRANS_ATCHTHR 0x4
#define MXT_RETRANS_CTRL_MOISTCALEN (1 << 4)
-/* T81 gesture */
-#define MXT_GESTURE_CTRL 0x0
-
/* T72 noise suppression */
-#define MXT_NOICTRL_ENABLE (1 << 0)
#define MXT_NOICFG_VNOISY (1 << 1)
#define MXT_NOICFG_NOISY (1 << 0)
-/* T109 self-cap */
-#define MXT_SELFCTL_RPTEN 0x2
+/* T102 self-cap */
+#define MXT_SELFCAP_CMD 0x1
#define MXT_SELFCMD_TUNE 0x1
-#define MXT_SELFCMD_STM_TUNE 0x2
-#define MXT_SELFCMD_AFN_TUNE 0x3
-#define MXT_SELFCMD_STCR_TUNE 0x4
-#define MXT_SELFCMD_AFCR_TUNE 0x5
-#define MXT_SELFCMD_AFNVMSTCR_TUNE 0x6
-#define MXT_SELFCMD_RCR_TUNE 0x7
+#define MXT_SELFCMD_NVM_TUNE 0x2
+#define MXT_SELFCMD_RAM_TUNE 0x3
+#define MXT_SELFCMD_RAM_FINE 0x4
+#define MXT_SELFCMD_STORE 0x5
+#define MXT_SELFCMD_BG_TUNE 0x6
+#define MXT_SELFCAL_RECALHITHREN (1 << 6)
+#define MXT_SELFCAL_RECALLOTHREN (1 << 7)
#define MXT_DEBUGFS_DIR "atmel_mxt_ts"
#define MXT_DEBUGFS_FILE "object"
@@ -514,12 +462,9 @@
#define MXT_INPUT_EVENT_SENSITIVE_MODE_ON 1
#define MXT_INPUT_EVENT_STYLUS_MODE_OFF 2
#define MXT_INPUT_EVENT_STYLUS_MODE_ON 3
-#define MXT_INPUT_EVENT_WAKUP_MODE_OFF 4
-#define MXT_INPUT_EVENT_WAKUP_MODE_ON 5
-#define MXT_INPUT_EVENT_END 5
+#define MXT_INPUT_EVENT_END 3
-#define MXT_MAX_FINGER_NUM 16
-#define BOOTLOADER_1664_1188 1
+#define MXT_MAX_FINGER_NUM 10
struct mxt_info {
u8 family_id;
@@ -563,10 +508,17 @@ struct mxt_golden_msg {
struct mxt_selfcap_status {
- u8 cmd;
+ u8 cause;
u8 error_code;
};
+struct mxt_finger {
+ int x;
+ int y;
+ int state;
+ unsigned long jiffies_val;
+};
+
struct mxt_mode_switch {
struct mxt_data *data;
u8 mode;
@@ -582,7 +534,6 @@ struct mxt_data {
struct mxt_object *object_table;
struct regulator *regulator_vdd;
struct regulator *regulator_avdd;
- struct regulator *regulator_vddio;
u16 mem_size;
struct mxt_info info;
unsigned int irq;
@@ -606,28 +557,44 @@ struct mxt_data {
u8 t100_tchaux_bits;
unsigned long keystatus;
u8 vendor_id;
- u8 rev_id;
int current_index;
u8 update_flag;
+ u8 gr_enable;
+ int golden_ok;
u8 test_result[6];
+ u8 selfthr_save;
+ u8 intthr_save;
+ struct mxt_finger finger;
+ struct mxt_finger finger_tracker[MXT_MAX_FINGER_NUM];
+ int land_signed;
int touch_num;
+ int self_restore_done;
+ u8 anti_calib[4];
u8 diag_mode;
u8 atchthr;
+ u8 self_recalib_para;
+ struct workqueue_struct* work_queue;
+ struct delayed_work update_setting_delayed_work;
+ struct delayed_work disable_anticalib_delayed_work;
+ struct work_struct pre_use_work;
u8 sensitive_mode;
u8 stylus_mode;
- u8 wakeup_gesture_mode;
- bool is_wakeup_by_gesture;
- int hover_tune_status;
- struct delayed_work calibration_delayed_work;
- u8 adcperx_normal[10];
- u8 adcperx_wakeup[10];
+ bool cal_in_progress;
+ bool is_recalib_available;
+ int safe_count;
+ int prev_status;
+ u16 ref_diff_threshold;
+ int *ignore_tx;
+ int *ignore_rx;
+ int ignore_tx_num;
+ int ignore_rx_num;
+ bool is_ignore_channel_saved;
+ bool init_complete;
+ bool use_last_golden;
bool irq_enabled;
- u8 lockdown_info[MXT_LOCKDOWN_SIZE];
- u8 userdata_info[MXT_USERDATA_SIZE];
- bool firmware_updated;
+ struct mutex golden_mutex;
bool keys_off;
- bool hw_wakeup;
- bool screen_off;
+
/* Slowscan parameters */
int slowscan_enabled;
@@ -639,9 +606,6 @@ struct mxt_data {
u8 slowscan_shad_actv2idle_timeout;
struct mxt_golden_msg golden_msg;
struct mxt_selfcap_status selfcap_status;
- struct work_struct self_tuning_work;
- struct work_struct hover_loading_work;
- bool finger_down[MXT_MAX_FINGER_NUM];
/* Cached parameters from object table */
u16 T5_address;
@@ -664,20 +628,14 @@ struct mxt_data {
u8 T63_reportid_min;
u8 T63_reportid_max;
u8 T66_reportid;
- u8 T81_reportid_min;
- u8 T81_reportid_max;
- u8 T92_reportid_min;
- u8 T92_reportid_max;
u8 T100_reportid_min;
u8 T100_reportid_max;
- u8 T109_reportid;
-
-#ifdef CONFIG_FB
- struct notifier_block fb_notif;
-#endif
+ u8 T102_reportid;
};
static struct mxt_suspend mxt_save[] = {
+ {MXT_PROCG_NOISE_T22, MXT_NOISE_CTRL,
+ MXT_T22_DISABLE, MXT_SUSPEND_DYNAMIC, 0},
{MXT_GEN_POWER_T7, MXT_POWER_IDLEACQINT,
MXT_T7_IDLEACQ_DISABLE, MXT_SUSPEND_DYNAMIC, 0},
{MXT_GEN_POWER_T7, MXT_POWER_ACTVACQINT,
@@ -704,23 +662,9 @@ static const struct mxt_i2c_address_pair mxt_i2c_addresses[] = {
{ 0x34, 0x5a },
{ 0x35, 0x5b },
#endif
-};
-
-static struct gpiomux_setting mxt_rst_cutoff_pwr_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_NONE,
-};
-static struct gpiomux_setting mxt_int_cutoff_pwr_cfg = {
- .func = GPIOMUX_FUNC_GPIO,
- .drv = GPIOMUX_DRV_6MA,
- .pull = GPIOMUX_PULL_NONE,
};
-static ssize_t mxt_update_firmware(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count, bool *upgraded);
-
static int mxt_bootloader_read(struct mxt_data *data, u8 *val, unsigned int count)
{
int ret;
@@ -808,29 +752,13 @@ static u8 mxt_read_chg(struct mxt_data *data)
return val;
}
-static void mxt_disable_irq(struct mxt_data *data)
-{
- if (likely(data->irq_enabled)) {
- disable_irq(data->irq);
- data->irq_enabled = false;
- }
-}
-
-static void mxt_enable_irq(struct mxt_data *data)
-{
- if (likely(!data->irq_enabled)) {
- enable_irq(data->irq);
- data->irq_enabled = true;
- }
-}
-
static int mxt_wait_for_chg(struct mxt_data *data)
{
int timeout_counter = 0;
- int count = 10;
+ int count = 100;
while ((timeout_counter++ <= count) && mxt_read_chg(data))
- mdelay(10);
+ msleep(10);
if (timeout_counter > count) {
dev_err(&data->client->dev, "mxt_wait_for_chg() timeout!\n");
@@ -932,10 +860,13 @@ static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
return 0;
}
+static int mxt_chip_reset(struct mxt_data *data);
+
static int mxt_read_reg(struct i2c_client *client,
u16 reg, u16 len, void *val)
{
struct device *dev = &client->dev;
+ struct mxt_data *data = i2c_get_clientdata(client);
struct i2c_msg xfer[2];
u8 buf[2];
int ret;
@@ -959,6 +890,8 @@ static int mxt_read_reg(struct i2c_client *client,
if (ret != ARRAY_SIZE(xfer)) {
dev_err(dev, "%s: i2c transfer failed (%d)\n",
__func__, ret);
+ if (data->init_complete)
+ mxt_chip_reset(data);
return -EIO;
}
@@ -968,6 +901,7 @@ static int mxt_read_reg(struct i2c_client *client,
static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
{
struct device *dev = &client->dev;
+ struct mxt_data *data = i2c_get_clientdata(client);
u8 buf[3];
buf[0] = reg & 0xff;
@@ -976,13 +910,15 @@ static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
if (i2c_master_send(client, buf, 3) != 3) {
dev_err(dev, "%s: i2c send failed\n", __func__);
+ if (data->init_complete)
+ mxt_chip_reset(data);
return -EIO;
}
return 0;
}
-static int mxt_write_block(struct i2c_client *client, u16 addr, u16 length, u8 *value)
+int mxt_write_block(struct i2c_client *client, u16 addr, u16 length, u8 *value)
{
int i;
struct {
@@ -1063,29 +999,6 @@ static int mxt_write_object(struct mxt_data *data,
return ret;
}
-static int mxt_set_clr_reg(struct mxt_data *data,
- u8 type, u8 offset, u8 mask_s, u8 mask_c)
-{
- int error;
- u8 val;
-
- error = mxt_read_object(data, type, offset, &val);
- if (error) {
- dev_err(&data->client->dev,
- "Failed to read object %d\n", (int)type);
- return error;
- }
-
- val &= ~mask_c;
- val |= mask_s;
-
- error = mxt_write_object(data, type, offset, val);
- if (error)
- dev_err(&data->client->dev,
- "Failed to write object %d\n", (int)type);
- return error;
-}
-
static int mxt_soft_reset(struct mxt_data *data, u8 value)
{
struct device *dev = &data->client->dev;
@@ -1100,6 +1013,48 @@ static int mxt_soft_reset(struct mxt_data *data, u8 value)
return 0;
}
+static void mxt_anti_calib_control(struct mxt_data *data, bool enable)
+{
+ struct device *dev = &data->client->dev;
+ int error;
+ int i;
+ int count = sizeof(data->anti_calib);
+ u8 anti_calib[] = {0xFF, 0x01, 0x00, 0x00};
+
+ if (enable) {
+ anti_calib[0] = data->anti_calib[0];
+ anti_calib[1] = data->anti_calib[1];
+ anti_calib[2] = data->anti_calib[2];
+ anti_calib[3] = data->anti_calib[3];
+ }
+
+ for (i = 0; i < count; i++) {
+ error = mxt_write_object(data, MXT_GEN_ACQUIRE_T8,
+ MXT_ACQUIRE_ATCHCALST+i, anti_calib[i]);
+ if (error) {
+ dev_err(dev, "write to t8 failed!\n");
+ return;
+ }
+ }
+}
+
+static void mxt_self_recalib_control(struct mxt_data *data, bool enable)
+{
+ struct device *dev = &data->client->dev;
+ int error;
+ u8 val;
+
+ if (enable)
+ val = data->self_recalib_para;
+ else
+ val = 0x3F;
+
+ error = mxt_write_object(data, MXT_SPT_SELFCAPHOVERCTECONFIG_T102,
+ MXT_SELF_RECALCFG, val);
+ if (error)
+ dev_err(dev, "Failed to write t102 recalib!\n");
+}
+
static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
{
struct device *dev = &data->client->dev;
@@ -1115,6 +1070,17 @@ static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
if (status & MXT_STATUS_CAL) {
dev_info(dev, "Calibration start!\n");
+ if (data->is_recalib_available) {
+ mxt_anti_calib_control(data, true);
+ mxt_self_recalib_control(data, true);
+ data->cal_in_progress = true;
+ }
+ } else if (data->cal_in_progress) {
+ dev_info(dev, "Schedule delayed work for anti-touch setting!\n");
+ if (data->is_recalib_available) {
+ queue_delayed_work(data->work_queue, &data->update_setting_delayed_work, HZ);
+ data->cal_in_progress = false;
+ }
}
if (status)
@@ -1206,6 +1172,56 @@ static void mxt_proc_t9_messages(struct mxt_data *data, u8 *message)
}
}
+#define TYPE_SELF_THR 0x1
+#define TYPE_SELF_INTTHR_STYLUS 0x2
+#define TYPE_SELF_INTTHR_SUSPEND 0x3
+static void mxt_adjust_self_setting(struct mxt_data *data, bool is_update, u8 type)
+{
+ struct device *dev = &data->client->dev;
+ const struct mxt_platform_data *pdata = data->pdata;
+ int error, i;
+ u8 update_val = 0;
+ u8 original_val = 0;
+ int index = data->current_index;
+ u8 reg_pos[2];
+ u8 val;
+ int count = sizeof(reg_pos);
+ u8 obj_num = MXT_SPT_AUXTOUCHCONFIG_T104;
+
+ if (type == TYPE_SELF_THR) {
+ update_val = pdata->config_array[index].selfthr_suspend;
+ original_val = data->selfthr_save;
+ reg_pos[0] = MXT_AUXTCHCFG_XTCHTHR;
+ reg_pos[1] = MXT_AUXTCHCFG_YTCHTHR;
+ } else if (type == TYPE_SELF_INTTHR_STYLUS) {
+ update_val = pdata->config_array[index].selfintthr_stylus;
+ original_val = data->intthr_save;
+ reg_pos[0] = MXT_AUXTCHCFG_INTTHRX;
+ reg_pos[1] = MXT_AUXTCHCFG_INTTHRY;
+ } else if (type == TYPE_SELF_INTTHR_SUSPEND) {
+ update_val = pdata->config_array[index].selfintthr_suspend;
+ original_val = data->intthr_save;
+ reg_pos[0] = MXT_AUXTCHCFG_INTTHRX;
+ reg_pos[1] = MXT_AUXTCHCFG_INTTHRY;
+ }
+
+ if(update_val == 0)
+ return;
+
+ if (is_update)
+ val = update_val;
+ else
+ val =original_val;
+
+ for (i = 0; i < count; i++) {
+ error = mxt_write_object(data, obj_num, reg_pos[i], val);
+ if (error) {
+ dev_err(dev, "Failed to write T104 pos 0x%x!\n", reg_pos[i]);
+ return;
+ }
+ }
+}
+
static int mxt_do_diagnostic(struct mxt_data *data, u8 mode)
{
int error = 0;
@@ -1235,25 +1251,306 @@ static int mxt_do_diagnostic(struct mxt_data *data, u8 mode)
return -ETIMEDOUT;
}
-static void mxt_set_t7_for_gesture(struct mxt_data *data, bool enable);
-static void mxt_set_gesture_wake_up(struct mxt_data *data, bool enable);
+#define DELTA_TYPE_SELF 0x1
+#define DELTA_TYPE_MULT 0x2
+#define REF_TYPE_MULT 0x3
+#define REF_TYPE_MULT_MAX 0x4
+#define MONITOR_HAS_RISK 0x0
+#define MONITOR_NO_RISK 0x1
+#define MONITOR_IGNORE_IT 0x2
-static int mxt_prevent_sleep() {
- if (in_phone_call())
- return 0;
+static bool mxt_should_ignore_line(struct mxt_data *data,
+ bool is_rx, int line)
+{
+ int i;
+ int num;
+ int *target_array;
+
+ if (is_rx) {
+ num = data->ignore_rx_num;
+ target_array = data->ignore_rx;
+ }
+ else {
+ num = data->ignore_tx_num;
+ target_array = data->ignore_tx;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (line == target_array[i])
+ return true;
+ }
+
+ return false;
+}
+
+static int mxt_monitor_delta_no_calib_risk(struct mxt_data *data, u8 type)
+{
+ struct device *dev = &data->client->dev;
+ int error, i;
+ u16 addr = data->T37_address;
+ short val, no_touch_threshold, prev_val;
+ u8 *buf;
+ size_t buf_size;
+ u8 mode;
+ const struct mxt_platform_data *pdata = data->pdata;
+ int index = data->current_index;
+ int result = MONITOR_NO_RISK;
+ int read_size = 0;
+ int count = 0, row = 0;
+ short *ref_buf;
+ int diff_max;
+
+ if (type == DELTA_TYPE_SELF) {
+ buf_size = MXT_DIAG_SELF_SIZE;
+ mode = MXT_DIAG_SELF_DELTA;
+ no_touch_threshold = pdata->config_array[index].self_no_touch_threshold;
+ } else if (type == DELTA_TYPE_MULT) {
+ buf_size = MXT_DIAG_TOTAL_SIZE;
+ mode = MXT_DIAG_MULT_DELTA;
+ no_touch_threshold = pdata->config_array[index].mult_no_touch_threshold;
+ } else if (type == REF_TYPE_MULT || type == REF_TYPE_MULT_MAX) {
+ buf_size = MXT_DIAG_TOTAL_SIZE;
+ mode = MXT_DIAG_MULT_REF;
+ ref_buf = (short*)kmalloc(sizeof(short) * (buf_size >> 1), GFP_KERNEL);
+ if (ref_buf == NULL)
+ return MONITOR_NO_RISK;
+ } else
+ return MONITOR_NO_RISK;
+
+ buf = kmalloc(buf_size, GFP_KERNEL);
+ if (buf == NULL) {
+ dev_err(dev, "Failed to alloc buffer for delta getting!\n");
+ return MONITOR_NO_RISK;
+ }
+
+ error = mxt_do_diagnostic(data, mode);
+ if (error) {
+ dev_err(dev, "Failed to send get self delta data cmd!\n");
+ result = false;
+ goto end;
+ }
+
+ while (read_size < buf_size) {
+ error = mxt_read_reg(data->client, addr + 2,
+ MXT_DIAG_PAGE_SIZE, buf + read_size);
+ if (error) {
+ dev_err(dev, "Read from T37 failed!\n");
+ return error;
+ }
+
+ read_size += MXT_DIAG_PAGE_SIZE;
+
+ error = mxt_do_diagnostic(data, MXT_DIAG_PAGE_UP);
+ if (error) {
+ dev_err(dev, "do diagnostic 0x%02x failed!\n", MXT_DIAG_PAGE_UP);
+ return error;
+ }
+ }
+
+ for (i = 0; i < buf_size; i += 2) {
+ val = (buf[i+1] << 8) | buf[i];
+ if (data->debug_enabled && type != REF_TYPE_MULT)
+ dev_info(dev, "val = 0x%04x\n", val);
+ if (type == DELTA_TYPE_SELF) {
+ if (abs(val) > no_touch_threshold)
+ result = MONITOR_HAS_RISK;
+ } else if (type == DELTA_TYPE_MULT) {
+ if (val > no_touch_threshold || val < -(no_touch_threshold)) {
+ if (data->debug_enabled)
+ pr_info("risk val = %d\n", (int)val);
+ result = MONITOR_HAS_RISK;
+ }
+ } else if (type == REF_TYPE_MULT || type == REF_TYPE_MULT_MAX) {
+ ref_buf[row * pdata->rx_num + count] = val;
+ count ++;
+ if (data->debug_enabled) {
+ if (count == 1)
+ printk(KERN_CONT "#### ");
+ printk(KERN_CONT "%5d ", val);
+ }
+ if (count >= 2) {
+ short delta;
+ delta = val - prev_val;
+ if (count < (pdata->rx_num - 1) && row < (pdata->tx_num - 4)) {
+ if (abs(delta) >= pdata->ref_diff_threshold &&
+ type == REF_TYPE_MULT_MAX) {
+ if (!mxt_should_ignore_line(data, true, count)) {
+ data->ignore_rx[data->ignore_rx_num++] = count;
+ pr_info("ignore column = %d\n", count);
+ }
+ }
+ if (abs(delta) >= diff_max &&
+ type == REF_TYPE_MULT_MAX)
+ diff_max = abs(delta);
+
+ if (type == REF_TYPE_MULT) {
+ if (!mxt_should_ignore_line(data, true, count)) {
+ if (abs(delta) >= data->ref_diff_threshold) {
+ dev_info(dev, "horizontal failed diff row = %d, col = %d, diff = %d\n",
+ row, count, delta);
+ result = MONITOR_HAS_RISK;
+ break;
+ }
+ } else if (data->debug_enabled)
+ dev_info(dev, "col %d is ignored!\n", count);
+ }
+ }
+ }
+
+ if (row >= 1 && row < (pdata->tx_num - 4) &&
+ row != pdata->tx_num/2) { /* skip last line and half line*/
+ short delta = val - ref_buf[(row -1) * pdata->rx_num + count - 1];
+ if (abs(delta) >= pdata->ref_diff_threshold &&
+ type == REF_TYPE_MULT_MAX) {
+ if (!mxt_should_ignore_line(data, false, row)) {
+ data->ignore_tx[data->ignore_tx_num++] = row;
+ pr_info("ignore row = %d\n", row);
+ }
+ }
+ if (abs(delta) >= diff_max &&
+ type == REF_TYPE_MULT_MAX)
+ diff_max = abs(delta);
+
+ if (type == REF_TYPE_MULT) {
+ if (!mxt_should_ignore_line(data, false, row)) {
+ if (abs(delta) >= data->ref_diff_threshold) {
+ dev_info(dev, "vertical failed diff row = %d, col = %d, diff = %d\n",
+ row, count, delta);
+ result = MONITOR_HAS_RISK;
+ break;
+ }
+ } else if (data->debug_enabled)
+ dev_info(dev, "row %d is ignored!\n", row);
+ }
+ }
+
+ if (count == pdata->rx_num) {
+ if (data->debug_enabled)
+ printk(KERN_CONT "\n");
+ count = 0;
+ row ++;
+ }
+ prev_val = val;
+ }
+ }
+
+ if (type == DELTA_TYPE_SELF && result == MONITOR_HAS_RISK) {
+ if (data->self_restore_done && data->touch_num > 0) {
+ dev_info(dev, "ignore current polling!\n");
+ result = MONITOR_IGNORE_IT;
- if (s2w_switch > 0 || dt2w_switch == 1)
- return 1;
+ } else if (!data->self_restore_done && data->touch_num == 1) {
+ dev_info(dev, "ignore current polling!\n");
+ result = MONITOR_IGNORE_IT;
+ }
+ }
+
+end:
+ if (type == REF_TYPE_MULT || type == REF_TYPE_MULT_MAX)
+ kfree(ref_buf);
+ kfree(buf);
+ if (type != REF_TYPE_MULT_MAX)
+ return result;
else
- return 0;
+ return diff_max;
+}
+
+static void mxt_do_calibration(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int error, i;
+ u8 val;
+ int time_out = 100;
+
+ error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_CALIBRATE, 1);
+ if (error) {
+ dev_err(dev, "failed to do calibration!\n");
+ return;
+ }
+
+ for (i = 0; i < time_out; i++) {
+ error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_CALIBRATE, &val);
+ if (error) {
+ dev_err(dev, "failed to read calibration!\n");
+ return;
+ }
+
+ if (val == 0)
+ break;
+ msleep(10);
+ }
+}
+
+#define MAX_SAFE_COUNT 8
+#define RISK_WEIGHT 2
+#define SAFE_WEIGHT 1
+static void mxt_update_setting_delayed_work(struct work_struct *work)
+{
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct mxt_data *data = container_of(delayed_work, struct mxt_data, update_setting_delayed_work);
+ int status;
+ u8 monitor_type;
+
+ dev_info(&data->client->dev,
+ "Update setting delayed work called. safe_count = %d\n",
+ data->safe_count);
+
+ if (data->gr_enable)
+ monitor_type = DELTA_TYPE_SELF;
+ else
+ monitor_type = REF_TYPE_MULT;
+ status = mxt_monitor_delta_no_calib_risk(data, monitor_type);
+ if (status == MONITOR_NO_RISK) {
+ if (data->prev_status == MONITOR_HAS_RISK) {
+ if (data->safe_count >= RISK_WEIGHT)
+ data->safe_count -= RISK_WEIGHT;
+ } else if (data->prev_status == MONITOR_NO_RISK)
+ data->safe_count += SAFE_WEIGHT;
+ if (data->safe_count == MAX_SAFE_COUNT) {
+ data->safe_count = 0;
+ queue_delayed_work(data->work_queue, &data->disable_anticalib_delayed_work, HZ);
+ } else
+ queue_delayed_work(data->work_queue, &data->update_setting_delayed_work, HZ);
+ }
+ else {
+ if (status == MONITOR_HAS_RISK) {
+ if (!data->gr_enable || data->sensitive_mode) {
+ mxt_do_calibration(data);
+ }
+ }
+
+ queue_delayed_work(data->work_queue, &data->update_setting_delayed_work, HZ);
+ }
+
+ data->prev_status = status;
}
+static int mxt_do_curr_golden_ref_tune(struct mxt_data *data);
+
+static void mxt_disable_anticalib_delayed_work(struct work_struct *work)
+{
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct mxt_data *data = container_of(delayed_work, struct mxt_data, disable_anticalib_delayed_work);
+ int error;
+
+ mxt_anti_calib_control(data, false);
+ mxt_self_recalib_control(data, false);
+ if (!data->use_last_golden && !data->gr_enable) {
+ error = mxt_do_curr_golden_ref_tune(data);
+ if (!error) {
+ dev_info(&data->client->dev, "last golden OK, set flag !\n");
+ data->use_last_golden = true;
+ }
+ }
+}
static void mxt_proc_t100_messages(struct mxt_data *data, u8 *message)
{
struct device *dev = &data->client->dev;
struct input_dev *input_dev = data->input_dev;
- u8 status, touch_type, touch_event;
+ u8 status;
int x;
int y;
int area = 0;
@@ -1262,6 +1559,7 @@ static void mxt_proc_t100_messages(struct mxt_data *data, u8 *message)
u8 peak = 0;
int id;
int index = 0;
+ int finger_state = 0;
if (!input_dev || data->driver_paused)
return;
@@ -1279,6 +1577,8 @@ static void mxt_proc_t100_messages(struct mxt_data *data, u8 *message)
data->touch_num = message[2];
if (data->debug_enabled)
dev_info(dev, "touch num = %d\n", data->touch_num);
+ if (data->touch_num > 1 && !data->self_restore_done)
+ data->land_signed = 0;
if (status & MXT_T100_SUP)
{
@@ -1292,9 +1592,8 @@ static void mxt_proc_t100_messages(struct mxt_data *data, u8 *message)
}
else if (id >= 2) {
/* deal with each point report */
+ int prev_state = data->finger_tracker[id - 2].state;
status = message[1];
- touch_type = (status & 0x70) >> 4;
- touch_event = status & 0x0F;
x = (message[3] << 8) | (message[2] & 0xFF);
y = (message[5] << 8) | (message[4] & 0xFF);
index = 6;
@@ -1313,55 +1612,98 @@ static void mxt_proc_t100_messages(struct mxt_data *data, u8 *message)
input_mt_slot(input_dev, id - 2);
if (status & MXT_T100_DETECT) {
- if (touch_event == MXT_T100_EVENT_DOWN || touch_event == MXT_T100_EVENT_UNSUP
- || touch_event == MXT_T100_EVENT_MOVE || touch_event == MXT_T100_EVENT_NONE) {
- /* Touch in detect, report X/Y position */
- if (touch_event == MXT_T100_EVENT_DOWN ||
- touch_event == MXT_T100_EVENT_UNSUP)
- data->finger_down[id - 2] = true;
- if ((touch_event == MXT_T100_EVENT_MOVE ||
- touch_event == MXT_T100_EVENT_NONE) &&
- !data->finger_down[id - 2])
- return;
-
- input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
- input_report_abs(input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
- if (touch_type == MXT_T100_TYPE_HOVERING_FINGER)
- input_report_abs(input_dev, BTN_TOUCH, 0);
- else
- input_report_abs(input_dev, BTN_TOUCH, 1);
-
- if (data->t100_tchaux_bits & MXT_T100_AMPL) {
- if (touch_type == MXT_T100_TYPE_HOVERING_FINGER)
- amplitude = 0;
- else if (amplitude == 0)
- amplitude = 1;
- input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
+ finger_state |= 1;
+ if (prev_state == 0) {
+ data->finger_tracker[id - 2].x = x;
+ data->finger_tracker[id - 2].y = y;
+ data->finger_tracker[id - 2].jiffies_val = jiffies;
+ } else {
+ unsigned long landed_jiffies;
+ int delta_x, delta_y, threshold;
+
+ landed_jiffies = data->finger_tracker[id - 2].jiffies_val;
+ landed_jiffies += data->pdata->landing_jiffies;
+
+ if ((prev_state & 0x80) == 0) {
+ /* use the big threshold for landing period */
+ if (time_before(jiffies, landed_jiffies)) {
+ if (data->finger_tracker[id - 2].x >= data->max_x - data->pdata->edge_clip ||
+ data->finger_tracker[id - 2].x <= data->pdata->edge_clip)
+ threshold = data->pdata->landing_edge_threshold;
+ else
+ threshold = data->pdata->landing_threshold;
+ }
+ else /* use the middle jitter threshold */
+ threshold = data->pdata->staying_threshold;
+ } else { /* use the small threshold during movement */
+ threshold = data->pdata->moving_threshold;
}
- if (data->t100_tchaux_bits & MXT_T100_AREA) {
- if (touch_type == MXT_T100_TYPE_HOVERING_FINGER)
- area = 0;
- else if (area == 0)
- area = 1;
- input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
+ delta_x = x - data->finger_tracker[id - 2].x;
+ delta_y = y - data->finger_tracker[id - 2].y;
+
+ /* report the recorded position if the change is small */
+ if (delta_x * delta_x + delta_y * delta_y <= threshold * threshold) {
+ x = data->finger_tracker[id - 2].x;
+ y = data->finger_tracker[id - 2].y;
+ finger_state |= (prev_state & 0x80);
+ } else { /* save new location and set moving flag */
+ data->finger_tracker[id - 2].x = x;
+ data->finger_tracker[id - 2].y = y;
+ finger_state |= 0x80;
}
- if (data->t100_tchaux_bits & MXT_T100_VECT)
- input_report_abs(input_dev, ABS_MT_ORIENTATION, vector);
+ }
+ /* Touch in detect, report X/Y position */
+ if (data->touch_num == 1 &&
+ !data->land_signed &&
+ !data->self_restore_done) {
+ data->finger.x = x;
+ data->finger.y = y;
+ data->land_signed = 1;
+ if (data->debug_enabled)
+ dev_info(dev, "One touch signed\n");
+ }
+
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+
+ if (data->t100_tchaux_bits & MXT_T100_AMPL)
+ {
+ if (amplitude == 0)
+ amplitude = 1;
+ input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
+ }
+ if (data->t100_tchaux_bits & MXT_T100_AREA) {
+ if (area == 0)
+ area = 1;
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
+ }
+ if (data->t100_tchaux_bits & MXT_T100_VECT) {
+ if (vector == 0)
+ vector = 1;
+ input_report_abs(input_dev, ABS_MT_ORIENTATION, vector);
}
} else {
/* Touch no longer in detect, so close out slot */
if (data->touch_num == 0 &&
- mxt_prevent_sleep() &&
- data->is_wakeup_by_gesture) {
- dev_info(dev, "wakeup finger release, restore t7 and t8!\n");
- data->is_wakeup_by_gesture = false;
- mxt_set_t7_for_gesture(data, false);
+ data->land_signed &&
+ !data->self_restore_done) {
+ int delta_x = x - data->finger.x;
+ int delta_y = y - data->finger.y;
+ if(delta_x * delta_x + delta_y * delta_y >=
+ data->pdata->unlock_move_threshold) {
+ data->self_restore_done = true;
+ mxt_adjust_self_setting(data, false, TYPE_SELF_THR);
+ mxt_adjust_self_setting(data, false, TYPE_SELF_INTTHR_SUSPEND);
+ dev_info(dev, "unlocked, set intthr to normal!\n");
+ } else
+ data->land_signed = 0;
}
+ finger_state = 0;
mxt_input_sync(data);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
- data->finger_down[id - 2] = false;
}
+ data->finger_tracker[id - 2].state = finger_state;
}
}
@@ -1375,7 +1717,8 @@ static void mxt_proc_t15_messages(struct mxt_data *data, u8 *msg)
bool sync = false;
unsigned long keystates = le32_to_cpu(msg[2]);
int index = data->current_index;
- if(data->keys_off || data->screen_off) {
+
+ if(data->keys_off) {
return;
}
@@ -1405,15 +1748,9 @@ static void mxt_proc_t19_messages(struct mxt_data *data, u8 *msg)
struct device *dev = &data->client->dev;
const struct mxt_platform_data *pdata = data->pdata;
- if (get_hw_version_major() == 5) {
- dev_info(dev, "T19 is not used for distinguishing TP vendor in X5\n");
- return;
- }
-
data->vendor_id = msg[1];
data->vendor_id &= pdata->gpio_mask;
- dev_info(dev, "T19: vendor_id & gpio_mask = 0x%x & 0x%x = 0x%x\n",
- msg[1], pdata->gpio_mask, data->vendor_id);
+ dev_info(dev, "T19: vendor_id = 0x%x\n", data->vendor_id);
}
static void mxt_proc_t25_messages(struct mxt_data *data, u8 *msg)
@@ -1511,6 +1848,7 @@ static void mxt_proc_t66_messages(struct mxt_data *data, u8 *msg)
{
struct device *dev = &data->client->dev;
+ mutex_lock(&data->golden_mutex);
dev_info(dev, "message for t66= 0x%x 0x%x 0x%x 0x%x\n",
msg[1], msg[2], msg[3], msg[4]);
@@ -1518,46 +1856,22 @@ static void mxt_proc_t66_messages(struct mxt_data *data, u8 *msg)
data->golden_msg.fcalmaxdiff = msg[2];
data->golden_msg.fcalmaxdiffx = msg[3];
data->golden_msg.fcalmaxdiffy = msg[4];
+ mutex_unlock(&data->golden_mutex);
}
-static void mxt_proc_t81_message(struct mxt_data *data, u8 *msg)
+static void mxt_proc_t102_messages(struct mxt_data *data, u8 *msg)
{
struct device *dev = &data->client->dev;
- struct input_dev *input_dev = data->input_dev;
- dev_info(dev, "msg for t81 = 0x%x 0x%x\n",
- msg[0], msg[1]);
+ dev_info(dev, "msg for t102 = 0x%x 0x%x 0x%x 0x%x\n",
+ msg[2], msg[3], msg[4], msg[5]);
- if (data->is_stopped) {
- data->is_wakeup_by_gesture = true;
- input_event(input_dev, EV_KEY, KEY_POWER, 1);
- input_sync(input_dev);
- input_event(input_dev, EV_KEY, KEY_POWER, 0);
- input_sync(input_dev);
+ if (msg[2] == 0x3) {
+ data->selfcap_status.cause = msg[2];
+ data->selfcap_status.error_code = msg[3];
}
}
-static void mxt_proc_t92_message(struct mxt_data *data, u8 *msg)
-{
- struct device *dev = &data->client->dev;
-
- dev_info(dev, "msg for t92 = 0x%x 0x%x\n",
- msg[0], msg[1]);
-
- /* we can do something to handle wakeup gesture */
-}
-
-static void mxt_proc_t109_messages(struct mxt_data *data, u8 *msg)
-{
- struct device *dev = &data->client->dev;
-
- dev_info(dev, "msg for t109 = 0x%x 0x%x\n",
- msg[1], msg[2]);
-
- data->selfcap_status.cmd = msg[1];
- data->selfcap_status.error_code = msg[2];
-}
-
static int mxt_proc_message(struct mxt_data *data, u8 *msg)
{
u8 report_id = msg[0];
@@ -1593,17 +1907,11 @@ static int mxt_proc_message(struct mxt_data *data, u8 *msg)
mxt_proc_t42_messages(data, msg);
} else if (report_id == data->T66_reportid) {
mxt_proc_t66_messages(data, msg);
- } else if (report_id >= data->T81_reportid_min
- && report_id <= data->T81_reportid_max) {
- mxt_proc_t81_message(data, msg);
- } else if (report_id >= data->T92_reportid_min
- && report_id <= data->T92_reportid_max) {
- mxt_proc_t92_message(data, msg);
} else if (report_id >= data->T100_reportid_min
&& report_id <= data->T100_reportid_max) {
mxt_proc_t100_messages(data, msg);
- } else if (report_id == data->T109_reportid) {
- mxt_proc_t109_messages(data, msg);
+ } else if (report_id == data->T102_reportid) {
+ mxt_proc_t102_messages(data, msg);
}
return 0;
@@ -1748,7 +2056,6 @@ update_count:
static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;
-
if (data->T44_address)
return mxt_read_messages_t44(data);
else
@@ -1773,7 +2080,7 @@ static void mxt_read_current_crc(struct mxt_data *data)
/* on failure, CRC is set to 0 and config will always be downloaded */
}
-static int mxt_download_config(struct mxt_data *data, const char *fn)
+int mxt_download_config(struct mxt_data *data, const char *fn)
{
struct device *dev = &data->client->dev;
struct mxt_info cfg_info;
@@ -1791,7 +2098,6 @@ static int mxt_download_config(struct mxt_data *data, const char *fn)
unsigned int type, instance, size;
u8 val;
u16 reg;
- int add_num = 0;
ret = request_firmware(&cfg, fn, dev);
if (ret < 0) {
@@ -1883,16 +2189,6 @@ static int mxt_download_config(struct mxt_data *data, const char *fn)
goto release_mem;
}
data_pos += offset;
- if (type == 35) {
- if (instance == 0) {
- type = 150 + add_num;
- add_num ++;
- } else
- type = 150 + add_num - 1;
- }
-
- pr_info("write to type = %d, instance = %d, size = %d, offset = %d\n",
- (int)type, (int)instance, (int)size, (int)offset);
object = mxt_get_object(data, type);
if (!object) {
@@ -1910,27 +2206,28 @@ static int mxt_download_config(struct mxt_data *data, const char *fn)
if (size > object->size) {
/* Either we are in fallback mode due to wrong
- * config or config from a later fw version,
- * or the file is corrupt or hand-edited */
+ * config or config from a later fw version,
+ * or the file is corrupt or hand-edited */
dev_warn(dev, "Discarding %u bytes in T%u!\n",
- size - object->size, type);
+ size - object->size, type);
+
size = object->size;
} else if (object->size > size) {
/* If firmware is upgraded, new bytes may be added to
- * end of objects. It is generally forward compatible
- * to zero these bytes - previous behaviour will be
- * retained. However this does invalidate the CRC and
- * will force fallback mode until the configuration is
- * updated. We warn here but do nothing else - the
- * malloc has zeroed the entire configuration. */
+ * end of objects. It is generally forward compatible
+ * to zero these bytes - previous behaviour will be
+ * retained. However this does invalidate the CRC and
+ * will force fallback mode until the configuration is
+ * updated. We warn here but do nothing else - the
+ * malloc has zeroed the entire configuration. */
dev_warn(dev, "Zeroing %d byte(s) in T%d\n",
- object->size - size, type);
+ object->size - size, type);
}
for (i = 0; i < size; i++) {
ret = sscanf(cfg->data + data_pos, "%hhx%n",
- &val,
- &offset);
+ &val,
+ &offset);
if (ret != 1) {
dev_err(dev, "Bad format\n");
ret = -EINVAL;
@@ -1939,18 +2236,8 @@ static int mxt_download_config(struct mxt_data *data, const char *fn)
byte_offset = reg + i - config_start_offset;
- /* Special case for T38:
- * Since T38 is used to store userdata, when we update the
- * config, the userdata shall not be updated. */
- if (get_hw_version_major() <= 4) {
- /* T38 is stored as config info in X5,
- * no need to protect this register */
- if (type == MXT_SPT_USERDATA_T38 && i < MXT_USERDATA_SIZE)
- val = data->userdata_info[i];
- }
-
if ((byte_offset >= 0)
- && (byte_offset <= config_mem_size)) {
+ && (byte_offset <= config_mem_size)) {
*(config_mem + byte_offset) = val;
} else {
dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
@@ -1961,6 +2248,7 @@ static int mxt_download_config(struct mxt_data *data, const char *fn)
data_pos += offset;
}
+
}
/* calculate crc of the received configs (not the raw config file) */
@@ -2000,8 +2288,6 @@ release:
return ret;
}
-static int mxt_chip_reset(struct mxt_data *data);
-
static int mxt_set_power_cfg(struct mxt_data *data, u8 mode)
{
struct device *dev = &data->client->dev;
@@ -2021,16 +2307,14 @@ static int mxt_set_power_cfg(struct mxt_data *data, u8 mode)
if (mxt_get_object(data, mxt_save[i].suspend_obj) == NULL)
continue;
if (mxt_save[i].suspend_flags == MXT_SUSPEND_DYNAMIC)
+ error |= mxt_read_object(data,
+ mxt_save[i].suspend_obj,
+ mxt_save[i].suspend_reg,
+ &mxt_save[i].restore_val);
error |= mxt_write_object(data,
mxt_save[i].suspend_obj,
mxt_save[i].suspend_reg,
mxt_save[i].suspend_val);
- if (error) {
- error = mxt_chip_reset(data);
- if (error)
- dev_err(dev, "Failed to do chip reset!\n");
- break;
- }
}
break;
@@ -2045,12 +2329,6 @@ static int mxt_set_power_cfg(struct mxt_data *data, u8 mode)
mxt_save[cnt].suspend_obj,
mxt_save[cnt].suspend_reg,
mxt_save[cnt].restore_val);
- if (error) {
- error = mxt_chip_reset(data);
- if (error)
- dev_err(dev, "Failed to do chip reset!\n");
- break;
- }
}
break;
}
@@ -2156,22 +2434,15 @@ static int mxt_read_internal_gpio(struct mxt_data *data)
u8 val;
ret = mxt_write_object(data, MXT_SPT_GPIOPWM_T19,
- MXT_GPIOPWM_INTPULLUP, 0xFF);
- if (ret) {
- dev_err(dev, "Failed to enable internal pull-up resistor!\n");
- return ret;
- }
-
- ret = mxt_write_object(data, MXT_SPT_GPIOPWM_T19,
- MXT_GPIOPWM_CTRL, MXT_GPIO_FORCERPT);
+ MXT_GPIOPWM_CTRL, MXT_GPIO_FORCERPT);
if (ret) {
dev_err(dev, "Failed to write force report to GPIO !\n");
return ret;
}
- while (i < timeout) {
+ while(i < timeout) {
ret = mxt_read_object(data, MXT_SPT_GPIOPWM_T19,
- MXT_GPIOPWM_CTRL, &val);
+ MXT_GPIOPWM_CTRL, &val);
if (ret) {
dev_err(dev, "Failed to read GPIO ctrl status !\n");
return ret;
@@ -2181,7 +2452,7 @@ static int mxt_read_internal_gpio(struct mxt_data *data)
is_timeout = false;
break;
}
- i++;
+ i ++;
msleep(1);
}
@@ -2192,20 +2463,6 @@ static int mxt_read_internal_gpio(struct mxt_data *data)
mxt_read_t9_messages_until_invalid(data);
- ret = mxt_write_object(data, MXT_SPT_GPIOPWM_T19,
- MXT_GPIOPWM_INTPULLUP, 0);
- if (ret) {
- dev_err(dev, "Failed to disable internal pull-up resistor!\n");
- return ret;
- }
-
- ret = mxt_write_object(data, MXT_SPT_GPIOPWM_T19,
- MXT_GPIOPWM_CTRL, MXT_GPIO_DISABLEOUTPUT);
- if (ret) {
- dev_err(dev, "Failed to disable reading GPIO status!\n");
- return ret;
- }
-
return 0;
}
@@ -2213,36 +2470,27 @@ static const char * mxt_get_config(struct mxt_data *data, bool is_default)
{
const struct mxt_platform_data *pdata = data->pdata;
int i;
-
- if (pdata->default_config == -1) {
- /* no default config is set */
- is_default = false;
- }
+ int lcd_id = 1;
for (i = 0; i < pdata->config_array_size; i++) {
if (data->info.family_id== pdata->config_array[i].family_id &&
data->info.variant_id == pdata->config_array[i].variant_id &&
data->info.version == pdata->config_array[i].version &&
- data->info.build == pdata->config_array[i].build &&
- data->rev_id == pdata->config_array[i].rev_id &&
- data->vendor_id == pdata->config_array[i].vendor_id) {
- break;
+ data->info.build == pdata->config_array[i].build) {
+ if (!is_default) {
+ if (data->vendor_id == pdata->config_array[i].vendor_id &&
+ lcd_id == pdata->config_array[i].lcd_id) {
+ data->current_index = i;
+ return pdata->config_array[i].mxt_cfg_name;
+ }
+ } else {
+ data->current_index = i;
+ return pdata->config_array[i].mxt_cfg_name;
+ }
}
}
- if (i >= pdata->config_array_size) {
- /* No matching config */
- if (!is_default)
- return NULL;
- else
- i = pdata->default_config;
- }
-
- dev_info(&data->client->dev, "Choose config %d: %s, is_default = %d\n",
- i, pdata->config_array[i].mxt_cfg_name, is_default);
-
- data->current_index = i;
- return pdata->config_array[i].mxt_cfg_name;
+ return NULL;
}
static int mxt_backup_nv(struct mxt_data *data)
@@ -2283,180 +2531,24 @@ static int mxt_backup_nv(struct mxt_data *data)
return 0;
}
-static int mxt_read_rev(struct mxt_data *data)
-{
- struct device *dev = &data->client->dev;
- int ret;
- int i = 0;
- u8 val;
-
- ret = mxt_write_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_DIAGNOSTIC, 0x80);
- if (ret) {
- dev_err(dev, "Failed to send rev read command!\n");
- return ret;
- }
-
- while (i < 100) {
- ret = mxt_read_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_DIAGNOSTIC, &val);
- if (ret) {
- dev_err(dev, "Failed to read diagnostic!\n");
- return ret;
- }
-
- if (val == 0)
- break;
- i++;
- msleep(10);
- }
-
- ret = mxt_read_object(data, MXT_DEBUG_DIAGNOSTIC_T37,
- MXT_DIAG_REV_ID, &data->rev_id);
- if (ret) {
- pr_err("Failed to read rev id!\n");
- return ret;
- }
-
- pr_info("read rev_id = 0x%x\n", data->rev_id);
-
- return 0;
-}
-
-static int mxt_read_userdata_info(struct mxt_data *data)
-{
- int ret = 0;
- struct mxt_object *object;
- u16 reg;
-
- object = mxt_get_object(data, MXT_SPT_USERDATA_T38);
- if (!object)
- return -EINVAL;
-
- reg = object->start_address;
- ret = mxt_read_reg(data->client, reg,
- MXT_USERDATA_SIZE, data->userdata_info);
- if (ret)
- dev_err(&data->client->dev, "Failed to read T38\n");
-
- return ret;
-}
-
-static int mxt_read_lockdown_info(struct mxt_data *data)
-{
- struct device *dev = &data->client->dev;
- struct mxt_object *object;
- int ret, i = 0;
- u8 val;
- u16 reg;
-
- ret = mxt_write_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_DIAGNOSTIC, 0x81);
- if (ret) {
- dev_err(dev, "Failed to send lockdown info read command!\n");
- return ret;
- }
-
- while (i < 100) {
- ret = mxt_read_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_DIAGNOSTIC, &val);
- if (ret) {
- dev_err(dev, "Failed to read diagnostic!\n");
- return ret;
- }
-
- if (val == 0)
- break;
-
- i++;
- msleep(10);
- }
-
- object = mxt_get_object(data, MXT_DEBUG_DIAGNOSTIC_T37);
- if (!object)
- return -EINVAL;
-
- reg = object->start_address;
- ret = mxt_read_reg(data->client, reg + MXT_LOCKDOWN_OFFSET,
- MXT_LOCKDOWN_SIZE, data->lockdown_info);
- if (ret)
- dev_err(dev, "Failed to read lockdown info!\n");
-
- return 0;
-}
-
static int mxt_check_reg_init(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
int ret;
const char* config_name = NULL;
- bool is_recheck = false, use_default_cfg = false;
-
- if (data->firmware_updated)
- use_default_cfg = true;
+ bool is_recheck = false;
start:
- ret = mxt_read_rev(data);
- if (ret) {
- dev_err(dev, "Can not get rev!\n");
- is_recheck = true;
- } else {
- is_recheck = false;
- }
-
ret = mxt_read_internal_gpio(data);
if (ret) {
- dev_err(dev, "Can not get internal gpio status!\n");
+ dev_err(dev, "Can not get internal gpio status, just give default one!\n");
+ config_name = mxt_get_config(data, true);
is_recheck = true;
} else {
+ config_name = mxt_get_config(data, false);
is_recheck = false;
}
- if (get_hw_version_major() >= 5) {
- /*
- * Firmware 1.5.AA supports lockdown info, which is only
- * used for X5
- */
- ret = mxt_read_lockdown_info(data);
- if (ret) {
- dev_err(dev, "Cannot get lockdown info, set lockdown info to 0xFF!\n");
- memset(data->lockdown_info, 0xFF, MXT_LOCKDOWN_SIZE);
- }
-
- dev_info(dev, "Got lockdown info: %02X %02X %02X %02X %02X %02X %02X %02X\n",
- data->lockdown_info[0], data->lockdown_info[1],
- data->lockdown_info[2], data->lockdown_info[3],
- data->lockdown_info[4], data->lockdown_info[5],
- data->lockdown_info[6], data->lockdown_info[7]);
-
- /* In X5, we use lockdown info for storing TP vendor info */
- data->vendor_id = data->lockdown_info[0];
-
- /* Lockdown info is not flashed into some old TP panels,
- * set the default vendor id to 0x38 */
- if (data->vendor_id == 0) {
- dev_err(dev, "TP maker info is empty, use the default one!\n");
- data->vendor_id = 0x38; /* Default vendor is sharp */
- }
- }
-
- config_name = mxt_get_config(data, use_default_cfg);
-
- /* If we need to recheck, we shall not get a default config */
- if (use_default_cfg)
- use_default_cfg = false;
-
- ret = mxt_read_userdata_info(data);
- if (ret) {
- dev_err(dev, "Can not get userdata info(T38)!\n");
- } else {
- dev_info(dev, "Got userdata info: %02X %02X %02X %02X %02X %02X %02X %02X",
- data->userdata_info[0], data->userdata_info[1],
- data->userdata_info[2], data->userdata_info[3],
- data->userdata_info[4], data->userdata_info[5],
- data->userdata_info[6], data->userdata_info[7]);
- }
-
if (config_name == NULL) {
dev_info(dev, "Not found matched config!\n");
return -ENOENT;
@@ -2513,7 +2605,6 @@ static int mxt_get_object_table(struct mxt_data *data)
u16 end_address;
u8 reportid = 0;
u8 buf[data->info.object_num][MXT_OBJECT_SIZE];
- int add_num = 0;
data->mem_size = 0;
data->object_table = kcalloc(data->info.object_num,
@@ -2531,10 +2622,6 @@ static int mxt_get_object_table(struct mxt_data *data)
struct mxt_object *object = data->object_table + i;
object->type = buf[i][0];
- if (object->type == 35) {
- object->type = 150 + add_num;
- add_num ++;
- }
object->start_address = (buf[i][2] << 8) | buf[i][1];
object->size = buf[i][3] + 1;
object->instances = buf[i][4] + 1;
@@ -2611,21 +2698,13 @@ static int mxt_get_object_table(struct mxt_data *data)
case MXT_SPT_GOLDENREF_T66:
data->T66_reportid = object->max_reportid;
break;
- case MXT_TOUCH_MORE_GESTURE_T81:
- data->T81_reportid_min = object->min_reportid;
- data->T81_reportid_max = object->max_reportid;
- break;
- case MXT_TOUCH_GESTURE_T92:
- data->T92_reportid_min = object->min_reportid;
- data->T92_reportid_max = object->max_reportid;
- break;
case MXT_TOUCH_MULTI_T100:
data->T100_reportid_max = object->max_reportid;
data->T100_reportid_min = object->min_reportid;
data->num_touchids = object->num_report_ids * object->instances;
break;
- case MXT_SPT_SELFCAPGLOBALCONFIG_T109:
- data->T109_reportid = object->max_reportid;
+ case MXT_SPT_SELFCAPHOVERCTECONFIG_T102:
+ data->T102_reportid = object->max_reportid;
break;
}
@@ -2791,15 +2870,7 @@ static void mxt_initialize_regulator(struct mxt_data *data)
dev_info(&client->dev,
"Atmel regulator_get for avdd failed: %ld\n",
PTR_ERR(data->regulator_avdd));
- goto err_put_regulator_vdd;
- }
-
- data->regulator_vddio = devm_regulator_get(&client->dev, "vddio");
- if (IS_ERR(data->regulator_vddio)) {
- dev_info(&client->dev,
- "Atmel regulator_get for avdd failed: %ld\n",
- PTR_ERR(data->regulator_vddio));
- goto err_put_regulator_avdd;
+ goto err_put_regulator;
}
dev_info(&client->dev,
@@ -2814,19 +2885,11 @@ static void mxt_initialize_regulator(struct mxt_data *data)
if (ret < 0)
dev_err(&client->dev,
"Atmel regulator_enable for avdd failed; Error code:%d\n", ret);
-
- ret = regulator_enable(data->regulator_vddio);
- if (ret < 0)
- dev_err(&client->dev,
- "Atmel regulator_enable for avdd failed; Error code:%d\n", ret);
return;
-err_put_regulator_avdd:
- devm_regulator_put(data->regulator_avdd);
-err_put_regulator_vdd:
+err_put_regulator:
devm_regulator_put(data->regulator_vdd);
err_null_regulator:
- data->regulator_vddio = NULL;
data->regulator_avdd = NULL;
data->regulator_vdd = NULL;
}
@@ -2835,14 +2898,45 @@ static ssize_t mxt_update_fw_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
+static int mxt_update_self_chgtime(struct mxt_data *data, bool inc)
+{
+ int error;
+ u8 val;
+ struct device *dev = &data->client->dev;
+ const struct mxt_platform_data *pdata = data->pdata;
+ int index = data->current_index;
+
+ error = mxt_read_object(data, MXT_SPT_SELFCAPHOVERCTECONFIG_T102,
+ MXT_SELF_CHGTIME, &val);
+ if (error) {
+ dev_err(dev, "Failed to get self charge time!\n");
+ return error;
+ }
+
+ if (inc) {
+ val += 5;
+ if (val > pdata->config_array[index].self_chgtime_max)
+ return -ERANGE;
+ }
+ else {
+ val -= 5;
+ if (val < pdata->config_array[index].self_chgtime_min)
+ return -ERANGE;
+ }
+
+ error = mxt_write_object(data, MXT_SPT_SELFCAPHOVERCTECONFIG_T102,
+ MXT_SELF_CHGTIME, val);
+
+ return error;
+}
-static int mxt_wait_for_self_tune_msg(struct mxt_data *data, u8 expect_val)
+static int mxt_wait_for_self_tune_msg(struct mxt_data *data)
{
int time_out = 1000;
int i = 0;
while(i < time_out) {
- if (data->selfcap_status.cmd == expect_val)
+ if (data->selfcap_status.cause == 0x3)
return 0;
i++;
msleep(10);
@@ -2851,37 +2945,50 @@ static int mxt_wait_for_self_tune_msg(struct mxt_data *data, u8 expect_val)
return -ETIMEDOUT;
}
-static int mxt_do_self_tune(struct mxt_data *data, u8 cmd)
+static int mxt_do_self_tune(struct mxt_data *data, u8 cmd, bool nv_backup)
{
int error;
struct device *dev = &data->client->dev;
memset(&data->selfcap_status, 0x0, sizeof(data->selfcap_status));
- if (mxt_get_object(data, MXT_SPT_SELFCAPGLOBALCONFIG_T109) == NULL) {
- dev_err(dev, "No T109 exist!\n");
+ if (mxt_get_object(data, MXT_SPT_SELFCAPHOVERCTECONFIG_T102) == NULL) {
+ dev_err(dev, "Not T102 exist!\n");
return 0;
}
- error = mxt_write_object(data, MXT_SPT_SELFCAPGLOBALCONFIG_T109,
- MXT_SELFCAPCFG_CTRL, MXT_SELFCTL_RPTEN);
- if (error) {
- dev_err(dev, "Error when enable t109 report en!\n");
- return error;
- }
-
- error = mxt_write_object(data, MXT_SPT_SELFCAPGLOBALCONFIG_T109,
- MXT_SELFCAPCFG_CMD, cmd);
+ error = mxt_write_object(data, MXT_SPT_SELFCAPHOVERCTECONFIG_T102,
+ MXT_SELFCAP_CMD, cmd);
if (error) {
dev_err(dev, "Error when execute cmd 0x%x!\n", cmd);
return error;
}
- error = mxt_wait_for_self_tune_msg(data, cmd);
+ error = mxt_wait_for_self_tune_msg(data);
if(!error) {
- if (data->selfcap_status.error_code != 0)
+ if (data->selfcap_status.error_code & 0x02) {
+ error = mxt_update_self_chgtime(data, true);
+ if (error)
+ return error;
+ return -EINVAL;
+ } else if (data->selfcap_status.error_code & 0x01) {
+ error = mxt_update_self_chgtime(data, false);
+ if (error)
+ return error;
return -EINVAL;
+ } else
+ dev_info(dev, "Tuning pass!\n");
+ } else
+ return -EINVAL;
+
+ if (nv_backup) {
+ error = mxt_write_object(data, MXT_SPT_SELFCAPHOVERCTECONFIG_T102,
+ MXT_SELFCAP_CMD, MXT_SELFCMD_STORE);
+ if (error) {
+ dev_err(dev, "Error when execute cmd store!\n");
+ return error;
+ }
}
return 0;
@@ -2909,10 +3016,9 @@ static int mxt_get_init_setting(struct mxt_data *data)
u8 intthr;
u8 glovectrl;
u8 atchthr;
+ u8 anti_calib[4];
int i;
struct device *dev = &data->client->dev;
- const struct mxt_platform_data *pdata = data->pdata;
- int index = data->current_index;
if (mxt_get_object(data, MXT_SPT_AUXTOUCHCONFIG_T104) != NULL) {
error = mxt_read_object(data, MXT_SPT_AUXTOUCHCONFIG_T104,
@@ -2921,6 +3027,7 @@ static int mxt_get_init_setting(struct mxt_data *data)
dev_err(dev, "Failed to read self threshold from t104!\n");
return error;
}
+ data->selfthr_save = selfthr;
error = mxt_read_object(data, MXT_SPT_AUXTOUCHCONFIG_T104,
MXT_AUXTCHCFG_INTTHRX, &intthr);
@@ -2928,6 +3035,7 @@ static int mxt_get_init_setting(struct mxt_data *data)
dev_err(dev, "Failed to read internal threshold from t104!\n");
return error;
}
+ data->intthr_save= intthr;
}
if (mxt_get_object(data, MXT_PROCI_GLOVEDETECTION_T78) != NULL) {
@@ -2951,25 +3059,24 @@ static int mxt_get_init_setting(struct mxt_data *data)
data->atchthr = atchthr;
}
- for (i = 0; i < ARRAY_SIZE(mxt_save); i++) {
- error = mxt_read_object(data, MXT_GEN_POWER_T7,
- i, &mxt_save[i].restore_val);
+ if (mxt_get_object(data, MXT_SPT_SELFCAPHOVERCTECONFIG_T102) != NULL) {
+ error = mxt_read_object(data, MXT_SPT_SELFCAPHOVERCTECONFIG_T102,
+ MXT_SELF_RECALCFG, &data->self_recalib_para);
if (error) {
- dev_err(dev, "Failed to read T7 byte %d\n", i);
+ dev_err(dev, "Faield to read from t102 self recalib para!\n");
return error;
}
}
- if (mxt_get_object(data, MXT_PROCG_NOISESUPSELFCAP_T108) != NULL) {
- for (i = 0; i < ARRAY_SIZE(data->adcperx_normal); i++) {
- data->adcperx_wakeup[i] = pdata->config_array[index].wake_up_self_adcx;
- error = mxt_read_object(data, MXT_PROCG_NOISESUPSELFCAP_T108,
- 19 + i, &data->adcperx_normal[i]);
- if (error) {
- dev_err(dev, "Failed to read T108 setting %d\n", i);
- return error;
- }
+ /* always have T8 */
+ for (i = 0; i < sizeof(anti_calib); i++) {
+ error = mxt_read_object(data, MXT_GEN_ACQUIRE_T8,
+ MXT_ACQUIRE_ATCHCALST+i, &anti_calib[i]);
+ if (error) {
+ dev_err(dev, "Failed to read from t8!\n");
+ return error;
}
+ data->anti_calib[i] = anti_calib[i];
}
error = mxt_read_resolution(data);
@@ -3004,10 +3111,9 @@ retry_probe:
data->state = BOOTLOADER;
/* this is not an error state, we can reflash
* from here */
- error = mxt_update_firmware(&client->dev, NULL,
+ error = mxt_update_fw_store(&client->dev, NULL,
data->pdata->mxt_fw_name,
- strlen(data->pdata->mxt_fw_name),
- &data->firmware_updated);
+ strlen(data->pdata->mxt_fw_name));
if (error != strlen(data->pdata->mxt_fw_name))
{
dev_err(&client->dev, "Error when update firmware!\n");
@@ -3273,18 +3379,28 @@ release_firmware:
return ret;
}
-static ssize_t mxt_update_firmware(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count, bool *upgraded)
+static ssize_t mxt_update_fw_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+
+ ssize_t count = sprintf(buf,
+ "family_id=0x%02x, variant_id=0x%02x, version=0x%02x, build=0x%02x, vendor=0x%02x\n",
+ data->info.family_id, data->info.variant_id,
+ data->info.version, data->info.build,
+ data->vendor_id);
+ return count;
+}
+
+static ssize_t mxt_update_fw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct mxt_data *data = dev_get_drvdata(dev);
int error;
char *fw_name;
int len = 0;
- if (upgraded)
- *upgraded = false;
-
if (count <= 0)
return -EINVAL;
@@ -3301,8 +3417,12 @@ static ssize_t mxt_update_firmware(struct device *dev,
fw_name[len] = 0;
}
- dev_info(dev, "Identify firmware name :%s\n", fw_name);
- mxt_disable_irq(data);
+ dev_info(dev, "Identify firmware name :%s \n", fw_name);
+
+ if(likely(data->irq_enabled)) {
+ disable_irq(data->irq);
+ data->irq_enabled=false;
+ }
error = mxt_load_fw(dev, fw_name);
if (error) {
@@ -3319,70 +3439,22 @@ static ssize_t mxt_update_firmware(struct device *dev,
kfree(data->msg_buf);
data->msg_buf = NULL;
- if (upgraded)
- *upgraded = true;
-
mxt_initialize(data);
}
if (data->state == APPMODE) {
- mxt_enable_irq(data);
- }
-
- kfree(fw_name);
- return count;
-}
-static ssize_t mxt_update_fw_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
-
- ssize_t count = sprintf(buf,
- "family_id=0x%02x, variant_id=0x%02x, version=0x%02x, build=0x%02x, vendor=0x%02x\n",
- data->info.family_id, data->info.variant_id,
- data->info.version, data->info.build,
- data->vendor_id);
- return count;
-}
-
-static ssize_t mxt_update_fw_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return mxt_update_firmware(dev, attr, buf, count, NULL);
-}
-
-static ssize_t mxt_keys_off_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
- int count;
- char c;
+ if (likely(!data->irq_enabled)) {
+ enable_irq(data->irq);
+ data->irq_enabled=true;
+ }
- c = data->keys_off ? '1' : '0';
- count = sprintf(buf, "%c\n", c);
+ }
+ kfree(fw_name);
return count;
}
-static ssize_t mxt_keys_off_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
- int i;
-
- if (sscanf(buf, "%u", &i) == 1 && i < 2) {
- data->keys_off = (i == 1);
-
- dev_dbg(dev, "%s\n", i ? "hw keys off" : "hw keys on");
- return count;
- } else {
- dev_dbg(dev, "keys_off write error\n");
- return -EINVAL;
- }
-}
-
static ssize_t mxt_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -3436,40 +3508,70 @@ static ssize_t mxt_pause_store(struct device *dev,
}
}
-static ssize_t mxt_debug_enable_show(struct device *dev,
+static ssize_t mxt_keys_off_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mxt_data *data = dev_get_drvdata(dev);
int count;
char c;
- c = data->debug_enabled ? '1' : '0';
+ c = data->keys_off ? '1' : '0';
count = sprintf(buf, "%c\n", c);
return count;
}
-static ssize_t mxt_debug_enable_store(struct device *dev,
+static ssize_t mxt_keys_off_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mxt_data *data = dev_get_drvdata(dev);
int i;
if (sscanf(buf, "%u", &i) == 1 && i < 2) {
- data->debug_enabled = (i == 1);
+ data->keys_off = (i == 1);
- dev_dbg(dev, "%s\n", i ? "debug enabled" : "debug disabled");
+ dev_dbg(dev, "%s\n", i ? "hw keys off" : "hw keys on");
return count;
} else {
- dev_dbg(dev, "debug_enabled write error\n");
+ dev_dbg(dev, "keys_off write error\n");
return -EINVAL;
}
}
-static int mxt_check_mem_access_params(struct mxt_data *data, loff_t off,
- size_t *count)
+static ssize_t mxt_debug_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- if (data->state != APPMODE) {
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+ char c;
+
+ c = data->debug_enabled ? '1' : '0';
+ count = sprintf(buf, "%c\n", c);
+
+ return count;
+}
+
+static ssize_t mxt_debug_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int i;
+
+ if (sscanf(buf, "%u", &i) == 1 && i < 2) {
+ data->debug_enabled = (i == 1);
+
+ dev_dbg(dev, "%s\n", i ? "debug enabled" : "debug disabled");
+ return count;
+ } else {
+ dev_dbg(dev, "debug_enabled write error\n");
+ return -EINVAL;
+ }
+}
+
+static int mxt_check_mem_access_params(struct mxt_data *data, loff_t off,
+ size_t *count)
+{
+ if (data->state != APPMODE) {
dev_err(&data->client->dev, "Not in APPMODE\n");
return -EINVAL;
}
@@ -3604,178 +3706,531 @@ static ssize_t mxt_slowscan_store(struct device *dev,
return count;
}
-static void mxt_self_tune(struct mxt_data *data, u8 save_cmd)
+static void mxt_self_tune(struct mxt_data *data, u8 nv_backup)
{
struct device *dev = &data->client->dev;
int retry_times = 10;
int i = 0;
int error;
- while(i++ < retry_times) {
- error = mxt_do_self_tune(data, MXT_SELFCMD_TUNE);
- if (error) {
- dev_err(dev, "Self tune cmd failed!\n");
- continue;
- }
- error = mxt_do_self_tune(data, save_cmd);
+ while(i < retry_times) {
+ error = mxt_do_self_tune(data, MXT_SELFCMD_TUNE, (bool)nv_backup);
if (!error)
return;
- else {
- dev_err(dev, "Self store cmd failed!\n");
- continue;
+ else if (error == -ERANGE) {
+ dev_err(dev, "self out of range!\n");
+ return;
}
+ i++;
}
dev_err(dev, "Even retry self tuning for 10 times, still can't pass.!\n");
}
-static bool mxt_self_tune_pass(struct mxt_data *data, bool is_hover_mode)
+static void mxt_enable_golden_ref(struct mxt_data *data, bool enable);
+
+#define MAX_DIFF_MARGIN 50
+static void mxt_pre_use_work(struct work_struct* work)
{
- int error;
+ struct mxt_data *data = container_of(work, struct mxt_data, pre_use_work);
+ const struct mxt_platform_data *pdata = data->pdata;
struct device *dev = &data->client->dev;
- u16 addr = data->T37_address;
- u8 mode = MXT_DIAG_SELF_REF;
- size_t bufsize = MXT_DIAG_SELF_SIZE;
- int read_size = 0;
- int i, j = 0;
- u8 *buf;
- short val;
- int bound[] = {32, 68};
- int start[] = {40, 80};
+ int val;
+ int i = 0;
- buf = kmalloc(MXT_DIAG_TOTAL_SIZE, GFP_KERNEL);
- if (buf == NULL) {
- dev_err(dev, "Failed to alloc buffer for delta getting!\n");
- return false;
+ mxt_self_tune(data, false);
+
+ if (!data->gr_enable && !data->is_ignore_channel_saved) {
+ mxt_enable_golden_ref(data, true);
+ mxt_anti_calib_control(data, false);
+ mxt_self_recalib_control(data, false);
+ msleep(1000);
+ while(mxt_monitor_delta_no_calib_risk(data, DELTA_TYPE_MULT)
+ != MONITOR_NO_RISK) {
+ dev_info(dev, "time %d Risk exists, wait until no touch!\n", i);
+ msleep(100);
+ i ++;
+ if (i == 50)
+ break;
+ }
+
+ mxt_anti_calib_control(data, true);
+ mxt_self_recalib_control(data, true);
+ mxt_enable_golden_ref(data, false);
+ mxt_do_calibration(data);
+ msleep(2000);
+ data->ignore_rx_num = 0;
+ data->ignore_tx_num = 0;
+ val = mxt_monitor_delta_no_calib_risk(data, REF_TYPE_MULT_MAX);
+ dev_info(dev, "Ignore tx num = %d rx num = %d\n",
+ data->ignore_tx_num, data->ignore_rx_num);
+ data->ref_diff_threshold = pdata->ref_diff_threshold;
+
+ if (data->ignore_rx_num >= 3 || data->ignore_tx_num >= 3) {
+ if (val > pdata->ref_diff_threshold ||
+ val <= pdata->ref_diff_threshold / 2)
+ data->ref_diff_threshold = val + MAX_DIFF_MARGIN;
+ data->ignore_rx_num = 0;
+ data->ignore_tx_num = 0;
+ } else
+ data->ref_diff_threshold = val + MAX_DIFF_MARGIN;
+
+ dev_info(dev, "Max diff = %d\n", val);
+ dev_info(dev, "Last ref_diff_threshold = %d\n", (int)data->ref_diff_threshold);
+ data->is_ignore_channel_saved = true;
}
- error = mxt_do_diagnostic(data, mode);
+ data->is_recalib_available = true;
+
+ i = 0;
+ while ((mxt_monitor_delta_no_calib_risk(data, DELTA_TYPE_MULT)
+ != MONITOR_NO_RISK) &&
+ (mxt_monitor_delta_no_calib_risk(data, DELTA_TYPE_SELF)
+ != MONITOR_NO_RISK)) {
+ msleep(100);
+ i ++;
+ if (i == 50)
+ break;
+ }
+
+ mxt_do_calibration(data);
+}
+
+static ssize_t mxt_self_tune_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ u8 nv_backup;
+ struct mxt_data *data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%hhu", &nv_backup) == 1)
+ mxt_self_tune(data, nv_backup);
+ else
+ return -EINVAL;
+
+ return count;
+}
+
+static int mxt_execute_golden_command(struct mxt_data *data, u8 cmd)
+{
+ struct device *dev = &data->client->dev;
+ int error;
+ u8 ori_val = MXT_GOLDCTRL_ENABLE | MXT_GOLDCTRL_REPEN;
+
+ ori_val &= ~MXT_GOLD_CMD_MASK;
+ ori_val |= cmd;
+ error = mxt_write_object(data, MXT_SPT_GOLDENREF_T66,
+ MXT_GOLDENREF_CTRL, ori_val);
+ pr_info("write command = 0x%x\n", ori_val);
if (error) {
- dev_err(dev, "Failed to do diagnostic!\n");
- kfree(buf);
- return false;
+ dev_err(dev, "Write object t66 error, when execute cmd 0x%x\n", cmd);
+ return error;
}
- if (is_hover_mode) {
- error = mxt_do_diagnostic(data, MXT_DIAG_PAGE_UP);
+ return 0;
+}
+
+static int mxt_do_prepare_golden(struct mxt_data *data, bool dualx_on)
+{
+ struct device *dev = &data->client->dev;
+ int error;
+ int i;
+ u8 t8_close [] = {0xFF, 0x01, 0x00, 0x00};
+
+ /* first close T8 anti-calib */
+ for (i = 0; i < sizeof(t8_close); i++) {
+ error = mxt_write_object(data, MXT_GEN_ACQUIRE_T8,
+ MXT_ACQUIRE_ATCHCALST+i, t8_close[i]);
if (error) {
- dev_err(dev, "do diagnostic 0x%02x failed\n", MXT_DIAG_PAGE_UP);
- kfree(buf);
- return false;
+ dev_err(dev, "Failed to close anti-calib\n");
+ return error;
}
}
- while (read_size < bufsize) {
- error = mxt_read_reg(data->client, addr + 2,
- MXT_DIAG_PAGE_SIZE, buf + read_size);
+ /* Must enable both self sensing and mutual sensing*/
+ error = mxt_write_object(data, MXT_GEN_ACQUIRE_T8,
+ MXT_ACQUIRE_MEASALLOW,
+ MXT_MEASALLOW_MULT | MXT_MEASALLOW_SELT);
+ if (error) {
+ dev_err(dev, "Failed to close self-sensing!\n");
+ return error;
+ }
+
+ /* close the t66 en*/
+ error = mxt_write_object(data, MXT_SPT_GOLDENREF_T66,
+ MXT_GOLDENREF_CTRL, 0);
+ if (error) {
+ dev_err(dev, "failed to disable t66!\n");
+ return error;
+ }
+
+ if (dualx_on) {
+ error = mxt_write_object(data, MXT_PROCG_NOISESUPPRESSION_T72,
+ MXT_NOISESUP_CALCFG, MXT_NOICFG_VNOISY);
if (error) {
- dev_err(dev, "Read from T37 failed!\n");
- kfree(buf);
- return false;
+ dev_err(dev, "failed to enter very noisy mode!\n");
+ return error;
}
+ }
- read_size += MXT_DIAG_PAGE_SIZE;
+ /* calib after t66 disabled, make sure the surface is flat */
+ mxt_do_calibration(data);
- error = mxt_do_diagnostic(data, MXT_DIAG_PAGE_UP);
+ return 0;
+}
+
+static int mxt_check_golden_status(struct mxt_data *data, bool dualx_on)
+{
+ struct device *dev = &data->client->dev;
+ int error;
+ int i = 0;
+ int time_out = 1000;
+
+ if (dualx_on) {
+ error = mxt_write_object(data, MXT_PROCG_NOISESUPPRESSION_T72,
+ MXT_NOISESUP_CALCFG, MXT_NOICFG_VNOISY);
if (error) {
- dev_err(dev, "do diagnostic 0x%02x failed!\n", MXT_DIAG_PAGE_UP);
- kfree(buf);
- return false;
+ dev_err(dev, "failed to enter very noisy mode!\n");
+ return error;
}
}
- for (i = 0; i < bufsize; i += 2) {
- if (i == bound[j]) {
- i = start[j];
- j++;
- }
- val = (buf[i+1] << 8) | buf[i];
- pr_info("tune val [%d] = %d\n", i, val);
- if (val > 17384 || val < 15384) {
- kfree(buf);
- return false;
- }
+
+ error = mxt_write_object(data, MXT_SPT_GOLDENREF_T66,
+ MXT_GOLDENREF_CTRL, MXT_GOLDCTRL_ENABLE | MXT_GOLDCTRL_REPEN);
+ if (error) {
+ dev_err(dev, "failed to enable t66\n");
+ return error;
}
- kfree(buf);
- return true;
+ error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_REPORTALL, 1);
+ if (error) {
+ dev_err(dev, "failed to report all msg!\n");
+ return error;
+ }
+
+ data->golden_msg.status = MXT_GOLDSTATE_INVALID;
+ while (1) {
+ if (data->golden_msg.status == MXT_GOLDSTATE_INVALID) {
+ if(i++ >= time_out) {
+ error = -ETIMEDOUT;
+ return error;
+ }
+ msleep(10);
+ continue;
+ } else
+ break;
+ data->golden_msg.status = MXT_GOLDSTATE_INVALID;
+ }
+
+ if (data->golden_msg.status & MXT_GOLDSTS_BADSTOREDATA)
+ return -EINVAL;
+
+ return 0;
}
-static void mxt_hover_loading_work(struct work_struct* work)
+static int mxt_do_curr_golden_ref_tune(struct mxt_data *data)
{
- struct mxt_data *data = container_of(work, struct mxt_data, hover_loading_work);
+ struct device *dev = &data->client->dev;
+ bool is_sequence_done = false;
+ int k, j;
+ u8 status;
+ int time_out = 200;
int error;
- if (data->rev_id == REV_D) {
- error = mxt_do_self_tune(data, MXT_SELFCMD_AFN_TUNE);
- if (error)
- dev_err(&data->client->dev,
- "Failed to load hover ref from flash!\n");
+ data->golden_msg.status = MXT_GOLDSTATE_INVALID;
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_PRIME | MXT_GOLD_USECURR);
+ if (error) {
+ dev_err(dev, "execute command prime failed\n");
+ return error;
}
+
+ k = 0;
+ j = 0;
+ while (!is_sequence_done) {
+ mutex_lock(&data->golden_mutex);
+ if (data->golden_msg.status == MXT_GOLDSTATE_INVALID) {
+ if(k++ >= time_out) {
+ error = -ETIMEDOUT;
+ mutex_unlock(&data->golden_mutex);
+ return error;
+ }
+ mutex_unlock(&data->golden_mutex);
+ msleep(10);
+ continue;
+ }
+ k = 0;
+ dev_info(dev, "data->golden_msg.status = 0x%x\n", data->golden_msg.status);
+ status = data->golden_msg.status & MXT_GOLD_STATE_MASK;
+ if (status == MXT_GOLDSTATE_PRIME) {
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_GENERATE | MXT_GOLD_USECURR);
+ if (error) {
+ dev_err(dev, "execute command generate failed\n");
+ mutex_unlock(&data->golden_mutex);
+ return error;
+ }
+ } else if (data->golden_msg.status == MXT_GOLDSTATE_IDLE) {
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_NONE | MXT_GOLD_USECURR);
+ if (error) {
+ dev_err(dev, "execute command none failed\n");
+ mutex_unlock(&data->golden_mutex);
+ return error;
+ }
+ is_sequence_done = true;
+ } else {
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_PRIME | MXT_GOLD_USECURR);
+ if (error) {
+ dev_err(dev, "execute command prime failed\n");
+ mutex_unlock(&data->golden_mutex);
+ return error;
+ }
+ }
+ data->golden_msg.status = MXT_GOLDSTATE_INVALID;
+ mutex_unlock(&data->golden_mutex);
+ }
+
+ return 0;
}
-static void mxt_self_tuning_work(struct work_struct* work)
+static int mxt_do_golden_ref_tune(struct mxt_data *data, bool dualx_on)
{
- struct mxt_data *data = container_of(work, struct mxt_data, self_tuning_work);
+ struct device *dev = &data->client->dev;
+ bool is_sequence_done = false;
+ int error;
+ int j, k;
+ u8 status;
+ int retry_times = 5;
+ int time_out = 1000;
- if (data->rev_id == REV_D) {
- do {
- mxt_self_tune(data, MXT_SELFCMD_STCR_TUNE);
- if (mxt_self_tune_pass(data, false))
- break;
- } while (1);
+ error = mxt_do_prepare_golden(data, dualx_on);
+ if (error)
+ return error;
+
+ msleep(100);
+ data->golden_msg.status = MXT_GOLDSTATE_INVALID;
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_PRIME);
+ if (error) {
+ dev_err(dev, "execute command 1 failed\n");
+ return error;
}
+
+ j = 0;
+ k = 0;
+ while (!is_sequence_done) {
+ if (data->golden_msg.status == MXT_GOLDSTATE_INVALID) {
+ if(k++ >= time_out) {
+ error = -ETIMEDOUT;
+ return error;
+ }
+ msleep(10);
+ continue;
+ }
+ k = 0;
+ pr_info("data->golden_msg.status = 0x%x\n", data->golden_msg.status);
+ status = data->golden_msg.status & MXT_GOLD_STATE_MASK;
+
+ if (data->golden_msg.status & MXT_GOLDSTS_FCALSEQERR) {
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_NONE);
+ if (error) {
+ dev_err(dev, "execute command 0 failed\n");
+ return error;
+ }
+ msleep(100);
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_PRIME);
+ if (error) {
+ dev_err(dev, "execute command 1 failed\n");
+ return error;
+ }
+ } else if (data->golden_msg.status == MXT_GOLDSTATE_IDLE) {
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_NONE);
+ if (error) {
+ dev_err(dev, "execute command 0 failed\n");
+ return error;
+ }
+ is_sequence_done = true;
+ } else if (status == MXT_GOLDSTATE_PRIME) {
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_GENERATE);
+ if (error) {
+ dev_err(dev, "execute command 2 failed\n");
+ return error;
+ }
+ } else if (status == MXT_GOLDSTATE_GEN) {
+ if (data->golden_msg.status == MXT_GOLDSTATE_GEN_PASS) {
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_CONFIRM);
+ if (error) {
+ dev_err(dev, "execute command 2 failed\n");
+ return error;
+ }
+ } else if(data->golden_msg.status == MXT_GOLDSTATE_GEN_FAIL) {
+ dev_info(dev, "max_diff = 0x%x, max_diffx = 0x%x, max_diffy = 0x%x\n",
+ data->golden_msg.fcalmaxdiff,
+ data->golden_msg.fcalmaxdiffx,
+ data->golden_msg.fcalmaxdiffy);
+ error = mxt_execute_golden_command(data, MXT_GOLDCMD_NONE);
+ if (error) {
+ dev_err(dev, "execute command 0 failed\n");
+ return error;
+ }
+ return -EINVAL;
+ }
+ } else if (j++ == retry_times) {
+ dev_err(dev, "Generate golden reference failed!\n");
+ /* disable the T66 */
+ error = mxt_write_object(data, MXT_SPT_GOLDENREF_T66,
+ MXT_GOLDENREF_CTRL, 0x0);
+ if (error)
+ dev_err(dev, "Disable T66 failed!\n");
+
+ return -ETIMEDOUT;
+ }
+ data->golden_msg.status = MXT_GOLDSTATE_INVALID;
+ }
+
+ error = mxt_soft_reset(data, MXT_RESET_VALUE);
+ if (error) {
+ dev_err(dev, "Failed when reset!\n");
+ return error;
+ }
+
+ error = mxt_check_golden_status(data, dualx_on);
+ if (error) {
+ dev_err(dev, "Store golden ref is bad!\n");
+ return error;
+ }
+
+ dev_info(dev, "Run golden ref generating successfully!\n");
+ return 0;
}
-static ssize_t mxt_self_tune_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t mxt_golden_ref_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- u8 execute_cmd;
struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
- if (sscanf(buf, "%hhu", &execute_cmd) == 1)
- mxt_self_tune(data, MXT_SELFCMD_STCR_TUNE);
- else
- return -EINVAL;
+ count = sprintf(buf, "%d\n", data->golden_ok);
return count;
}
-static void mxt_do_calibration(struct mxt_data *data)
+#define TOTAL_TEST_NUM 3
+
+static bool mxt_is_golden_ref_good(struct mxt_data *data, bool dualx_on)
{
+ int i;
struct device *dev = &data->client->dev;
- int error, i;
- u8 val;
- int time_out = 100;
- error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_CALIBRATE, 1);
- if (error) {
- dev_err(dev, "failed to do calibration!\n");
- return;
+ if (dualx_on) {
+ int error;
+ error = mxt_write_object(data, MXT_PROCG_NOISESUPPRESSION_T72,
+ MXT_NOISESUP_CALCFG, MXT_NOICFG_VNOISY);
+ if (error) {
+ dev_err(dev, "failed to enter very noisy mode!\n");
+ return false;
+ }
}
- for (i = 0; i < time_out; i++) {
- error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_CALIBRATE, &val);
- if (error) {
- dev_err(dev, "failed to read calibration!\n");
+ msleep(100);
+
+ for (i = 0; i < TOTAL_TEST_NUM; i++) {
+ if (mxt_monitor_delta_no_calib_risk(data, DELTA_TYPE_MULT) !=
+ MONITOR_NO_RISK)
+ return false;
+ msleep(1000);
+ }
+
+ return true;
+}
+
+static void mxt_enable_golden_ref(struct mxt_data *data, bool enable)
+{
+ int error;
+ u8 val;
+ struct device *dev = &data->client->dev;
+
+ if (enable)
+ val = MXT_GOLDCTRL_ENABLE | MXT_GOLDCTRL_REPEN;
+ else
+ val = 0;
+
+ if (mxt_get_object(data, MXT_SPT_GOLDENREF_T66) == NULL) {
+ dev_err(dev, "No such object, ignore!\n");
return;
+ }
+
+ error = mxt_write_object(data, MXT_SPT_GOLDENREF_T66,
+ MXT_GOLDENREF_CTRL, val);
+ if (error)
+ dev_err(dev, "Failed to set golden_ref ctrl!\n");
+}
+
+static ssize_t mxt_golden_ref_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int error;
+ int val;
+
+ data->golden_ok = 0;
+ data->is_recalib_available = false;
+ sscanf(buf, "%u", &val);
+ mutex_lock(&data->input_dev->mutex);
+ if (val == 1) {
+ dev_info(dev, "Call mxt_golden_ref_store\n");
+ if (mxt_get_object(data, MXT_SPT_GOLDENREF_T66) == NULL) {
+ dev_err(dev, "No such object, ignore!\n");
+ mutex_unlock(&data->input_dev->mutex);
+ data->is_recalib_available = true;
+ return 0;
}
- if (val == 0)
- break;
- msleep(10);
+ error = mxt_soft_reset(data, MXT_RESET_VALUE);
+ if (error)
+ goto end;
+ error = mxt_do_golden_ref_tune(data, false);
+ if (error)
+ goto end;
+ if (!mxt_is_golden_ref_good(data, false)) {
+ dev_err(dev, "non-dual-x detect failed!\n");
+ goto end;
+ }
+
+ error = mxt_do_golden_ref_tune(data, true);
+ if (error)
+ goto end;
+ if (mxt_is_golden_ref_good(data, true))
+ data->golden_ok = 1;
+ else
+ dev_err(dev, "dual-x detect failed!\n");
+ } else {
+ mutex_unlock(&data->input_dev->mutex);
+ data->is_recalib_available = true;
+ return -EINVAL;
+ }
+
+end:
+ mutex_unlock(&data->input_dev->mutex);
+ error = mxt_soft_reset(data, MXT_RESET_VALUE);
+ if (error) {
+ data->is_recalib_available = true;
+ return error;
}
+ mxt_do_calibration(data);
+ data->is_recalib_available = true;
+ return count;
}
-static void mxt_calibration_delayed_work(struct work_struct *work)
+static ssize_t mxt_golden_en_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
- struct delayed_work *delayed_work = to_delayed_work(work);
- struct mxt_data *data = container_of(delayed_work, struct mxt_data,
- calibration_delayed_work);
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int val;
- mxt_do_calibration(data);
+ sscanf(buf, "%u", &val);
+ mxt_enable_golden_ref(data, (bool)val);
+ data->gr_enable = (bool)val;
+
+ return count;
}
static ssize_t mxt_update_fw_flag_store(struct device *dev,
@@ -3868,6 +4323,8 @@ static int mxt_stylus_mode_switch(struct mxt_data *data, bool mode_on)
}
}
+ mxt_adjust_self_setting(data, ctrl & MXT_PSTYLUS_ENABLE,
+ TYPE_SELF_INTTHR_STYLUS);
error = mxt_write_object(data, MXT_PROCI_STYLUS_T47,
MXT_PSTYLUS_CTRL, ctrl);
if (error) {
@@ -4034,6 +4491,53 @@ static ssize_t mxt_diagnostic_store(struct device *dev,
return count;
}
+static void mxt_update_noise_mode(struct mxt_data *data)
+{
+ int error;
+ struct device *dev = &data->client->dev;
+ u8 noise_ctrl;
+ const struct mxt_platform_data *pdata = data->pdata;
+ u8 *linearity_reg_pos = pdata->linearity_reg_pos;
+ u8 *linearity_array;
+ int i;
+
+ if (data->sensitive_mode) {
+ error = mxt_read_object(data, MXT_PROCG_NOISESUPPRESSION_T72,
+ MXT_NOISESUP_CFG1, &noise_ctrl);
+ if (error) {
+ dev_err(dev, "Failed in reading from T72!\n");
+ return;
+ }
+
+ if (noise_ctrl != MXT_NOICFG_NOISY) {
+ error = mxt_write_object(data, MXT_PROCG_NOISESUPPRESSION_T72,
+ MXT_NOISESUP_CFG1, MXT_NOICFG_NOISY);
+ if (error) {
+ dev_err(dev, "Failed in writing to T72!\n");
+ return;
+ }
+ }
+ linearity_array = pdata->linearity_dualx;
+ } else {
+ error = mxt_write_object(data, MXT_PROCG_NOISESUPPRESSION_T72,
+ MXT_NOISESUP_CFG1, 0);
+ if (error) {
+ dev_err(dev, "Failed in writing to T72!\n");
+ return;
+ }
+ linearity_array = pdata->linearity_singlex;
+ }
+
+ for (i = 0; i < pdata->linearity_para_num; i++) {
+ error = mxt_write_object(data, MXT_TOUCH_MULTI_T100,
+ linearity_reg_pos[i], linearity_array[i]);
+ if (error) {
+ dev_err(dev, "Failed in writing to T100!\n");
+ return;
+ }
+ }
+}
+
static int mxt_sensitive_mode_switch(struct mxt_data *data, bool mode_on)
{
int error;
@@ -4117,65 +4621,11 @@ static int mxt_sensitive_mode_switch(struct mxt_data *data, bool mode_on)
}
data->sensitive_mode = (u8)mode_on;
+ mxt_update_noise_mode(data);
return error;
}
-static ssize_t mxt_wakeup_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
- int count;
-
- count = sprintf(buf, "%d\n", (int)data->wakeup_gesture_mode);
-
- return count;
-}
-
-static void mxt_enable_gesture_mode(struct mxt_data *data)
-{
- if (!data->hw_wakeup){
- return;
- }
- u8 t81_val;
- int error;
-
- if (data->wakeup_gesture_mode)
- t81_val = 7;
- else
- t81_val = 0;
-
- error = mxt_write_object(data, MXT_TOUCH_MORE_GESTURE_T81,
- MXT_GESTURE_CTRL, t81_val);
- if (error)
- dev_info(&data->client->dev, "write to t81 enabled failed!\n");
-}
-
-static ssize_t mxt_wakeup_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
- const struct mxt_platform_data *pdata = data->pdata;
- int index = data->current_index;
- unsigned long val;
- int error;
-
- if (pdata->config_array[index].wake_up_self_adcx == 0)
- return count;
-
- error = strict_strtoul(buf, 0, &val);
-
- if (!error) {
- data->wakeup_gesture_mode = (u8)val;
- data->hw_wakeup = true;
- }
-
- mxt_enable_gesture_mode(data);
-
- return error ? : count;
-}
-
static ssize_t mxt_sensitive_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -4211,135 +4661,20 @@ static ssize_t mxt_sensitive_mode_store(struct device *dev,
return error ? : count;
}
-
-static void mxt_control_hover(struct mxt_data *data, bool enable)
-{
- int error;
- u8 t8_val, t101_val;
- struct device *dev = &data->client->dev;
-
- if (enable) {
- t8_val = 0x0F;
- t101_val = 0x01;
- } else {
- t8_val = 0x0B;
- t101_val = 0x00;
- }
-
- error = mxt_write_object(data, MXT_GEN_ACQUIRE_T8,
- MXT_ACQUIRE_MEASALLOW, t8_val);
- if (error) {
- dev_err(dev, "Failed to set t8 value!\n");
- return;
- }
-
- error = mxt_write_object(data, MXT_SPT_TOUCHSCREENHOVER_T101,
- MXT_HOVER_CTRL, t101_val);
- if (error)
- dev_err(dev, "Failed to set t101 value!\n");
-}
-
-static ssize_t mxt_hover_tune_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
- int count;
-
- count = sprintf(buf, "%d\n", (int)data->hover_tune_status);
-
- return count;
-}
-
-static ssize_t mxt_hover_tune_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
- unsigned long val;
- int error;
-
- error = strict_strtoul(buf, 0, &val);
- if (!error) {
- if (val == 1 && data->rev_id == REV_D) {
- mxt_control_hover(data, true);
- mxt_self_tune(data, MXT_SELFCMD_STM_TUNE);
- if (mxt_self_tune_pass(data, true))
- data->hover_tune_status = 1;
- else
- data->hover_tune_status = 0;
- mxt_control_hover(data, false);
- }
- }
-
- return error ? : count;
-}
-
-static ssize_t mxt_hover_from_flash_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
- unsigned long val;
- int error;
-
- error = strict_strtoul(buf, 0, &val);
- if (!error && val == 0)
- schedule_work(&data->self_tuning_work);
-
- return error ? : count;
-}
-
-static ssize_t mxt_panel_color_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
- int count;
-
- if (get_hw_version_major() >= 5) {
- /* Panel color only supported in X5.
- * Color info is stored in lockdown info byte2 */
- count = snprintf(buf, PAGE_SIZE, "%c\n",
- data->lockdown_info[2]);
- } else {
- count = snprintf(buf, PAGE_SIZE, "%s\n",
- "Unknown");
- }
-
- return count;
-}
-
static int mxt_chip_reset(struct mxt_data *data)
{
int error;
- mxt_disable_irq(data);
- if (get_hw_version_major() <= 4) {
- /* Keep same behaviour in X4 */
- gpio_set_value(data->pdata->power_gpio, 0);
- msleep(20);
- gpio_set_value(data->pdata->power_gpio, 1);
- } else {
- /* In X5, power is controlled by both LCD an TP, so just toggle the reset pin */
- if (data->pdata->cut_off_power)
- gpio_direction_output(data->pdata->reset_gpio, 1);
-
- gpio_set_value(data->pdata->reset_gpio, 0);
- msleep(20);
- gpio_set_value(data->pdata->reset_gpio, 1);
-
- if (data->pdata->cut_off_power)
- gpio_direction_input(data->pdata->reset_gpio);
- }
+ gpio_set_value(data->pdata->power_gpio, 0);
+ msleep(20);
+ gpio_set_value(data->pdata->power_gpio, 1);
msleep(10);
mxt_wait_for_chg(data);
- mxt_enable_irq(data);
- error = mxt_soft_reset(data, MXT_RESET_VALUE);
- if (error)
- return error;
+ data->is_recalib_available = false;
error = mxt_initialize(data);
- schedule_work(&data->hover_loading_work);
+ queue_work(data->work_queue, &data->pre_use_work);
return error;
}
@@ -4375,16 +4710,16 @@ static void mxt_switch_mode_work(struct work_struct *work)
{
struct mxt_mode_switch *ms = container_of(work, struct mxt_mode_switch, switch_mode_work);
struct mxt_data *data = ms->data;
- const struct mxt_platform_data *pdata = data->pdata;
- int index = data->current_index;
u8 value = ms->mode;
if (value == MXT_INPUT_EVENT_SENSITIVE_MODE_ON ||
- value == MXT_INPUT_EVENT_SENSITIVE_MODE_OFF)
+ value == MXT_INPUT_EVENT_SENSITIVE_MODE_OFF) {
mxt_sensitive_mode_switch(data, (bool)(value - MXT_INPUT_EVENT_SENSITIVE_MODE_OFF));
+ }
else if (value == MXT_INPUT_EVENT_STYLUS_MODE_ON ||
- value == MXT_INPUT_EVENT_STYLUS_MODE_OFF)
+ value == MXT_INPUT_EVENT_STYLUS_MODE_OFF) {
mxt_stylus_mode_switch(data, (bool)(value - MXT_INPUT_EVENT_STYLUS_MODE_OFF));
+ }
if (ms != NULL) {
kfree(ms);
@@ -4462,15 +4797,17 @@ static ssize_t mxt_mem_access_write(struct file *filp, struct kobject *kobj,
static DEVICE_ATTR(update_fw, S_IWUSR | S_IRUSR, mxt_update_fw_show, mxt_update_fw_store);
static DEVICE_ATTR(debug_enable, S_IWUSR | S_IRUSR, mxt_debug_enable_show,
mxt_debug_enable_store);
-static DEVICE_ATTR(keys_off, S_IWUSR | S_IRUSR, mxt_keys_off_show,
- mxt_keys_off_store);
static DEVICE_ATTR(pause_driver, S_IWUSR | S_IRUSR, mxt_pause_show,
mxt_pause_store);
+static DEVICE_ATTR(keys_off, S_IWUSR | S_IRUSR, mxt_keys_off_show,
+ mxt_keys_off_store);
static DEVICE_ATTR(version, S_IRUGO, mxt_version_show, NULL);
static DEVICE_ATTR(build, S_IRUGO, mxt_build_show, NULL);
static DEVICE_ATTR(slowscan_enable, S_IWUSR | S_IRUSR,
mxt_slowscan_show, mxt_slowscan_store);
static DEVICE_ATTR(self_tune, S_IWUSR, NULL, mxt_self_tune_store);
+static DEVICE_ATTR(golden_ref, S_IWUSR | S_IRUSR, mxt_golden_ref_show, mxt_golden_ref_store);
+static DEVICE_ATTR(golden_en, S_IWUSR, NULL, mxt_golden_en_store);
static DEVICE_ATTR(update_fw_flag, S_IWUSR, NULL, mxt_update_fw_flag_store);
static DEVICE_ATTR(selftest, S_IWUSR | S_IRUSR, mxt_selftest_show, mxt_selftest_store);
static DEVICE_ATTR(stylus, S_IWUSR | S_IRUSR, mxt_stylus_show, mxt_stylus_store);
@@ -4478,10 +4815,6 @@ static DEVICE_ATTR(diagnostic, S_IWUSR | S_IRUSR, mxt_diagnostic_show, mxt_diagn
static DEVICE_ATTR(sensitive_mode, S_IWUSR | S_IRUSR, mxt_sensitive_mode_show, mxt_sensitive_mode_store);
static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, mxt_chip_reset_store);
static DEVICE_ATTR(chg_state, S_IRUGO, mxt_chg_state_show, NULL);
-static DEVICE_ATTR(wakeup_mode, S_IWUSR | S_IRUSR, mxt_wakeup_mode_show, mxt_wakeup_mode_store);
-static DEVICE_ATTR(hover_tune, S_IWUSR | S_IRUSR, mxt_hover_tune_show, mxt_hover_tune_store);
-static DEVICE_ATTR(hover_from_flash, S_IWUSR, NULL, mxt_hover_from_flash_store);
-static DEVICE_ATTR(panel_color, S_IRUSR, mxt_panel_color_show, NULL);
static struct attribute *mxt_attrs[] = {
&dev_attr_update_fw.attr,
@@ -4492,6 +4825,8 @@ static struct attribute *mxt_attrs[] = {
&dev_attr_build.attr,
&dev_attr_slowscan_enable.attr,
&dev_attr_self_tune.attr,
+ &dev_attr_golden_ref.attr,
+ &dev_attr_golden_en.attr,
&dev_attr_update_fw_flag.attr,
&dev_attr_selftest.attr,
&dev_attr_stylus.attr,
@@ -4499,10 +4834,6 @@ static struct attribute *mxt_attrs[] = {
&dev_attr_sensitive_mode.attr,
&dev_attr_chip_reset.attr,
&dev_attr_chg_state.attr,
- &dev_attr_wakeup_mode.attr,
- &dev_attr_hover_tune.attr,
- &dev_attr_hover_from_flash.attr,
- &dev_attr_panel_color.attr,
NULL
};
@@ -4510,93 +4841,34 @@ static const struct attribute_group mxt_attr_group = {
.attrs = mxt_attrs,
};
-static void mxt_set_t7_for_gesture(struct mxt_data *data, bool enable)
-{
- if (!data->hw_wakeup) {
- return;
- }
- int error, i;
- u8 t7_gesture_enable[] = {
- 135, 35, 20
- };
- u8 t7_gesture_disable[] = {
- 32, 9, 20
- };
- u8 *t7_val;
-
- if (enable)
- t7_val = t7_gesture_enable;
- else
- t7_val = t7_gesture_disable;
-
- for (i = 0; i < sizeof(t7_gesture_enable); i++) {
- error = mxt_write_object(data, MXT_GEN_POWER_T7,
- i, t7_val[i]);
- if (error) {
- pr_info("write to t7 byte %d failed!\n", i);
- return;
- }
- }
-}
-
-static void mxt_set_gesture_wake_up(struct mxt_data *data, bool enable)
+static bool mxt_read_and_check_calib_msg(struct mxt_data *data)
{
- if (!data->hw_wakeup)
- return;
- int error, i;
+ int ret;
+ int i = 0;
struct device *dev = &data->client->dev;
- u8 *t108_val;
-
- if (enable)
- t108_val = data->adcperx_wakeup;
- else
- t108_val = data->adcperx_normal;
+ bool is_calib_msg_exists = false;
- for (i = 0; i < sizeof(data->adcperx_normal); i++) {
- error = mxt_write_object(data, MXT_PROCG_NOISESUPSELFCAP_T108,
- i + 19, t108_val[i]);
- if (error) {
- dev_err(dev, "write to t108 byte %d failed!\n", i);
- return;
+ while (true) {
+ ret = mxt_read_reg(data->client, data->T5_address,
+ data->T5_msg_size, data->msg_buf);
+ if (ret) {
+ dev_err(dev, "Failed to read %d messages (%d)\n", i, ret);
+ return false;
}
- }
-
- if (enable) {
- error = mxt_set_clr_reg(data, MXT_PROCG_NOISESUPPRESSION_T72,
- MXT_NOISESUP_CTRL, 0, MXT_NOICTRL_ENABLE);
- } else {
- error = mxt_set_clr_reg(data, MXT_PROCG_NOISESUPPRESSION_T72,
- MXT_NOISESUP_CTRL, MXT_NOICTRL_ENABLE, 0);
- }
-
- if (error) {
- dev_err(dev, "write to t72 failed!\n");
- return;
- }
- if (enable) {
- error = mxt_set_clr_reg(data, MXT_TOUCH_MULTI_T100,
- MXT_MULTITOUCH_CTRL, 0, MXT_T100_CTRL_RPTEN);
- } else {
- error = mxt_set_clr_reg(data, MXT_TOUCH_MULTI_T100,
- MXT_MULTITOUCH_CTRL, MXT_T100_CTRL_RPTEN, 0);
- }
+ if (data->msg_buf[0] == MXT_RPTID_NOMSG)
+ break;
- if (error) {
- dev_err(dev, "write to t100 failed!\n");
- return;
+ print_hex_dump(KERN_DEBUG, "MXT MSG:", DUMP_PREFIX_NONE, 16, 1,
+ data->msg_buf, data->T5_msg_size, false);
+ if ((data->msg_buf[0] == data->T6_reportid) &&
+ (data->msg_buf[1] & MXT_STATUS_CAL))
+ is_calib_msg_exists = true;
+ i ++;
}
- if (enable) {
- error = mxt_set_clr_reg(data, MXT_TOUCH_KEYARRAY_T15,
- MXT_KEYARRAY_CTRL, 0, MXT_KEY_RPTEN);
- } else {
- error = mxt_set_clr_reg(data, MXT_TOUCH_KEYARRAY_T15,
- MXT_KEYARRAY_CTRL, MXT_KEY_RPTEN, 0);
- }
+ return is_calib_msg_exists;
- if (error)
- dev_err(dev, "write to t15 failed!\n");
}
static void mxt_start(struct mxt_data *data)
@@ -4604,25 +4876,17 @@ static void mxt_start(struct mxt_data *data)
int error;
struct device *dev = &data->client->dev;
- if (mxt_prevent_sleep() && data->is_stopped!=1) {
- mxt_set_gesture_wake_up(data, false);
- if (!data->is_wakeup_by_gesture)
- mxt_set_t7_for_gesture(data, false);
- data->is_stopped = 0;
+ if (data->is_stopped == 0)
return;
- } else {
- if (data->is_stopped == 0)
- return;
- error = mxt_set_power_cfg(data, MXT_POWER_CFG_RUN);
- if (error)
- return;
- /* At this point, it may be necessary to clear state
- * by disabling/re-enabling the noise suppression object */
+ error = mxt_set_power_cfg(data, MXT_POWER_CFG_RUN);
+ if (error)
+ return;
- /* Recalibrate since chip has been in deep sleep */
- schedule_delayed_work(&data->calibration_delayed_work, msecs_to_jiffies(100));
- }
+ if (mxt_read_and_check_calib_msg(data))
+ queue_delayed_work(data->work_queue, &data->update_setting_delayed_work, HZ);
+ else
+ mxt_do_calibration(data);
dev_dbg(dev, "MXT started\n");
}
@@ -4632,21 +4896,13 @@ static void mxt_stop(struct mxt_data *data)
int error;
struct device *dev = &data->client->dev;
- if (mxt_prevent_sleep()) {
- data->is_wakeup_by_gesture = false;
- mxt_set_t7_for_gesture(data, true);
- mxt_set_gesture_wake_up(data, true);
- data->is_stopped = 1;
- } else {
- if (data->is_stopped)
- return;
+ if (data->is_stopped)
+ return;
- cancel_delayed_work_sync(&data->calibration_delayed_work);
- error = mxt_set_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
+ error = mxt_set_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
- if (!error)
- dev_dbg(dev, "MXT suspended\n");
- }
+ if (!error)
+ dev_dbg(dev, "MXT suspended\n");
}
static int mxt_input_open(struct input_dev *dev)
@@ -4674,7 +4930,6 @@ static void mxt_clear_touch_event(struct mxt_data *data)
for (id = 0; id < data->num_touchids - 2; id++) {
input_mt_slot(input_dev, id);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
- data->finger_down[id] = false;
}
for (i = 0; i < data->pdata->config_array[index].key_num; i++)
clear_bit(data->pdata->config_array[index].key_codes[i], input_dev->key);
@@ -4689,76 +4944,43 @@ static int mxt_suspend(struct device *dev)
struct mxt_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
- if (data->pdata->cut_off_power) {
- /* In the power is cut off with LCD off, wake up gesture can not be used */
- mutex_lock(&input_dev->mutex);
-
- if (data->is_stopped) {
- mutex_unlock(&input_dev->mutex);
- return 0;
- }
-
- mxt_disable_irq(data);
- gpio_set_value(data->pdata->reset_gpio, 0);
-
- mxt_clear_touch_event(data);
-
- if (data->regulator_vdd && data->regulator_avdd && data->regulator_vddio) {
- ret = regulator_disable(data->regulator_avdd);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator disable for avdd failed: %d\n", ret);
- }
- ret = regulator_disable(data->regulator_vdd);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator disable for vdd failed: %d\n", ret);
- }
-
- ret = regulator_disable(data->regulator_vddio);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator disable for vddio failed: %d\n", ret);
- }
- }
-
- data->is_stopped = 1;
+ if(likely(data->irq_enabled)) {
+ disable_irq(client->irq);
+ data->irq_enabled=false;
+ }
- mutex_unlock(&input_dev->mutex);
- } else {
- if (!mxt_prevent_sleep())
- mxt_disable_irq(data);
+ data->safe_count = 0;
+ cancel_delayed_work_sync(&data->update_setting_delayed_work);
+ cancel_delayed_work_sync(&data->disable_anticalib_delayed_work);
+ mxt_adjust_self_setting(data, true, TYPE_SELF_THR);
+ mxt_adjust_self_setting(data, true, TYPE_SELF_INTTHR_SUSPEND);
+ mxt_anti_calib_control(data, true);
+ mxt_self_recalib_control(data, true);
- mutex_lock(&input_dev->mutex);
+ mutex_lock(&input_dev->mutex);
- if (input_dev->users)
- mxt_stop(data);
+ if (input_dev->users)
+ mxt_stop(data);
- mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&input_dev->mutex);
- mxt_clear_touch_event(data);
+ mxt_clear_touch_event(data);
- if (data->regulator_vdd && data->regulator_avdd && data->regulator_vddio) {
- ret = regulator_disable(data->regulator_avdd);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator disable for avdd failed: %d\n", ret);
- }
- ret = regulator_disable(data->regulator_vdd);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator disable for vdd failed: %d\n", ret);
- }
- ret = regulator_disable(data->regulator_vddio);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator disable for vddio failed: %d\n", ret);
- }
+ if (data->regulator_vdd && data->regulator_avdd) {
+ ret = regulator_disable(data->regulator_avdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator disable for avdd failed: %d\n", ret);
+ }
+ ret = regulator_disable(data->regulator_vdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator disable for vdd failed: %d\n", ret);
}
- data->is_stopped = 1;
-
}
+ data->land_signed = 0;
+ data->self_restore_done = 0;
return 0;
}
@@ -4770,67 +4992,31 @@ static int mxt_resume(struct device *dev)
struct mxt_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
- if (data->pdata->cut_off_power) {
- mutex_lock(&input_dev->mutex);
-
- if (!data->is_stopped) {
- mutex_unlock(&input_dev->mutex);
- return 0;
+ if (data->regulator_vdd && data->regulator_avdd) {
+ ret = regulator_enable(data->regulator_vdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator enable for vdd failed: %d\n", ret);
}
-
- if (data->regulator_vdd && data->regulator_avdd && data->regulator_vddio) {
- ret = regulator_enable(data->regulator_vdd);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator enable for vdd failed: %d\n", ret);
- }
- ret = regulator_enable(data->regulator_avdd);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator enable for avdd failed: %d\n", ret);
- }
- ret = regulator_enable(data->regulator_vddio);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator enable for vddio failed: %d\n", ret);
- }
+ ret = regulator_enable(data->regulator_avdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator enable for avdd failed: %d\n", ret);
}
+ }
- mxt_wait_for_chg(data);
- mxt_enable_irq(data);
- schedule_delayed_work(&data->calibration_delayed_work, msecs_to_jiffies(100));
- data->is_stopped = false;
-
- mutex_unlock(&input_dev->mutex);
- } else {
- mxt_enable_irq(data);
-
- if (data->regulator_vdd && data->regulator_avdd && data->regulator_vddio) {
- ret = regulator_enable(data->regulator_vdd);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator enable for vdd failed: %d\n", ret);
- }
- ret = regulator_enable(data->regulator_avdd);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator enable for avdd failed: %d\n", ret);
- }
- ret = regulator_enable(data->regulator_vddio);
- if (ret < 0) {
- dev_err(dev,
- "Atmel regulator enable for vddio failed: %d\n", ret);
- }
- }
+ mutex_lock(&input_dev->mutex);
- mutex_lock(&input_dev->mutex);
+ if (input_dev->users)
+ mxt_start(data);
- if (input_dev->users)
- mxt_start(data);
+ mutex_unlock(&input_dev->mutex);
- data->is_stopped = false;
- mutex_unlock(&input_dev->mutex);
+ if (likely(!data->irq_enabled)) {
+ enable_irq(client->irq);
+ data->irq_enabled=true;
}
+
return 0;
}
@@ -4858,51 +5044,6 @@ static int mxt_input_disable(struct input_dev *in_dev)
return error;
}
-#ifdef CONFIG_FB
-static int fb_notifier_cb(struct notifier_block *self,
- unsigned long event, void *data)
-{
- struct fb_event *evdata = data;
- int *blank;
- struct mxt_data *mxt_data =
- container_of(self, struct mxt_data, fb_notif);
-
- if (evdata && evdata->data && event == FB_EVENT_BLANK && mxt_data) {
- blank = evdata->data;
- if (*blank == FB_BLANK_UNBLANK) {
- dev_info(&mxt_data->client->dev, "##### UNBLANK SCREEN #####\n");
- mxt_data->screen_off = false;
- mxt_input_enable(mxt_data->input_dev);
- } else if (*blank == FB_BLANK_POWERDOWN) {
- dev_info(&mxt_data->client->dev, "##### BLANK SCREEN #####\n");
- mxt_data->screen_off = true;
- mxt_input_disable(mxt_data->input_dev);
- }
- }
-
- return 0;
-}
-
-static void configure_sleep(struct mxt_data *data)
-{
- int ret;
-
- data->fb_notif.notifier_call = fb_notifier_cb;
- ret = fb_register_client(&data->fb_notif);
- if (ret) {
- dev_err(&data->client->dev,
- "Unable to register fb_notifier, err: %d\n", ret);
- }
-}
-#else
-static void configure_sleep(struct mxt_data *data)
-{
- data->input_dev->enable = mxt_input_enable;
- data->input_dev->disable = mxt_input_disable;
- data->input_dev->enabled = true;
-}
-#endif
-
static int mxt_initialize_input_device(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
@@ -4928,12 +5069,14 @@ static int mxt_initialize_input_device(struct mxt_data *data)
input_dev->dev.parent = dev;
input_dev->open = mxt_input_open;
input_dev->close = mxt_input_close;
+ input_dev->enable = mxt_input_enable;
+ input_dev->disable = mxt_input_disable;
+ input_dev->enabled = true;
input_dev->event = mxt_input_event;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
- __set_bit(BTN_TOUCH, input_dev->keybit);
/* For multi touch */
input_mt_init_slots(input_dev,
@@ -4987,8 +5130,6 @@ static int mxt_initialize_input_device(struct mxt_data *data)
data->input_dev = input_dev;
- configure_sleep(data);
-
return 0;
}
@@ -5119,9 +5260,13 @@ static void mxt_dump_value(struct device *dev, struct mxt_platform_data *pdata)
dev_info(dev, "irq gpio= %d\n", pdata->irq_gpio);
dev_info(dev, "power gpio= %d\n", pdata->power_gpio);
dev_info(dev, "fw name = %s\n", pdata->mxt_fw_name);
+ dev_info(dev, "unlock move threshold= %d\n", pdata->unlock_move_threshold);
+ dev_info(dev, "landing threshold= %d\n", pdata->landing_threshold);
+ dev_info(dev, "landing edge threshold= %d\n", pdata->landing_edge_threshold);
+ dev_info(dev, "staying threshold= %d\n", pdata->staying_threshold);
+ dev_info(dev, "jiffies= %ld\n", pdata->landing_jiffies);
dev_info(dev, "config size = %d\n", pdata->config_array_size);
dev_info(dev, "gpio mask = 0x%x\n", pdata->gpio_mask);
- dev_info(dev, "cut off power = %d\n", (int)pdata->cut_off_power);
for (i = 0; i < pdata->config_array_size; i++) {
dev_info(dev, "family_id = 0x%x\n", pdata->config_array[i].family_id);
@@ -5130,8 +5275,6 @@ static void mxt_dump_value(struct device *dev, struct mxt_platform_data *pdata)
dev_info(dev, "build = 0x%x\n", pdata->config_array[i].build);
dev_info(dev, "mxt_cfg_name = %s\n", pdata->config_array[i].mxt_cfg_name);
dev_info(dev, "vendor_id = 0x%x\n", pdata->config_array[i].vendor_id);
- dev_info(dev, "rev_id = 0x%x\n", pdata->config_array[i].rev_id);
- dev_info(dev, "wakeup self adcx = 0x%x\n", pdata->config_array[i].wake_up_self_adcx);
}
}
@@ -5142,18 +5285,18 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
struct mxt_config_info *info;
struct device_node *temp, *np = dev->of_node;
u32 temp_val;
+ int *linearity_reg_pos;
+ int *linearity_singlex;
+ int *linearity_dualx;
+ int i;
/* reset, irq, power gpio info */
pdata->reset_gpio = of_get_named_gpio_flags(np, "atmel,reset-gpio",
0, &pdata->reset_gpio_flags);
pdata->irq_gpio = of_get_named_gpio_flags(np, "atmel,irq-gpio",
0, &pdata->irq_gpio_flags);
- if (get_hw_version_major() <= 4)
- pdata->power_gpio = of_get_named_gpio_flags(np, "atmel,power-gpio",
- 0, &pdata->power_gpio_flags);
- else
- pdata->power_gpio = -EINVAL;
-
+ pdata->power_gpio = of_get_named_gpio_flags(np, "atmel,power-gpio",
+ 0, &pdata->power_gpio_flags);
ret = of_property_read_u32(np, "atmel,irqflags", &temp_val);
if (ret) {
dev_err(dev, "Unable to read irqflags id\n");
@@ -5168,7 +5311,29 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
return ret;
}
- pdata->cut_off_power = of_property_read_bool(np, "atmel,cut-off-power");
+ ret = of_property_read_u32(np, "atmel,unlock-move-threshold", &pdata->unlock_move_threshold);
+ if (ret)
+ dev_err(dev, "Unable to read unlock move threshold\n");
+
+ ret = of_property_read_u32(np, "atmel,staying-threshold", &pdata->staying_threshold);
+ if (ret)
+ dev_err(dev, "Unable to read staying threshold\n");
+
+ ret = of_property_read_u32(np, "atmel,landing-threshold", &pdata->landing_threshold);
+ if (ret)
+ dev_err(dev, "Unable to read landing threshold\n");
+
+ ret = of_property_read_u32(np, "atmel,landing-edge-threshold", &pdata->landing_edge_threshold);
+ if (ret)
+ dev_err(dev, "Unable to read landing edge threshold\n");
+
+ ret = of_property_read_u32(np, "atmel,landing-jiffies", (u32*)&pdata->landing_jiffies);
+ if (ret)
+ dev_err(dev, "Unable to read landing jiffies\n");
+
+ ret = of_property_read_u32(np, "atmel,edge-clip", (u32*)&pdata->edge_clip);
+ if (ret)
+ dev_err(dev, "Unable to read edge clip\n");
ret = of_property_read_u32(np, "atmel,gpio-mask", (u32*)&temp_val);
if (ret)
@@ -5176,16 +5341,82 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
else
pdata->gpio_mask = (u8)temp_val;
- ret = of_property_read_u32(np, "atmel,config-array-size", &pdata->config_array_size);
+ ret = of_property_read_u32(np, "atmel,linearity-para-num", (u32*)&temp_val);
+ if (ret)
+ dev_err(dev, "Unable to read linearity para num\n");
+
+ linearity_reg_pos = devm_kzalloc(dev, sizeof(int) * temp_val, GFP_KERNEL);
+ if (!linearity_reg_pos)
+ return -ENOMEM;
+ linearity_singlex = devm_kzalloc(dev, sizeof(int) * temp_val, GFP_KERNEL);
+ if (!linearity_singlex)
+ return -ENOMEM;
+ linearity_dualx = devm_kzalloc(dev, sizeof(int) * temp_val, GFP_KERNEL);
+ if (!linearity_dualx)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(np, "atmel,linearity-reg-pos",
+ linearity_reg_pos, temp_val);
if (ret) {
- dev_err(dev, "Unable to get array size\n");
+ dev_err(dev, "Unable to get linearity reg pos.\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32_array(np, "atmel,linearity-singlex",
+ linearity_singlex, temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to get linearity singlex.\n");
return ret;
}
- ret = of_property_read_u32(np, "atmel,default-config", &pdata->default_config);
+ ret = of_property_read_u32_array(np, "atmel,linearity-dualx",
+ linearity_dualx, temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to get linearity dualx.\n");
+ return ret;
+ }
+
+ pdata->linearity_para_num = temp_val;
+ pdata->linearity_reg_pos = devm_kzalloc(dev, sizeof(u8) * temp_val, GFP_KERNEL);
+ if (!pdata->linearity_reg_pos)
+ return -ENOMEM;
+ pdata->linearity_singlex = devm_kzalloc(dev, sizeof(u8) * temp_val, GFP_KERNEL);
+ if (!pdata->linearity_singlex)
+ return -ENOMEM;
+ pdata->linearity_dualx = devm_kzalloc(dev, sizeof(u8) * temp_val, GFP_KERNEL);
+ if (!pdata->linearity_dualx)
+ return -ENOMEM;
+ for (i = 0; i < temp_val; i++) {
+ pdata->linearity_reg_pos[i] = (u8)linearity_reg_pos[i];
+ pdata->linearity_singlex[i] = (u8)linearity_singlex[i];
+ pdata->linearity_dualx[i] = (u8)linearity_dualx[i];
+ }
+
+ ret = of_property_read_u32(np, "atmel,rx-num", (u32*)&temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to get rx number.\n");
+ return ret;
+ } else
+ pdata->rx_num = (u8)temp_val;
+
+ ret = of_property_read_u32(np, "atmel,tx-num", (u32*)&temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to get tx number.\n");
+ return ret;
+ } else
+ pdata->tx_num = (u8)temp_val;
+
+ ret = of_property_read_u32(np, "atmel,ref-diff-threshold", (u32*)&temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to get reference diff threshold.\n");
+ return ret;
+ } else
+ pdata->ref_diff_threshold = (u16)temp_val;
+
+ ret = of_property_read_u32(np, "atmel,config-array-size", &pdata->config_array_size);
if (ret) {
- dev_err(dev, "Unable to get default config\n");
- pdata->default_config = -1;
+ dev_err(dev, "Unable to get array size\n");
+ return ret;
}
pdata->config_array = devm_kzalloc(dev, pdata->config_array_size *
@@ -5234,13 +5465,12 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
return ret;
} else
info->vendor_id = (u8)temp_val;
- ret = of_property_read_u32(temp, "atmel,rev-id", &temp_val);
+ ret = of_property_read_u32(temp, "atmel,lcd-id", &temp_val);
if (ret) {
- dev_err(dev, "Unable to read rev id\n");
+ dev_err(dev, "Unable to read lcd id\n");
return ret;
} else
- info->rev_id = (u8)temp_val;
-
+ info->lcd_id = (int)temp_val;
ret = of_property_read_u32(temp, "atmel,key-num", &temp_val);
if (ret) {
dev_err(dev, "Unable to read key num id\n");
@@ -5260,18 +5490,42 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
}
}
+ ret = of_property_read_u32(temp, "atmel,selfthr-suspend", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read selfthr-suspend\n");
+ return ret;
+ } else
+ info->selfthr_suspend = temp_val;
ret = of_property_read_u32(temp, "atmel,selfintthr-stylus", &temp_val);
if (ret) {
dev_err(dev, "Unable to read selfintthr-stylus\n");
return ret;
} else
info->selfintthr_stylus = temp_val;
+ ret = of_property_read_u32(temp, "atmel,selfintthr-suspend", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read selfintthr-suspend\n");
+ return ret;
+ } else
+ info->selfintthr_suspend = temp_val;
ret = of_property_read_u32(temp, "atmel,t71-tchthr-pos", &temp_val);
if (ret) {
dev_err(dev, "Unable to read t71-glove-ctrl-reg\n");
return ret;
} else
info->t71_tchthr_pos = temp_val;
+ ret = of_property_read_u32(temp, "atmel,self-no-touch-threshold", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read self-no-touch-threshold\n");
+ return ret;
+ } else
+ info->self_no_touch_threshold = temp_val;
+ ret = of_property_read_u32(temp, "atmel,mult-no-touch-threshold", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read mult-no-touch-threshold\n");
+ return ret;
+ } else
+ info->mult_no_touch_threshold = temp_val;
ret = of_property_read_u32(temp, "atmel,self-chgtime-min", &temp_val);
if (ret) {
dev_err(dev, "Unable to read self-chgtime-min\n");
@@ -5315,14 +5569,6 @@ static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
} else
info->mult_tchthr_not_sensitive = temp_val;
- ret = of_property_read_u32(temp, "atmel,wake-up-self-adcx", &temp_val);
- if (ret) {
- dev_err(dev, "Unable to read wake-up-self-adcx\n");
- info->wake_up_self_adcx = 0;
- } else
- info->wake_up_self_adcx = (u8)temp_val;
-
-
info++;
}
@@ -5343,10 +5589,9 @@ static int __devinit mxt_probe(struct i2c_client *client,
struct mxt_platform_data *pdata;
struct mxt_data *data;
int error;
- struct gpiomux_setting old_rst_setting, old_int_setting;
-// if (get_hw_version_major() < 4)
-// return -ENODEV;
+ if (get_hw_version_major() >= 4)
+ return -ENODEV;
if (client->dev.of_node) {
pdata = devm_kzalloc(&client->dev,
@@ -5377,31 +5622,22 @@ static int __devinit mxt_probe(struct i2c_client *client,
data->pdata = pdata;
data->irq = client->irq;
- /* In X5 platform, we do not need to control touchscreen power,
- which is enabled by LCD */
- if (get_hw_version_major() <= 4) {
- /* In X4 platform, we need to control power gpio by ourselves */
- if (gpio_is_valid(pdata->power_gpio)) {
- error = gpio_request(pdata->power_gpio, "mxt_gpio_power");
- if (!error) {
- error = gpio_direction_output(pdata->power_gpio, 1);
- if (error) {
- pr_err("%s: unable to set direction gpio %d\n",
- __func__, pdata->power_gpio);
- goto err_disable_regulator;
- }
- } else {
- pr_err("%s: unable to request power gpio %d\n",
+ if (gpio_is_valid(pdata->power_gpio)) {
+ error = gpio_request(pdata->power_gpio, "mxt_gpio_power");
+ if (!error) {
+ error = gpio_direction_output(pdata->power_gpio, 1);
+ if (error) {
+ pr_err("%s: unable to set direction gpio %d\n",
__func__, pdata->power_gpio);
- goto err_free_data;
+ goto err_free_power_gpio;
}
+ } else {
+ pr_err("%s: unable to request power gpio %d\n",
+ __func__, pdata->power_gpio);
+ goto err_free_data;
}
- } else {
- /* In X5 platform, if we need to cut off power when lcd is off,
- * we should also control the power regulator */
- if (pdata->cut_off_power)
- mxt_initialize_regulator(data);
- }
+ } else
+ mxt_initialize_regulator(data);
if (gpio_is_valid(pdata->irq_gpio)) {
/* configure touchscreen irq gpio */
@@ -5437,73 +5673,49 @@ static int __devinit mxt_probe(struct i2c_client *client,
}
i2c_set_clientdata(data->client, data);
- mdelay(10);
+ msleep(10);
mxt_wait_for_chg(data);
- INIT_WORK(&data->self_tuning_work, mxt_self_tuning_work);
- INIT_WORK(&data->hover_loading_work, mxt_hover_loading_work);
- INIT_DELAYED_WORK(&data->calibration_delayed_work,
- mxt_calibration_delayed_work);
+
+ data->work_queue = create_workqueue("tp_work_queue");
+ if (data->work_queue != NULL) {
+ dev_info(&client->dev, "Create tp work queue!\n");
+ INIT_DELAYED_WORK(&data->update_setting_delayed_work,
+ mxt_update_setting_delayed_work);
+
+ INIT_DELAYED_WORK(&data->disable_anticalib_delayed_work,
+ mxt_disable_anticalib_delayed_work);
+ INIT_WORK(&data->pre_use_work, mxt_pre_use_work);
+ } else {
+ dev_err(&client->dev, "Fatal error, workqueue can't be created!!!\n");
+ goto err_disable_regulator;
+ }
+ mutex_init(&data->golden_mutex);
/* Initialize i2c device */
-retry:
error = mxt_initialize(data);
if (error)
{
- if (gpio_is_valid(pdata->power_gpio))
- pr_err("power gpio = %d\n", (int)gpio_get_value(pdata->power_gpio));
+ pr_err("power gpio = %d\n", (int)gpio_get_value(pdata->power_gpio));
pr_err("reset gpio = %d\n", (int)gpio_get_value(pdata->reset_gpio));
pr_err("chg gpio = %d\n", (int)gpio_get_value(pdata->irq_gpio));
- if (error != -ENOENT) {
- if (client->addr == 0x4a)
- goto err_reset_gpio_req;
- else {
- client->addr = 0x4a;
- goto retry;
- }
- }
+ if (error != -ENOENT)
+ goto err_disable_regulator;
else {
- error = mxt_update_firmware(&client->dev, NULL,
- pdata->mxt_fw_name, strlen(pdata->mxt_fw_name), &data->firmware_updated);
+ error = mxt_update_fw_store(&client->dev, NULL,
+ pdata->mxt_fw_name, strlen(pdata->mxt_fw_name));
if (error != strlen(pdata->mxt_fw_name))
{
dev_err(&client->dev, "Error when update firmware!\n");
- goto err_reset_gpio_req;
+ goto err_disable_regulator;
}
}
}
- /*
- * In X5 platform, since we will cut off lcd power when display is off.
- * To avoid a powerup issue, we will set RST pin to HI-Z and disable
- * internal pull-up resistor on INT pin
- */
- if (get_hw_version_major() == 5 && pdata->cut_off_power) {
- if (msm_gpiomux_write(pdata->reset_gpio, GPIOMUX_ACTIVE,
- &mxt_rst_cutoff_pwr_cfg, &old_rst_setting)) {
- dev_err(&client->dev, "Failed to set RESET pinmux setting\n");
- goto err_free_object;
- }
-
- if (msm_gpiomux_write(pdata->irq_gpio, GPIOMUX_ACTIVE,
- &mxt_int_cutoff_pwr_cfg, &old_int_setting)) {
- dev_err(&client->dev, "Failed to set INT pinmux setting\n");
- goto err_restore_rst_gpio_setting;
- }
-
- if (gpio_direction_input(pdata->reset_gpio)) {
- dev_err(&client->dev, "Failed to set RESET pin to input\n");
- goto err_restore_int_gpio_setting;
- }
- mdelay(10);
- mxt_wait_for_chg(data);
- }
-
- if (0)
- mxt_update_fw_by_flag(data);
+ mxt_update_fw_by_flag(data);
error = mxt_initialize_input_device(data);
if (error)
- goto err_restore_int_gpio_setting;
+ goto err_free_object;
error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
pdata->irqflags, client->dev.driver->name, data);
@@ -5511,10 +5723,8 @@ retry:
dev_err(&client->dev, "Error %d registering irq\n", error);
goto err_free_input_device;
}
- data->irq_enabled = true;
- data->screen_off = false;
- device_init_wakeup(&client->dev, 1);
+ data->irq_enabled = true;
error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
if (error) {
@@ -5523,7 +5733,6 @@ retry:
goto err_free_irq;
}
-
sysfs_bin_attr_init(&data->mem_access_attr);
data->mem_access_attr.attr.name = "mem_access";
data->mem_access_attr.attr.mode = S_IRUGO | S_IWUSR;
@@ -5539,7 +5748,16 @@ retry:
}
mxt_debugfs_init(data);
- schedule_work(&data->hover_loading_work);
+
+ data->ignore_tx = kmalloc(sizeof(int) * pdata->tx_num, GFP_KERNEL);
+ if (data->ignore_tx == NULL)
+ goto err_remove_sysfs_group;
+ data->ignore_rx = kmalloc(sizeof(int) * pdata->rx_num, GFP_KERNEL);
+ if (data->ignore_rx == NULL)
+ goto err_remove_sysfs_group;
+
+ queue_work(data->work_queue, &data->pre_use_work);
+ data->init_complete = true;
return 0;
@@ -5552,31 +5770,23 @@ err_free_input_device:
err_free_object:
kfree(data->msg_buf);
kfree(data->object_table);
-err_restore_int_gpio_setting:
- if (get_hw_version_major() == 5 && pdata->cut_off_power)
- msm_gpiomux_write(pdata->irq_gpio, GPIOMUX_ACTIVE,
- &old_int_setting, NULL);
-err_restore_rst_gpio_setting:
- if (get_hw_version_major() == 5 && pdata->cut_off_power)
- msm_gpiomux_write(pdata->reset_gpio, GPIOMUX_ACTIVE,
- &old_rst_setting, NULL);
+err_disable_regulator:
+ if (gpio_is_valid(pdata->power_gpio)) {
+ gpio_set_value_cansleep(pdata->power_gpio, 0);
+ } else {
+ regulator_disable(data->regulator_avdd);
+ regulator_disable(data->regulator_vdd);
+ }
err_reset_gpio_req:
if (gpio_is_valid(pdata->reset_gpio))
gpio_free(pdata->reset_gpio);
err_irq_gpio_req:
if (gpio_is_valid(pdata->irq_gpio))
gpio_free(pdata->irq_gpio);
-err_disable_regulator:
+err_free_power_gpio:
if (gpio_is_valid(pdata->power_gpio)) {
- gpio_set_value_cansleep(pdata->power_gpio, 0);
gpio_free(pdata->power_gpio);
}
- if (data->regulator_vdd)
- regulator_disable(data->regulator_vdd);
- if (data->regulator_avdd)
- regulator_disable(data->regulator_avdd);
- if (data->regulator_vddio)
- regulator_disable(data->regulator_vddio);
err_free_data:
kfree(data);
return error;
@@ -5587,6 +5797,9 @@ static int __devexit mxt_remove(struct i2c_client *client)
struct mxt_data *data = i2c_get_clientdata(client);
const struct mxt_platform_data *pdata = data->pdata;
+ cancel_delayed_work_sync(&data->update_setting_delayed_work);
+ cancel_delayed_work_sync(&data->disable_anticalib_delayed_work);
+ destroy_workqueue(data->work_queue);
sysfs_remove_bin_file(&client->dev.kobj, &data->mem_access_attr);
sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
free_irq(data->irq, data);
@@ -5597,14 +5810,13 @@ static int __devexit mxt_remove(struct i2c_client *client)
data->object_table = NULL;
if (gpio_is_valid(pdata->power_gpio)) {
gpio_set_value_cansleep(pdata->power_gpio, 0);
- gpio_free(pdata->power_gpio);
- }
- if (data->regulator_vdd)
- regulator_disable(data->regulator_vdd);
- if (data->regulator_avdd)
+ } else {
regulator_disable(data->regulator_avdd);
- if (data->regulator_vddio)
- regulator_disable(data->regulator_vddio);
+ regulator_disable(data->regulator_vdd);
+ }
+
+ if (gpio_is_valid(pdata->power_gpio))
+ gpio_free(pdata->power_gpio);
if (gpio_is_valid(pdata->irq_gpio))
gpio_free (pdata->irq_gpio);
@@ -5622,46 +5834,17 @@ static void mxt_shutdown(struct i2c_client *client)
{
struct mxt_data *data = i2c_get_clientdata(client);
- mxt_disable_irq(data);
- data->state = SHUTDOWN;
-}
-
-#ifdef CONFIG_PM
-static int mxt_ts_suspend(struct device *dev)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev) &&
- mxt_prevent_sleep()) {
- dev_info(dev, "touch enable irq wake\n");
- mxt_disable_irq(data);
- enable_irq_wake(data->client->irq);
- }
-
- return 0;
-}
-
-static int mxt_ts_resume(struct device *dev)
-{
- struct mxt_data *data = dev_get_drvdata(dev);
-
- if (device_may_wakeup(dev) &&
- mxt_prevent_sleep()) {
- dev_info(dev, "touch disable irq wake\n");
- disable_irq_wake(data->client->irq);
- mxt_enable_irq(data);
+ if(likely(data->irq_enabled)) {
+ disable_irq(data->irq);
+ data->irq_enabled=false;
}
- return 0;
+ data->state = SHUTDOWN;
}
-static SIMPLE_DEV_PM_OPS(mxt_touchscreen_pm_ops, mxt_ts_suspend, mxt_ts_resume);
-#endif
-
static const struct i2c_device_id mxt_id[] = {
{ "qt602240_ts", 0 },
- { "atmel_mxt_ts_640t", 0 },
- { "atmel_mxt_ts", 0},
+ { "atmel_mxt_ts", 0 },
{ "mXT224", 0 },
{ }
};
@@ -5669,9 +5852,8 @@ MODULE_DEVICE_TABLE(i2c, mxt_id);
#ifdef CONFIG_OF
static struct of_device_id mxt_match_table[] = {
- { .compatible = "atmel,mxt-ts-640t",},
- { .compatible = "atmel,mxt-ts", },
- {}
+ { .compatible = "atmel,mxt-ts",},
+ { },
};
#else
#define mxt_match_table NULL
@@ -5682,9 +5864,6 @@ static struct i2c_driver mxt_driver = {
.name = "atmel_mxt_ts",
.owner = THIS_MODULE,
.of_match_table = mxt_match_table,
-#ifdef CONFIG_PM
- .pm = &mxt_touchscreen_pm_ops,
-#endif
},
.probe = mxt_probe,
.remove = __devexit_p(mxt_remove),
@@ -5706,6 +5885,6 @@ late_initcall(mxt_init);
module_exit(mxt_exit);
/* Module information */
-MODULE_AUTHOR("Lionel Zhang <zhangbo_a@xiaomi.com>");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/atmel_mxt_ts_640t.c b/drivers/input/touchscreen/atmel_mxt_ts_640t.c
new file mode 100644
index 0000000..ba61ba4
--- /dev/null
+++ b/drivers/input/touchscreen/atmel_mxt_ts_640t.c
@@ -0,0 +1,5691 @@
+/*
+ * Atmel maXTouch Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Copyright (C) 2011 Atmel Corporation
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Copyright (C) 2015 XiaoMi, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c/atmel_mxt_ts_640t.h>
+#include <linux/debugfs.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/string.h>
+#include <linux/of_gpio.h>
+#include <asm/bootinfo.h>
+#include <mach/gpiomux.h>
+#ifdef CONFIG_FB
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#endif
+
+
+/* Version */
+#define MXT_VER_20 20
+#define MXT_VER_21 21
+#define MXT_VER_22 22
+
+/* Firmware files */
+#define MXT_FW_NAME "maxtouch.fw"
+#define MXT_CFG_MAGIC "OBP_RAW V1"
+
+#define REV_D 0x32
+
+/* Registers */
+#define MXT_FAMILY_ID 0x00
+#define MXT_VARIANT_ID 0x01
+#define MXT_VERSION 0x02
+#define MXT_BUILD 0x03
+#define MXT_MATRIX_X_SIZE 0x04
+#define MXT_MATRIX_Y_SIZE 0x05
+#define MXT_OBJECT_NUM 0x06
+#define MXT_OBJECT_START 0x07
+
+#define MXT_OBJECT_SIZE 6
+
+#define MXT_MAX_BLOCK_WRITE 256
+
+/* Object types */
+#define MXT_DEBUG_DIAGNOSTIC_T37 37
+#define MXT_SPT_USERDATA_T38 38
+#define MXT_GEN_MESSAGE_T5 5
+#define MXT_GEN_COMMAND_T6 6
+#define MXT_GEN_POWER_T7 7
+#define MXT_GEN_ACQUIRE_T8 8
+#define MXT_GEN_DATASOURCE_T53 53
+#define MXT_TOUCH_MULTI_T9 9
+#define MXT_TOUCH_KEYARRAY_T15 15
+#define MXT_TOUCH_PROXIMITY_T23 23
+#define MXT_TOUCH_PROXKEY_T52 52
+#define MXT_PROCI_GRIPFACE_T20 20
+#define MXT_PROCG_NOISE_T22 22
+#define MXT_PROCI_ACTIVE_STYLUS_T63 63
+#define MXT_PROCI_ONETOUCH_T24 24
+#define MXT_PROCI_TWOTOUCH_T27 27
+#define MXT_PROCI_GRIP_T40 40
+#define MXT_PROCI_PALM_T41 41
+#define MXT_PROCI_TOUCHSUPPRESSION_T42 42
+#define MXT_PROCI_STYLUS_T47 47
+#define MXT_PROCG_NOISESUPPRESSION_T48 48
+#define MXT_SPT_COMMSCONFIG_T18 18
+#define MXT_SPT_GPIOPWM_T19 19
+#define MXT_SPT_SELFTEST_T25 25
+#define MXT_SPT_CTECONFIG_T28 28
+#define MXT_SPT_DIGITIZER_T43 43
+#define MXT_SPT_MESSAGECOUNT_T44 44
+#define MXT_SPT_CTECONFIG_T46 46
+#define MXT_SPT_NOISESUPPRESSION_T48 48
+#define MXT_PROCI_LENSBENDING_T65 65
+#define MXT_SPT_GOLDENREF_T66 66
+#define MXT_SERIALDATACOMMAND_T68 68
+#define MXT_SPT_DYMCFG_T70 70
+#define MXT_SPT_DYMDATA_T71 71
+#define MXT_PROCG_NOISESUPPRESSION_T72 72
+#define MXT_PROCI_GLOVEDETECTION_T78 78
+#define MXT_PROCI_RETRANSMISSIONCOMPENSATION_T80 80
+#define MXT_TOUCH_MORE_GESTURE_T81 81
+#define MXT_TOUCH_GESTURE_T92 92
+#define MXT_TOUCH_MULTI_T100 100
+#define MXT_SPT_TOUCHSCREENHOVER_T101 101
+#define MXT_PROCG_NOISESUPSELFCAP_T108 108
+#define MXT_SPT_SELFCAPGLOBALCONFIG_T109 109
+#define MXT_SPT_AUXTOUCHCONFIG_T104 104
+
+/* MXT_GEN_MESSAGE_T5 object */
+#define MXT_RPTID_NOMSG 0xff
+
+/* MXT_GEN_COMMAND_T6 field */
+#define MXT_COMMAND_RESET 0
+#define MXT_COMMAND_BACKUPNV 1
+#define MXT_COMMAND_CALIBRATE 2
+#define MXT_COMMAND_REPORTALL 3
+#define MXT_COMMAND_DIAGNOSTIC 5
+
+/* MXT_GEN_POWER_T7 field */
+#define MXT_POWER_IDLEACQINT 0
+#define MXT_POWER_ACTVACQINT 1
+#define MXT_POWER_ACTV2IDLETO 2
+
+#define MXT_POWER_CFG_RUN 0
+#define MXT_POWER_CFG_DEEPSLEEP 1
+
+/* MXT_GEN_ACQUIRE_T8 field */
+#define MXT_ACQUIRE_CHRGTIME 0
+#define MXT_ACQUIRE_TCHDRIFT 2
+#define MXT_ACQUIRE_DRIFTST 3
+#define MXT_ACQUIRE_TCHAUTOCAL 4
+#define MXT_ACQUIRE_SYNC 5
+#define MXT_ACQUIRE_ATCHCALST 6
+#define MXT_ACQUIRE_ATCHCALSTHR 7
+#define MXT_ACQUIRE_MEASALLOW 10
+
+/* MXT_TOUCH_MULTI_T9 field */
+#define MXT_TOUCH_CTRL 0
+#define MXT_TOUCH_XORIGIN 1
+#define MXT_TOUCH_YORIGIN 2
+#define MXT_TOUCH_XSIZE 3
+#define MXT_TOUCH_YSIZE 4
+#define MXT_TOUCH_BLEN 6
+#define MXT_TOUCH_TCHTHR 7
+#define MXT_TOUCH_TCHDI 8
+#define MXT_TOUCH_ORIENT 9
+#define MXT_TOUCH_MOVHYSTI 11
+#define MXT_TOUCH_MOVHYSTN 12
+#define MXT_TOUCH_NUMTOUCH 14
+#define MXT_TOUCH_MRGHYST 15
+#define MXT_TOUCH_MRGTHR 16
+#define MXT_TOUCH_AMPHYST 17
+#define MXT_TOUCH_XRANGE_LSB 18
+#define MXT_TOUCH_XRANGE_MSB 19
+#define MXT_TOUCH_YRANGE_LSB 20
+#define MXT_TOUCH_YRANGE_MSB 21
+#define MXT_TOUCH_XLOCLIP 22
+#define MXT_TOUCH_XHICLIP 23
+#define MXT_TOUCH_YLOCLIP 24
+#define MXT_TOUCH_YHICLIP 25
+#define MXT_TOUCH_XEDGECTRL 26
+#define MXT_TOUCH_XEDGEDIST 27
+#define MXT_TOUCH_YEDGECTRL 28
+#define MXT_TOUCH_YEDGEDIST 29
+#define MXT_TOUCH_JUMPLIMIT 30
+
+/* MXT_TOUCH_MULTI_T100 field */
+#define MXT_MULTITOUCH_CTRL 0
+#define MXT_MULTITOUCH_CFG1 1
+#define MXT_MULTITOUCH_SCRAUX 2
+#define MXT_MULTITOUCH_TCHAUX 3
+#define MXT_MULTITOUCH_TCHEVENTCFG 4
+#define MXT_MULTITOUCH_AKSCFG 5
+#define MXT_MULTITOUCH_NUMTCH 6
+#define MXT_MULTITOUCH_XYCFG 7
+#define MXT_MULTITOUCH_XORIGIN 8
+#define MXT_MULTITOUCH_XSIZE 9
+#define MXT_MULTITOUCH_XPITCH 10
+#define MXT_MULTITOUCH_XLOCLIP 11
+#define MXT_MULTITOUCH_XHICLIP 12
+#define MXT_MULTITOUCH_XRANGE_LSB 13
+#define MXT_MULTITOUCH_XRANGE_MSB 14
+#define MXT_MULTITOUCH_XEDGECFG 15
+#define MXT_MULTITOUCH_XEDGEDIST 16
+#define MXT_MULTITOUCH_DXEDGECFG 17
+#define MXT_MULTITOUCH_DXEDGEDIST 18
+#define MXT_MULTITOUCH_YORIGIN 19
+#define MXT_MULTITOUCH_YSIZE 20
+#define MXT_MULTITOUCH_YPITCH 21
+#define MXT_MULTITOUCH_YLOCLIP 22
+#define MXT_MULTITOUCH_YHICLIP 23
+#define MXT_MULTITOUCH_YRANGE_LSB 24
+#define MXT_MULTITOUCH_YRANGE_MSB 25
+#define MXT_MULTITOUCH_YEDGECFG 26
+#define MXT_MULTITOUCH_YEDGEDIST 27
+#define MXT_MULTITOUCH_GAIN 28
+#define MXT_MULTITOUCH_DXGAIN 29
+#define MXT_MULTITOUCH_TCHTHR 30
+#define MXT_MULTITOUCH_TCHHYST 31
+#define MXT_MULTITOUCH_INTTHR 32
+#define MXT_MULTITOUCH_NOISESF 33
+#define MXT_MULTITOUCH_MGRTHR 35
+#define MXT_MULTITOUCH_MRGTHRADJSTR 36
+#define MXT_MULTITOUCH_MRGHYST 37
+#define MXT_MULTITOUCH_DXTHRSF 38
+#define MXT_MULTITOUCH_TCHDIDOWN 39
+#define MXT_MULTITOUCH_TCHDIUP 40
+#define MXT_MULTITOUCH_NEXTTCHDI 41
+#define MXT_MULTITOUCH_JUMPLIMIT 43
+#define MXT_MULTITOUCH_MOVFILTER 44
+#define MXT_MULTITOUCH_MOVSMOOTH 45
+#define MXT_MULTITOUCH_MOVPRED 46
+#define MXT_MULTITOUCH_MOVHYSTILSB 47
+#define MXT_MULTITOUCH_MOVHYSTIMSB 48
+#define MXT_MULTITOUCH_MOVHYSTNLSB 49
+#define MXT_MULTITOUCH_MOVHYSTNMSB 50
+#define MXT_MULTITOUCH_AMPLHYST 51
+#define MXT_MULTITOUCH_SCRAREAHYST 52
+
+/* MXT_TOUCH_KEYARRAY_T15 */
+#define MXT_KEYARRAY_CTRL 0
+
+/* MXT_PROCI_GRIPFACE_T20 field */
+#define MXT_GRIPFACE_CTRL 0
+#define MXT_GRIPFACE_XLOGRIP 1
+#define MXT_GRIPFACE_XHIGRIP 2
+#define MXT_GRIPFACE_YLOGRIP 3
+#define MXT_GRIPFACE_YHIGRIP 4
+#define MXT_GRIPFACE_MAXTCHS 5
+#define MXT_GRIPFACE_SZTHR1 7
+#define MXT_GRIPFACE_SZTHR2 8
+#define MXT_GRIPFACE_SHPTHR1 9
+#define MXT_GRIPFACE_SHPTHR2 10
+#define MXT_GRIPFACE_SUPEXTTO 11
+
+/* MXT_PROCI_NOISE field */
+#define MXT_NOISE_CTRL 0
+#define MXT_NOISE_OUTFLEN 1
+#define MXT_NOISE_GCAFUL_LSB 3
+#define MXT_NOISE_GCAFUL_MSB 4
+#define MXT_NOISE_GCAFLL_LSB 5
+#define MXT_NOISE_GCAFLL_MSB 6
+#define MXT_NOISE_ACTVGCAFVALID 7
+#define MXT_NOISE_NOISETHR 8
+#define MXT_NOISE_FREQHOPSCALE 10
+#define MXT_NOISE_FREQ0 11
+#define MXT_NOISE_FREQ1 12
+#define MXT_NOISE_FREQ2 13
+#define MXT_NOISE_FREQ3 14
+#define MXT_NOISE_FREQ4 15
+#define MXT_NOISE_IDLEGCAFVALID 16
+
+/* MXT_SPT_COMMSCONFIG_T18 */
+#define MXT_COMMS_CTRL 0
+#define MXT_COMMS_CMD 1
+
+/* MXT_SPT_GPIOPWM_T19 */
+#define MXT_GPIOPWM_CTRL 0
+#define MXT_GPIOPWM_INTPULLUP 3
+#define MXT_GPIO_FORCERPT 0x7
+#define MXT_GPIO_DISABLEOUTPUT 0
+
+/* MXT_SPT_CTECONFIG_T28 field */
+#define MXT_CTE_CTRL 0
+#define MXT_CTE_CMD 1
+#define MXT_CTE_MODE 2
+#define MXT_CTE_IDLEGCAFDEPTH 3
+#define MXT_CTE_ACTVGCAFDEPTH 4
+#define MXT_CTE_VOLTAGE 5
+
+#define MXT_VOLTAGE_DEFAULT 2700000
+#define MXT_VOLTAGE_STEP 10000
+
+/* MXT_DEBUG_DIAGNOSTIC_T37 */
+#define MXT_DIAG_PAGE_UP 0x01
+#define MXT_DIAG_MULT_DELTA 0x10
+#define MXT_DIAG_SELF_REF 0xF5
+#define MXT_DIAG_SELF_DELTA 0xFC
+#define MXT_DIAG_PAGE_SIZE 0x80
+#define MXT_DIAG_TOTAL_SIZE 0x438
+#define MXT_DIAG_SELF_SIZE 0x6C
+#define MXT_DIAG_REV_ID 21
+#define MXT_LOCKDOWN_OFFSET 4
+
+/* MXT_SPT_USERDATA_T38 */
+#define MXT_FW_UPDATE_FLAG 0
+#define MXT_USERDATA_SIZE 8
+
+/* MXT_PROCI_STYLUS_T47 */
+#define MXT_PSTYLUS_CTRL 0
+
+/* MXT_PROCI_LENSBENDING_T65 */
+#define MXT_LENSBENDING_CTRL 0
+
+/* MXT_SERIALDATACOMMAND_T68 */
+#define MXT_LOCKDOWN_SIZE 8
+
+/* MXT_PROCG_NOISESUPPRESSION_T72 */
+#define MXT_NOISESUP_CTRL 0
+#define MXT_NOISESUP_CALCFG 1
+#define MXT_NOISESUP_CFG1 2
+
+/* MXT_PROCI_GLOVEDETECTION_T78 */
+#define MXT_GLOVE_CTRL 0x00
+
+/* MXT_SPT_TOUCHSCREENHOVER_T101 */
+#define MXT_HOVER_CTRL 0x00
+
+/* MXT_SPT_AUXTOUCHCONFIG_T104 */
+#define MXT_AUXTCHCFG_XTCHTHR 2
+#define MXT_AUXTCHCFG_INTTHRX 4
+#define MXT_AUXTCHCFG_YTCHTHR 7
+#define MXT_AUXTCHCFG_INTTHRY 9
+
+/* MXT_SPT_SELFCAPGLOBALCONFIG_T109 */
+#define MXT_SELFCAPCFG_CTRL 0
+#define MXT_SELFCAPCFG_CMD 3
+
+
+/* Defines for Suspend/Resume */
+#define MXT_SUSPEND_STATIC 0
+#define MXT_SUSPEND_DYNAMIC 1
+#define MXT_T7_IDLEACQ_DISABLE 0
+#define MXT_T7_ACTVACQ_DISABLE 0
+#define MXT_T7_ACTV2IDLE_DISABLE 0
+#define MXT_T9_DISABLE 0
+#define MXT_T9_ENABLE 0x83
+#define MXT_T22_DISABLE 0
+#define MXT_T100_DISABLE 0
+
+/* Define for MXT_GEN_COMMAND_T6 */
+#define MXT_RESET_VALUE 0x01
+#define MXT_BACKUP_VALUE 0x55
+
+/* Define for MXT_PROCG_NOISESUPPRESSION_T42 */
+#define MXT_T42_MSG_TCHSUP (1 << 0)
+
+/* Delay times */
+#define MXT_BACKUP_TIME 25 /* msec */
+#define MXT_RESET_TIME 200 /* msec */
+#define MXT_RESET_NOCHGREAD 400 /* msec */
+#define MXT_FWRESET_TIME 1000 /* msec */
+#define MXT_WAKEUP_TIME 25 /* msec */
+
+/* Defines for MXT_SLOWSCAN_EXTENSIONS */
+#define SLOSCAN_DISABLE 0 /* Disable slow scan */
+#define SLOSCAN_ENABLE 1 /* Enable slow scan */
+#define SLOSCAN_SET_ACTVACQINT 2 /* Set ACTV scan rate */
+#define SLOSCAN_SET_IDLEACQINT 3 /* Set IDLE scan rate */
+#define SLOSCAN_SET_ACTV2IDLETO 4 /* Set the ACTIVE to IDLE TimeOut */
+
+/* Command to unlock bootloader */
+#define MXT_UNLOCK_CMD_MSB 0xaa
+#define MXT_UNLOCK_CMD_LSB 0xdc
+
+/* Bootloader mode status */
+#define MXT_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */
+#define MXT_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */
+#define MXT_FRAME_CRC_CHECK 0x02
+#define MXT_FRAME_CRC_FAIL 0x03
+#define MXT_FRAME_CRC_PASS 0x04
+#define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */
+#define MXT_BOOT_STATUS_MASK 0x3f
+#define MXT_BOOT_EXTENDED_ID (1 << 5)
+#define MXT_BOOT_ID_MASK 0x1f
+
+/* Define for T6 status byte */
+#define MXT_STATUS_RESET (1 << 7)
+#define MXT_STATUS_OFL (1 << 6)
+#define MXT_STATUS_SIGERR (1 << 5)
+#define MXT_STATUS_CAL (1 << 4)
+#define MXT_STATUS_CFGERR (1 << 3)
+#define MXT_STATUS_COMSERR (1 << 2)
+
+/* Define for T8 measallow byte */
+#define MXT_MEASALLOW_MULT (1 << 0)
+#define MXT_MEASALLOW_SELT (1 << 1)
+
+/* T9 Touch status */
+#define MXT_T9_UNGRIP (1 << 0)
+#define MXT_T9_SUPPRESS (1 << 1)
+#define MXT_T9_AMP (1 << 2)
+#define MXT_T9_VECTOR (1 << 3)
+#define MXT_T9_MOVE (1 << 4)
+#define MXT_T9_RELEASE (1 << 5)
+#define MXT_T9_PRESS (1 << 6)
+#define MXT_T9_DETECT (1 << 7)
+
+/* T100 Touch status */
+#define MXT_T100_CTRL_RPTEN (1 << 1)
+
+#define MXT_T100_EVENT_NONE 0
+#define MXT_T100_EVENT_MOVE 1
+#define MXT_T100_EVENT_UNSUP 2
+#define MXT_T100_EVENT_SUP 3
+#define MXT_T100_EVENT_DOWN 4
+#define MXT_T100_EVENT_UP 5
+#define MXT_T100_EVENT_UNSUPSUP 6
+#define MXT_T100_EVENT_UNSUPUP 7
+#define MXT_T100_EVENT_DOWNSUP 8
+#define MXT_T100_EVENT_DOWNUP 9
+
+#define MXT_T100_TYPE_RESERVED 0
+#define MXT_T100_TYPE_FINGER 1
+#define MXT_T100_TYPE_PASSIVE_STYLUS 2
+#define MXT_T100_TYPE_ACTIVE_STYLUS 3
+#define MXT_T100_TYPE_HOVERING_FINGER 4
+#define MXT_T100_TYPE_HOVERING_GLOVE 5
+
+#define MXT_T100_DETECT (1 << 7)
+#define MXT_T100_VECT (1 << 0)
+#define MXT_T100_AMPL (1 << 1)
+#define MXT_T100_AREA (1 << 2)
+#define MXT_T100_PEAK (1 << 4)
+
+#define MXT_T100_SUP (1 << 6)
+
+/* T15 KeyArray */
+#define MXT_KEY_RPTEN (1 << 1)
+#define MXT_KEY_ADAPTTHREN (1 << 2)
+
+/* Touch orient bits */
+#define MXT_XY_SWITCH (1 << 0)
+#define MXT_X_INVERT (1 << 1)
+#define MXT_Y_INVERT (1 << 2)
+
+/* T47 passive stylus */
+#define MXT_PSTYLUS_ENABLE (1 << 0)
+
+/* T63 Stylus */
+#define MXT_STYLUS_PRESS (1 << 0)
+#define MXT_STYLUS_RELEASE (1 << 1)
+#define MXT_STYLUS_MOVE (1 << 2)
+#define MXT_STYLUS_SUPPRESS (1 << 3)
+
+#define MXT_STYLUS_DETECT (1 << 4)
+#define MXT_STYLUS_TIP (1 << 5)
+#define MXT_STYLUS_ERASER (1 << 6)
+#define MXT_STYLUS_BARREL (1 << 7)
+
+#define MXT_STYLUS_PRESSURE_MASK 0x3F
+
+/* Touchscreen absolute values */
+#define MXT_MAX_AREA 0xff
+
+/* T66 Golden Reference */
+#define MXT_GOLDENREF_CTRL 0x00
+#define MXT_GOLDENREF_FCALFAILTHR 0x01
+#define MXT_GOLDENREF_FCALDRIFTCNT 0x02
+#define MXT_GOLDENREF_FCALDRIFTCOEF 0x03
+#define MXT_GOLDENREF_FCALDRIFTTLIM 0x04
+
+#define MXT_GOLDCTRL_ENABLE (1 << 0)
+#define MXT_GOLDCTRL_REPEN (1 << 1)
+
+#define MXT_GOLDSTS_BADSTOREDATA (1 << 0)
+#define MXT_GOLDSTS_FCALSEQERR (1 << 3)
+#define MXT_GOLDSTS_FCALSEQTO (1 << 4)
+#define MXT_GOLDSTS_FCALSEQDONE (1 << 5)
+#define MXT_GOLDSTS_FCALPASS (1 << 6)
+#define MXT_GOLDSTS_FCALFAIL (1 << 7)
+
+#define MXT_GOLDCMD_NONE 0x00
+#define MXT_GOLDCMD_PRIME 0x04
+#define MXT_GOLDCMD_GENERATE 0x08
+#define MXT_GOLDCMD_CONFIRM 0x0C
+
+#define MXT_GOLD_CMD_MASK 0x0C
+
+#define MXT_GOLDSTATE_INVALID 0xFF
+#define MXT_GOLDSTATE_IDLE MXT_GOLDSTS_FCALSEQDONE
+#define MXT_GOLDSTATE_PRIME 0x02
+#define MXT_GOLDSTATE_GEN 0x04
+#define MXT_GOLDSTATE_GEN_PASS (0x04 | MXT_GOLDSTS_FCALPASS)
+#define MXT_GOLDSTATE_GEN_FAIL (0x04 | MXT_GOLDSTS_FCALFAIL)
+
+#define MXT_GOLD_STATE_MASK 0x06
+
+/* T78 glove setting */
+#define MXT_GLOVECTL_ALL_ENABLE 0xB9
+#define MXT_GLOVECTL_GAINEN (1 << 4)
+
+/* T80 retransmission */
+#define MXT_RETRANS_CTRL 0x0
+#define MXT_RETRANS_ATCHTHR 0x4
+#define MXT_RETRANS_CTRL_MOISTCALEN (1 << 4)
+
+/* T81 gesture */
+#define MXT_GESTURE_CTRL 0x0
+
+/* T72 noise suppression */
+#define MXT_NOICTRL_ENABLE (1 << 0)
+#define MXT_NOICFG_VNOISY (1 << 1)
+#define MXT_NOICFG_NOISY (1 << 0)
+
+/* T109 self-cap */
+#define MXT_SELFCTL_RPTEN 0x2
+#define MXT_SELFCMD_TUNE 0x1
+#define MXT_SELFCMD_STM_TUNE 0x2
+#define MXT_SELFCMD_AFN_TUNE 0x3
+#define MXT_SELFCMD_STCR_TUNE 0x4
+#define MXT_SELFCMD_AFCR_TUNE 0x5
+#define MXT_SELFCMD_AFNVMSTCR_TUNE 0x6
+#define MXT_SELFCMD_RCR_TUNE 0x7
+
+#define MXT_DEBUGFS_DIR "atmel_mxt_ts"
+#define MXT_DEBUGFS_FILE "object"
+
+
+#define MXT_INPUT_EVENT_START 0
+#define MXT_INPUT_EVENT_SENSITIVE_MODE_OFF 0
+#define MXT_INPUT_EVENT_SENSITIVE_MODE_ON 1
+#define MXT_INPUT_EVENT_STYLUS_MODE_OFF 2
+#define MXT_INPUT_EVENT_STYLUS_MODE_ON 3
+#define MXT_INPUT_EVENT_WAKUP_MODE_OFF 4
+#define MXT_INPUT_EVENT_WAKUP_MODE_ON 5
+#define MXT_INPUT_EVENT_END 5
+
+#define MXT_MAX_FINGER_NUM 16
+#define BOOTLOADER_1664_1188 1
+
+struct mxt_info {
+ u8 family_id;
+ u8 variant_id;
+ u8 version;
+ u8 build;
+ u8 matrix_xsize;
+ u8 matrix_ysize;
+ u8 object_num;
+};
+
+struct mxt_object {
+ u8 type;
+ u16 start_address;
+ u16 size;
+ u16 instances;
+ u8 num_report_ids;
+
+ /* to map object and message */
+ u8 min_reportid;
+ u8 max_reportid;
+};
+
+enum mxt_device_state { INIT, APPMODE, BOOTLOADER, FAILED, SHUTDOWN };
+
+/* This structure is used to save/restore values during suspend/resume */
+struct mxt_suspend {
+ u8 suspend_obj;
+ u8 suspend_reg;
+ u8 suspend_val;
+ u8 suspend_flags;
+ u8 restore_val;
+};
+
+struct mxt_golden_msg {
+ u8 status;
+ u8 fcalmaxdiff;
+ u8 fcalmaxdiffx;
+ u8 fcalmaxdiffy;
+};
+
+
+struct mxt_selfcap_status {
+ u8 cmd;
+ u8 error_code;
+};
+
+struct mxt_mode_switch {
+ struct mxt_data *data;
+ u8 mode;
+ struct work_struct switch_mode_work;
+};
+
+/* Each client has this additional data */
+struct mxt_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ const struct mxt_platform_data *pdata;
+ enum mxt_device_state state;
+ struct mxt_object *object_table;
+ struct regulator *regulator_vdd;
+ struct regulator *regulator_avdd;
+ struct regulator *regulator_vddio;
+ u16 mem_size;
+ struct mxt_info info;
+ unsigned int irq;
+ unsigned int max_x;
+ unsigned int max_y;
+ struct bin_attribute mem_access_attr;
+ bool debug_enabled;
+ bool driver_paused;
+ u8 bootloader_addr;
+ u8 actv_cycle_time;
+ u8 idle_cycle_time;
+ u8 actv2idle_timeout;
+ u8 is_stopped;
+ u8 max_reportid;
+ u32 config_crc;
+ u32 info_block_crc;
+ u8 num_touchids;
+ u8 num_stylusids;
+ u8 *msg_buf;
+ u8 last_message_count;
+ u8 t100_tchaux_bits;
+ unsigned long keystatus;
+ u8 vendor_id;
+ u8 rev_id;
+ int current_index;
+ u8 update_flag;
+ u8 test_result[6];
+ int touch_num;
+ u8 diag_mode;
+ u8 atchthr;
+ u8 sensitive_mode;
+ u8 stylus_mode;
+ u8 wakeup_gesture_mode;
+ bool is_wakeup_by_gesture;
+ int hover_tune_status;
+ struct delayed_work calibration_delayed_work;
+ u8 adcperx_normal[10];
+ u8 adcperx_wakeup[10];
+ bool irq_enabled;
+ u8 lockdown_info[MXT_LOCKDOWN_SIZE];
+ u8 userdata_info[MXT_USERDATA_SIZE];
+ bool firmware_updated;
+ bool keys_off;
+
+ /* Slowscan parameters */
+ int slowscan_enabled;
+ u8 slowscan_actv_cycle_time;
+ u8 slowscan_idle_cycle_time;
+ u8 slowscan_actv2idle_timeout;
+ u8 slowscan_shad_actv_cycle_time;
+ u8 slowscan_shad_idle_cycle_time;
+ u8 slowscan_shad_actv2idle_timeout;
+ struct mxt_golden_msg golden_msg;
+ struct mxt_selfcap_status selfcap_status;
+ struct work_struct self_tuning_work;
+ struct work_struct hover_loading_work;
+ bool finger_down[MXT_MAX_FINGER_NUM];
+
+ /* Cached parameters from object table */
+ u16 T5_address;
+ u8 T5_msg_size;
+ u8 T6_reportid;
+ u16 T7_address;
+ u8 T9_reportid_min;
+ u8 T9_reportid_max;
+ u8 T15_reportid_min;
+ u8 T15_reportid_max;
+ u8 T19_reportid_min;
+ u8 T19_reportid_max;
+ u8 T25_reportid_min;
+ u8 T25_reportid_max;
+ u16 T37_address;
+ u8 T42_reportid_min;
+ u8 T42_reportid_max;
+ u16 T44_address;
+ u8 T48_reportid;
+ u8 T63_reportid_min;
+ u8 T63_reportid_max;
+ u8 T66_reportid;
+ u8 T81_reportid_min;
+ u8 T81_reportid_max;
+ u8 T92_reportid_min;
+ u8 T92_reportid_max;
+ u8 T100_reportid_min;
+ u8 T100_reportid_max;
+ u8 T109_reportid;
+
+#ifdef CONFIG_FB
+ struct notifier_block fb_notif;
+#endif
+};
+
+static struct mxt_suspend mxt_save[] = {
+ {MXT_GEN_POWER_T7, MXT_POWER_IDLEACQINT,
+ MXT_T7_IDLEACQ_DISABLE, MXT_SUSPEND_DYNAMIC, 0},
+ {MXT_GEN_POWER_T7, MXT_POWER_ACTVACQINT,
+ MXT_T7_ACTVACQ_DISABLE, MXT_SUSPEND_DYNAMIC, 0},
+ {MXT_GEN_POWER_T7, MXT_POWER_ACTV2IDLETO,
+ MXT_T7_ACTV2IDLE_DISABLE, MXT_SUSPEND_DYNAMIC, 0}
+};
+
+/* I2C slave address pairs */
+struct mxt_i2c_address_pair {
+ u8 bootloader;
+ u8 application;
+};
+
+static const struct mxt_i2c_address_pair mxt_i2c_addresses[] = {
+#ifdef BOOTLOADER_1664_1188
+ { 0x26, 0x4a },
+ { 0x27, 0x4b },
+#else
+ { 0x24, 0x4a },
+ { 0x25, 0x4b },
+ { 0x26, 0x4c },
+ { 0x27, 0x4d },
+ { 0x34, 0x5a },
+ { 0x35, 0x5b },
+#endif
+};
+
+static struct gpiomux_setting mxt_rst_cutoff_pwr_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting mxt_int_cutoff_pwr_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static ssize_t mxt_update_firmware(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count, bool *upgraded);
+
+static int mxt_bootloader_read(struct mxt_data *data, u8 *val, unsigned int count)
+{
+ int ret;
+ struct i2c_msg msg;
+
+ msg.addr = data->bootloader_addr;
+ msg.flags = data->client->flags & I2C_M_TEN;
+ msg.flags |= I2C_M_RD;
+ msg.len = count;
+ msg.buf = val;
+
+ ret = i2c_transfer(data->client->adapter, &msg, 1);
+
+ return (ret == 1) ? 0 : ret;
+}
+
+static int mxt_bootloader_write(struct mxt_data *data, const u8 * const val,
+ unsigned int count)
+{
+ int ret;
+ struct i2c_msg msg;
+
+ msg.addr = data->bootloader_addr;
+ msg.flags = data->client->flags & I2C_M_TEN;
+ msg.len = count;
+ msg.buf = (u8 *)val;
+
+ ret = i2c_transfer(data->client->adapter, &msg, 1);
+
+ return (ret == 1) ? 0 : ret;
+}
+
+static int mxt_get_bootloader_address(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mxt_i2c_addresses); i++) {
+ if (mxt_i2c_addresses[i].application == client->addr) {
+ data->bootloader_addr = mxt_i2c_addresses[i].bootloader;
+
+ dev_info(&client->dev, "Bootloader i2c addr: 0x%02x\n",
+ data->bootloader_addr);
+
+ return 0;
+ }
+ }
+
+ dev_err(&client->dev, "Address 0x%02x not found in address table\n",
+ client->addr);
+ return -EINVAL;
+}
+
+static int mxt_probe_bootloader(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+ u8 val;
+ bool crc_failure;
+
+ ret = mxt_get_bootloader_address(data);
+ if (ret)
+ return ret;
+
+ ret = mxt_bootloader_read(data, &val, 1);
+ if (ret) {
+ dev_err(dev, "%s: i2c recv failed\n", __func__);
+ return -EIO;
+ }
+
+ /* Check app crc fail mode */
+ crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL;
+
+ dev_err(dev, "Detected bootloader, status:%02X%s\n",
+ val, crc_failure ? ", APP_CRC_FAIL" : "");
+
+ return 0;
+}
+
+static u8 mxt_read_chg(struct mxt_data *data)
+{
+ int gpio_intr = data->pdata->irq_gpio;
+
+ u8 val = (u8)gpio_get_value(gpio_intr);
+ return val;
+}
+
+static void mxt_disable_irq(struct mxt_data *data)
+{
+ if (likely(data->irq_enabled)) {
+ disable_irq(data->irq);
+ data->irq_enabled = false;
+ }
+}
+
+static void mxt_enable_irq(struct mxt_data *data)
+{
+ if (likely(!data->irq_enabled)) {
+ enable_irq(data->irq);
+ data->irq_enabled = true;
+ }
+}
+
+static int mxt_wait_for_chg(struct mxt_data *data)
+{
+ int timeout_counter = 0;
+ int count = 10;
+
+ while ((timeout_counter++ <= count) && mxt_read_chg(data))
+ mdelay(10);
+
+ if (timeout_counter > count) {
+ dev_err(&data->client->dev, "mxt_wait_for_chg() timeout!\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val)
+{
+ struct device *dev = &data->client->dev;
+ u8 buf[3];
+
+ if (val & MXT_BOOT_EXTENDED_ID) {
+ if (mxt_bootloader_read(data, &buf[0], 3) != 0) {
+ dev_err(dev, "%s: i2c failure\n", __func__);
+ return -EIO;
+ }
+
+ dev_info(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]);
+
+ return buf[0];
+ } else {
+ dev_info(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK);
+
+ return val;
+ }
+}
+
+static int mxt_check_bootloader(struct mxt_data *data,
+ unsigned int state)
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+ u8 val;
+
+recheck:
+ ret = mxt_bootloader_read(data, &val, 1);
+ if (ret) {
+ dev_err(dev, "%s: i2c recv failed, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (state == MXT_WAITING_BOOTLOAD_CMD) {
+ val = mxt_get_bootloader_version(data, val);
+ }
+
+ switch (state) {
+ case MXT_WAITING_BOOTLOAD_CMD:
+ val &= ~MXT_BOOT_STATUS_MASK;
+ break;
+ case MXT_WAITING_FRAME_DATA:
+ case MXT_APP_CRC_FAIL:
+ val &= ~MXT_BOOT_STATUS_MASK;
+ break;
+ case MXT_FRAME_CRC_PASS:
+ if (val == MXT_FRAME_CRC_CHECK) {
+ mxt_wait_for_chg(data);
+ goto recheck;
+ } else if (val == MXT_FRAME_CRC_FAIL) {
+ dev_err(dev, "Bootloader CRC fail\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (val != state) {
+ dev_err(dev, "Invalid bootloader mode state 0x%02X\n", val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
+{
+ int ret;
+ u8 buf[2];
+
+ if (unlock) {
+ buf[0] = MXT_UNLOCK_CMD_LSB;
+ buf[1] = MXT_UNLOCK_CMD_MSB;
+ } else {
+ buf[0] = 0x01;
+ buf[1] = 0x01;
+ }
+
+ ret = mxt_bootloader_write(data, buf, 2);
+ if (ret) {
+ dev_err(&data->client->dev, "%s: i2c send failed, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mxt_read_reg(struct i2c_client *client,
+ u16 reg, u16 len, void *val)
+{
+ struct device *dev = &client->dev;
+ struct i2c_msg xfer[2];
+ u8 buf[2];
+ int ret;
+
+ buf[0] = reg & 0xff;
+ buf[1] = (reg >> 8) & 0xff;
+
+ /* Write register */
+ xfer[0].addr = client->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = 2;
+ xfer[0].buf = buf;
+
+ /* Read data */
+ xfer[1].addr = client->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = len;
+ xfer[1].buf = val;
+
+ ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer));
+ if (ret != ARRAY_SIZE(xfer)) {
+ dev_err(dev, "%s: i2c transfer failed (%d)\n",
+ __func__, ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
+{
+ struct device *dev = &client->dev;
+ u8 buf[3];
+
+ buf[0] = reg & 0xff;
+ buf[1] = (reg >> 8) & 0xff;
+ buf[2] = val;
+
+ if (i2c_master_send(client, buf, 3) != 3) {
+ dev_err(dev, "%s: i2c send failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int mxt_write_block(struct i2c_client *client, u16 addr, u16 length, u8 *value)
+{
+ int i;
+ struct {
+ __le16 le_addr;
+ u8 data[MXT_MAX_BLOCK_WRITE];
+ } i2c_block_transfer;
+
+ if (length > MXT_MAX_BLOCK_WRITE)
+ return -EINVAL;
+
+ memcpy(i2c_block_transfer.data, value, length);
+
+ i2c_block_transfer.le_addr = cpu_to_le16(addr);
+
+ i = i2c_master_send(client, (u8 *) &i2c_block_transfer, length + 2);
+
+ if (i == (length + 2))
+ return 0;
+ else
+ return -EIO;
+}
+
+static struct mxt_object *mxt_get_object(struct mxt_data *data, u8 type)
+{
+ struct mxt_object *object;
+ int i;
+
+ for (i = 0; i < data->info.object_num; i++) {
+ object = data->object_table + i;
+ if (object->type == type)
+ return object;
+ }
+
+ dev_err(&data->client->dev, "Invalid object type T%u\n", type);
+ return NULL;
+}
+
+static int mxt_read_object(struct mxt_data *data,
+ u8 type, u8 offset, u8 *val)
+{
+ struct mxt_object *object;
+ u16 reg;
+
+ object = mxt_get_object(data, type);
+ if (!object)
+ return -EINVAL;
+
+ reg = object->start_address;
+ if (data->debug_enabled)
+ dev_info(&data->client->dev, "read from object %d, reg 0x%02x, val 0x%x\n",
+ (int)type, reg + offset, *val);
+ return mxt_read_reg(data->client, reg + offset, 1, val);
+}
+
+static int mxt_write_object(struct mxt_data *data,
+ u8 type, u8 offset, u8 val)
+{
+ struct mxt_object *object;
+ u16 reg;
+ int ret;
+
+ object = mxt_get_object(data, type);
+ if (!object || offset >= object->size)
+ return -EINVAL;
+
+ if (offset >= object->size * object->instances) {
+ dev_err(&data->client->dev, "Tried to write outside object T%d"
+ " offset:%d, size:%d\n", type, offset, object->size);
+ return -EINVAL;
+ }
+
+ reg = object->start_address;
+ if (data->debug_enabled)
+ dev_info(&data->client->dev, "write to object %d, reg 0x%02x, val 0x%x\n",
+ (int)type, reg + offset, val);
+ ret = mxt_write_reg(data->client, reg + offset, val);
+
+ return ret;
+}
+
+static int mxt_set_clr_reg(struct mxt_data *data,
+ u8 type, u8 offset, u8 mask_s, u8 mask_c)
+{
+ int error;
+ u8 val;
+
+ error = mxt_read_object(data, type, offset, &val);
+ if (error) {
+ dev_err(&data->client->dev,
+ "Failed to read object %d\n", (int)type);
+ return error;
+ }
+
+ val &= ~mask_c;
+ val |= mask_s;
+
+ error = mxt_write_object(data, type, offset, val);
+ if (error)
+ dev_err(&data->client->dev,
+ "Failed to write object %d\n", (int)type);
+ return error;
+}
+
+static int mxt_soft_reset(struct mxt_data *data, u8 value)
+{
+ struct device *dev = &data->client->dev;
+
+ dev_info(dev, "Resetting chip\n");
+
+ mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_RESET, value);
+
+ msleep(MXT_RESET_NOCHGREAD);
+
+ return 0;
+}
+
+static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+ u32 crc;
+ u8 status = msg[1];
+
+ crc = msg[2] | (msg[3] << 8) | (msg[4] << 16);
+
+ if (crc != data->config_crc) {
+ data->config_crc = crc;
+ dev_dbg(dev, "T6 cfg crc 0x%06X\n", crc);
+ }
+
+ if (status & MXT_STATUS_CAL) {
+ dev_info(dev, "Calibration start!\n");
+ }
+
+ if (status)
+ dev_dbg(dev, "T6 status %s%s%s%s%s%s\n",
+ (status & MXT_STATUS_RESET) ? "RESET " : "",
+ (status & MXT_STATUS_OFL) ? "OFL " : "",
+ (status & MXT_STATUS_SIGERR) ? "SIGERR " : "",
+ (status & MXT_STATUS_CAL) ? "CAL " : "",
+ (status & MXT_STATUS_CFGERR) ? "CFGERR " : "",
+ (status & MXT_STATUS_COMSERR) ? "COMSERR " : "");
+}
+
+static void mxt_input_sync(struct mxt_data *data)
+{
+ input_mt_report_pointer_emulation(data->input_dev, false);
+ input_sync(data->input_dev);
+}
+
+static void mxt_proc_t9_messages(struct mxt_data *data, u8 *message)
+{
+ struct device *dev = &data->client->dev;
+ struct input_dev *input_dev = data->input_dev;
+ u8 status;
+ int x;
+ int y;
+ int area;
+ int amplitude;
+ u8 vector;
+ int id;
+
+ if (!input_dev || data->driver_paused)
+ return;
+
+ id = message[0] - data->T9_reportid_min;
+
+ if (id < 0 || id > data->num_touchids) {
+ dev_err(dev, "invalid touch id %d, total num touch is %d\n",
+ id, data->num_touchids);
+ return;
+ }
+
+ status = message[1];
+
+ x = (message[2] << 4) | ((message[4] >> 4) & 0xf);
+ y = (message[3] << 4) | ((message[4] & 0xf));
+ if (data->max_x < 1024)
+ x >>= 2;
+ if (data->max_y < 1024)
+ y >>= 2;
+ area = message[5];
+ amplitude = message[6];
+ vector = message[7];
+
+ dev_dbg(dev,
+ "[%d] %c%c%c%c%c%c%c%c x: %d y: %d area: %d amp: %d vector: %02X\n",
+ id,
+ (status & MXT_T9_DETECT) ? 'D' : '.',
+ (status & MXT_T9_PRESS) ? 'P' : '.',
+ (status & MXT_T9_RELEASE) ? 'R' : '.',
+ (status & MXT_T9_MOVE) ? 'M' : '.',
+ (status & MXT_T9_VECTOR) ? 'V' : '.',
+ (status & MXT_T9_AMP) ? 'A' : '.',
+ (status & MXT_T9_SUPPRESS) ? 'S' : '.',
+ (status & MXT_T9_UNGRIP) ? 'U' : '.',
+ x, y, area, amplitude, vector);
+
+ input_mt_slot(input_dev, id);
+
+ if ((status & MXT_T9_DETECT) && (status & MXT_T9_RELEASE)) {
+ /* Touch in detect, just after being released, so
+ * get new touch tracking ID */
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+ mxt_input_sync(data);
+ }
+
+ if (status & MXT_T9_DETECT) {
+ /* Touch in detect, report X/Y position */
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
+
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
+ input_report_abs(input_dev, ABS_MT_ORIENTATION, vector);
+ } else {
+ /* Touch no longer in detect, so close out slot */
+ mxt_input_sync(data);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+ }
+}
+
+static int mxt_do_diagnostic(struct mxt_data *data, u8 mode)
+{
+ int error = 0;
+ u8 val;
+ int time_out = 500;
+ int i = 0;
+
+ error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_DIAGNOSTIC, mode);
+ if (error) {
+ dev_err(&data->client->dev, "Failed to diag ref data value\n");
+ return error;
+ }
+
+ while(i < time_out) {
+ error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_DIAGNOSTIC, &val);
+ if (error) {
+ dev_err(&data->client->dev, "Failed to diag ref data value\n");
+ return error;
+ }
+ if (val == 0)
+ return 0;
+ i++;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static void mxt_set_t7_for_gesture(struct mxt_data *data, bool enable);
+static void mxt_set_gesture_wake_up(struct mxt_data *data, bool enable);
+
+static void mxt_proc_t100_messages(struct mxt_data *data, u8 *message)
+{
+ struct device *dev = &data->client->dev;
+ struct input_dev *input_dev = data->input_dev;
+ u8 status, touch_type, touch_event;
+ int x;
+ int y;
+ int area = 0;
+ int amplitude = 0;
+ u8 vector = 0;
+ u8 peak = 0;
+ int id;
+ int index = 0;
+
+ if (!input_dev || data->driver_paused)
+ return;
+
+ id = message[0] - data->T100_reportid_min;
+
+ if (id < 0 || id > data->num_touchids) {
+ dev_err(dev, "invalid touch id %d, total num touch is %d\n",
+ id, data->num_touchids);
+ return;
+ }
+
+ if (id == 0) {
+ status = message[1];
+ data->touch_num = message[2];
+ if (data->debug_enabled)
+ dev_info(dev, "touch num = %d\n", data->touch_num);
+
+ if (status & MXT_T100_SUP)
+ {
+ int i;
+ for (i = 0; i < data->num_touchids - 2; i++) {
+ input_mt_slot(input_dev, i);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+ }
+ mxt_input_sync(data);
+ }
+ }
+ else if (id >= 2) {
+ /* deal with each point report */
+ status = message[1];
+ touch_type = (status & 0x70) >> 4;
+ touch_event = status & 0x0F;
+ x = (message[3] << 8) | (message[2] & 0xFF);
+ y = (message[5] << 8) | (message[4] & 0xFF);
+ index = 6;
+
+ if (data->t100_tchaux_bits & MXT_T100_VECT)
+ vector = message[index++];
+ if (data->t100_tchaux_bits & MXT_T100_AMPL) {
+ amplitude = message[index++];
+ }
+ if (data->t100_tchaux_bits & MXT_T100_AREA) {
+ area = message[index++];
+ }
+ if (data->t100_tchaux_bits & MXT_T100_PEAK)
+ peak = message[index++];
+
+ input_mt_slot(input_dev, id - 2);
+
+ if (status & MXT_T100_DETECT) {
+ if (touch_event == MXT_T100_EVENT_DOWN || touch_event == MXT_T100_EVENT_UNSUP
+ || touch_event == MXT_T100_EVENT_MOVE || touch_event == MXT_T100_EVENT_NONE) {
+ /* Touch in detect, report X/Y position */
+ if (touch_event == MXT_T100_EVENT_DOWN ||
+ touch_event == MXT_T100_EVENT_UNSUP)
+ data->finger_down[id - 2] = true;
+ if ((touch_event == MXT_T100_EVENT_MOVE ||
+ touch_event == MXT_T100_EVENT_NONE) &&
+ !data->finger_down[id - 2])
+ return;
+
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ if (touch_type == MXT_T100_TYPE_HOVERING_FINGER)
+ input_report_abs(input_dev, BTN_TOUCH, 0);
+ else
+ input_report_abs(input_dev, BTN_TOUCH, 1);
+
+ if (data->t100_tchaux_bits & MXT_T100_AMPL) {
+ if (touch_type == MXT_T100_TYPE_HOVERING_FINGER)
+ amplitude = 0;
+ else if (amplitude == 0)
+ amplitude = 1;
+ input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
+ }
+ if (data->t100_tchaux_bits & MXT_T100_AREA) {
+ if (touch_type == MXT_T100_TYPE_HOVERING_FINGER)
+ area = 0;
+ else if (area == 0)
+ area = 1;
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
+ }
+ if (data->t100_tchaux_bits & MXT_T100_VECT)
+ input_report_abs(input_dev, ABS_MT_ORIENTATION, vector);
+ }
+ } else {
+ /* Touch no longer in detect, so close out slot */
+ if (data->touch_num == 0 &&
+ data->wakeup_gesture_mode &&
+ data->is_wakeup_by_gesture) {
+ dev_info(dev, "wakeup finger release, restore t7 and t8!\n");
+ data->is_wakeup_by_gesture = false;
+ mxt_set_t7_for_gesture(data, false);
+ }
+ mxt_input_sync(data);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+ data->finger_down[id - 2] = false;
+ }
+ }
+}
+
+static void mxt_proc_t15_messages(struct mxt_data *data, u8 *msg)
+{
+ struct input_dev *input_dev = data->input_dev;
+ struct device *dev = &data->client->dev;
+ const struct mxt_platform_data *pdata = data->pdata;
+ u8 key;
+ bool curr_state, new_state;
+ bool sync = false;
+ unsigned long keystates = le32_to_cpu(msg[2]);
+ int index = data->current_index;
+ if(data->keys_off) {
+ return;
+ }
+
+ for (key = 0; key < pdata->config_array[index].key_num; key++) {
+ curr_state = test_bit(key, &data->keystatus);
+ new_state = test_bit(key, &keystates);
+
+ if (!curr_state && new_state) {
+ dev_dbg(dev, "T15 key press: %u\n", key);
+ __set_bit(key, &data->keystatus);
+ input_event(input_dev, EV_KEY, pdata->config_array[index].key_codes[key], 1);
+ sync = true;
+ } else if (curr_state && !new_state) {
+ dev_dbg(dev, "T15 key release: %u\n", key);
+ __clear_bit(key, &data->keystatus);
+ input_event(input_dev, EV_KEY, pdata->config_array[index].key_codes[key], 0);
+ sync = true;
+ }
+ }
+
+ if (sync)
+ input_sync(input_dev);
+}
+
+static void mxt_proc_t19_messages(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+ const struct mxt_platform_data *pdata = data->pdata;
+
+ if (get_hw_version_major() == 5) {
+ dev_info(dev, "T19 is not used for distinguishing TP vendor in X5\n");
+ return;
+ }
+
+ data->vendor_id = msg[1];
+ data->vendor_id &= pdata->gpio_mask;
+ dev_info(dev, "T19: vendor_id & gpio_mask = 0x%x & 0x%x = 0x%x\n",
+ msg[1], pdata->gpio_mask, data->vendor_id);
+}
+
+static void mxt_proc_t25_messages(struct mxt_data *data, u8 *msg)
+{
+ memcpy(data->test_result,
+ &msg[1], sizeof(data->test_result));
+}
+
+static void mxt_proc_t42_messages(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+ u8 status = msg[1];
+
+ if (status & MXT_T42_MSG_TCHSUP)
+ dev_info(dev, "T42 suppress\n");
+ else
+ dev_info(dev, "T42 normal\n");
+}
+
+static int mxt_proc_t48_messages(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+ u8 status, state;
+
+ status = msg[1];
+ state = msg[4];
+
+ dev_dbg(dev, "T48 state %d status %02X %s%s%s%s%s\n",
+ state,
+ status,
+ (status & 0x01) ? "FREQCHG " : "",
+ (status & 0x02) ? "APXCHG " : "",
+ (status & 0x04) ? "ALGOERR " : "",
+ (status & 0x10) ? "STATCHG " : "",
+ (status & 0x20) ? "NLVLCHG " : "");
+
+ return 0;
+}
+
+static void mxt_proc_t63_messages(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+ struct input_dev *input_dev = data->input_dev;
+ u8 id;
+ u16 x, y;
+ u8 pressure;
+
+ if (!input_dev)
+ return;
+
+ /* stylus slots come after touch slots */
+ id = data->num_touchids + (msg[0] - data->T63_reportid_min);
+
+ if (id < 0 || id > (data->num_touchids + data->num_stylusids)) {
+ dev_err(dev, "invalid stylus id %d, max slot is %d\n",
+ id, data->num_stylusids);
+ return;
+ }
+
+ x = msg[3] | (msg[4] << 8);
+ y = msg[5] | (msg[6] << 8);
+ pressure = msg[7] & MXT_STYLUS_PRESSURE_MASK;
+
+ dev_dbg(dev,
+ "[%d] %c%c%c%c x: %d y: %d pressure: %d stylus:%c%c%c%c\n",
+ id,
+ (msg[1] & MXT_STYLUS_SUPPRESS) ? 'S' : '.',
+ (msg[1] & MXT_STYLUS_MOVE) ? 'M' : '.',
+ (msg[1] & MXT_STYLUS_RELEASE) ? 'R' : '.',
+ (msg[1] & MXT_STYLUS_PRESS) ? 'P' : '.',
+ x, y, pressure,
+ (msg[2] & MXT_STYLUS_BARREL) ? 'B' : '.',
+ (msg[2] & MXT_STYLUS_ERASER) ? 'E' : '.',
+ (msg[2] & MXT_STYLUS_TIP) ? 'T' : '.',
+ (msg[2] & MXT_STYLUS_DETECT) ? 'D' : '.');
+
+ input_mt_slot(input_dev, id);
+
+ if (msg[2] & MXT_STYLUS_DETECT) {
+ input_mt_report_slot_state(input_dev, MT_TOOL_PEN, 1);
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
+ } else {
+ input_mt_report_slot_state(input_dev, MT_TOOL_PEN, 0);
+ }
+
+ input_report_key(input_dev, BTN_STYLUS, (msg[2] & MXT_STYLUS_ERASER));
+ input_report_key(input_dev, BTN_STYLUS2, (msg[2] & MXT_STYLUS_BARREL));
+
+ mxt_input_sync(data);
+}
+
+static void mxt_proc_t66_messages(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+
+ dev_info(dev, "message for t66= 0x%x 0x%x 0x%x 0x%x\n",
+ msg[1], msg[2], msg[3], msg[4]);
+
+ data->golden_msg.status = msg[1];
+ data->golden_msg.fcalmaxdiff = msg[2];
+ data->golden_msg.fcalmaxdiffx = msg[3];
+ data->golden_msg.fcalmaxdiffy = msg[4];
+}
+
+static void mxt_proc_t81_message(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+ struct input_dev *input_dev = data->input_dev;
+
+ dev_info(dev, "msg for t81 = 0x%x 0x%x\n",
+ msg[0], msg[1]);
+
+ if (data->is_stopped) {
+ data->is_wakeup_by_gesture = true;
+ input_event(input_dev, EV_KEY, KEY_POWER, 1);
+ input_sync(input_dev);
+ input_event(input_dev, EV_KEY, KEY_POWER, 0);
+ input_sync(input_dev);
+ }
+}
+
+static void mxt_proc_t92_message(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+
+ dev_info(dev, "msg for t92 = 0x%x 0x%x\n",
+ msg[0], msg[1]);
+
+ /* we can do something to handle wakeup gesture */
+}
+
+static void mxt_proc_t109_messages(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+
+ dev_info(dev, "msg for t109 = 0x%x 0x%x\n",
+ msg[1], msg[2]);
+
+ data->selfcap_status.cmd = msg[1];
+ data->selfcap_status.error_code = msg[2];
+}
+
+static int mxt_proc_message(struct mxt_data *data, u8 *msg)
+{
+ u8 report_id = msg[0];
+
+ if (report_id == MXT_RPTID_NOMSG)
+ return -1;
+
+ if (data->debug_enabled)
+ print_hex_dump(KERN_DEBUG, "MXT MSG:", DUMP_PREFIX_NONE, 16, 1,
+ msg, data->T5_msg_size, false);
+
+ if (report_id >= data->T9_reportid_min
+ && report_id <= data->T9_reportid_max) {
+ mxt_proc_t9_messages(data, msg);
+ } else if (report_id >= data->T63_reportid_min
+ && report_id <= data->T63_reportid_max) {
+ mxt_proc_t63_messages(data, msg);
+ } else if (report_id >= data->T15_reportid_min
+ && report_id <= data->T15_reportid_max) {
+ mxt_proc_t15_messages(data, msg);
+ } else if (report_id >= data->T19_reportid_min
+ && report_id <= data->T19_reportid_max) {
+ mxt_proc_t19_messages(data, msg);
+ } else if (report_id >= data->T25_reportid_min
+ && report_id <= data->T25_reportid_max) {
+ mxt_proc_t25_messages(data, msg);
+ } else if (report_id == data->T6_reportid) {
+ mxt_proc_t6_messages(data, msg);
+ } else if (report_id == data->T48_reportid) {
+ mxt_proc_t48_messages(data, msg);
+ } else if (report_id >= data->T42_reportid_min
+ && report_id <= data->T42_reportid_max) {
+ mxt_proc_t42_messages(data, msg);
+ } else if (report_id == data->T66_reportid) {
+ mxt_proc_t66_messages(data, msg);
+ } else if (report_id >= data->T81_reportid_min
+ && report_id <= data->T81_reportid_max) {
+ mxt_proc_t81_message(data, msg);
+ } else if (report_id >= data->T92_reportid_min
+ && report_id <= data->T92_reportid_max) {
+ mxt_proc_t92_message(data, msg);
+ } else if (report_id >= data->T100_reportid_min
+ && report_id <= data->T100_reportid_max) {
+ mxt_proc_t100_messages(data, msg);
+ } else if (report_id == data->T109_reportid) {
+ mxt_proc_t109_messages(data, msg);
+ }
+
+ return 0;
+}
+
+static int mxt_read_count_messages(struct mxt_data *data, u8 count)
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+ int i;
+ u8 num_valid = 0;
+
+ /* Safety check for msg_buf */
+ if (count > data->max_reportid)
+ return -EINVAL;
+
+ /* Process remaining messages if necessary */
+ ret = mxt_read_reg(data->client, data->T5_address,
+ data->T5_msg_size * count, data->msg_buf);
+ if (ret) {
+ dev_err(dev, "Failed to read %u messages (%d)\n", count, ret);
+ return ret;
+ }
+
+ for (i = 0; i < count; i++) {
+ ret = mxt_proc_message(data,
+ data->msg_buf + data->T5_msg_size * i);
+
+ if (ret == 0)
+ num_valid++;
+ else
+ break;
+ }
+
+ /* return number of messages read */
+ return num_valid;
+}
+
+static irqreturn_t mxt_read_messages_t44(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+ u8 count, num_left;
+
+ /* Read T44 and T5 together */
+ ret = mxt_read_reg(data->client, data->T44_address,
+ data->T5_msg_size + 1, data->msg_buf);
+ if (ret) {
+ dev_err(dev, "Failed to read T44 and T5 (%d)\n", ret);
+ return IRQ_NONE;
+ }
+
+ count = data->msg_buf[0];
+
+ if (count == 0) {
+ dev_warn(dev, "Interrupt triggered but zero messages\n");
+ return IRQ_NONE;
+ } else if (count > data->max_reportid) {
+ dev_err(dev, "T44 count exceeded max report id\n");
+ count = data->max_reportid;
+ }
+
+ /* Process first message */
+ ret = mxt_proc_message(data, data->msg_buf + 1);
+ if (ret < 0) {
+ dev_warn(dev, "Unexpected invalid message\n");
+ return IRQ_NONE;
+ }
+
+ num_left = count - 1;
+
+ /* Process remaining messages if necessary */
+ if (num_left) {
+ ret = mxt_read_count_messages(data, num_left);
+ if (ret < 0) {
+ mxt_input_sync(data);
+ return IRQ_NONE;
+ } else if (ret != num_left) {
+ dev_warn(dev, "Unexpected invalid message\n");
+ }
+ }
+
+ mxt_input_sync(data);
+
+ return IRQ_HANDLED;
+}
+
+static int mxt_read_t9_messages_until_invalid(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int count, read;
+ u8 tries = 2;
+
+ count = data->max_reportid;
+
+ /* Read messages until we force an invalid */
+ do {
+ read = mxt_read_count_messages(data, count);
+ if (read < count)
+ return 0;
+ } while (--tries);
+
+ dev_err(dev, "CHG pin isn't cleared\n");
+ return -EBUSY;
+}
+
+static irqreturn_t mxt_read_t9_messages(struct mxt_data *data)
+{
+ int total_handled, num_handled;
+ u8 count = data->last_message_count;
+
+ if (count < 1 || count > data->max_reportid)
+ count = 1;
+
+ /* include final invalid message */
+ total_handled = mxt_read_count_messages(data, count + 1);
+ if (total_handled < 0)
+ return IRQ_NONE;
+ /* if there were invalid messages, then we are done */
+ else if (total_handled <= count)
+ goto update_count;
+
+ /* read two at a time until an invalid message or else we reach
+ * reportid limit */
+ do {
+ num_handled = mxt_read_count_messages(data, 2);
+ if (num_handled < 0)
+ return IRQ_NONE;
+
+ total_handled += num_handled;
+
+ if (num_handled < 2)
+ break;
+ } while (total_handled < data->num_touchids);
+
+update_count:
+ data->last_message_count = total_handled;
+ mxt_input_sync(data);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mxt_interrupt(int irq, void *dev_id)
+{
+ struct mxt_data *data = dev_id;
+
+ if (data->T44_address)
+ return mxt_read_messages_t44(data);
+ else
+ return mxt_read_t9_messages(data);
+}
+
+static void mxt_read_current_crc(struct mxt_data *data)
+{
+ /* CRC has already been read */
+ if (data->config_crc > 0)
+ return;
+
+ mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_REPORTALL, 1);
+
+ msleep(30);
+
+ /* Read all messages until invalid, this will update the
+ config crc stored in mxt_data */
+ mxt_read_t9_messages_until_invalid(data);
+
+ /* on failure, CRC is set to 0 and config will always be downloaded */
+}
+
+static int mxt_download_config(struct mxt_data *data, const char *fn)
+{
+ struct device *dev = &data->client->dev;
+ struct mxt_info cfg_info;
+ struct mxt_object *object;
+ const struct firmware *cfg = NULL;
+ int ret;
+ int offset;
+ int data_pos;
+ int byte_offset;
+ int i;
+ int config_start_offset;
+ u32 info_crc, config_crc;
+ u8 *config_mem;
+ size_t config_mem_size;
+ unsigned int type, instance, size;
+ u8 val;
+ u16 reg;
+ int add_num = 0;
+
+ ret = request_firmware(&cfg, fn, dev);
+ if (ret < 0) {
+ dev_err(dev, "Failure to request config file %s\n", fn);
+ return 0;
+ }
+
+ mxt_read_current_crc(data);
+
+ if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
+ dev_err(dev, "Unrecognised config file\n");
+ ret = -EINVAL;
+ goto release;
+ }
+
+ data_pos = strlen(MXT_CFG_MAGIC);
+
+ /* Load information block and check */
+ for (i = 0; i < sizeof(struct mxt_info); i++) {
+ ret = sscanf(cfg->data + data_pos, "%hhx%n",
+ (unsigned char *)&cfg_info + i,
+ &offset);
+ if (ret != 1) {
+ dev_err(dev, "Bad format\n");
+ ret = -EINVAL;
+ goto release;
+ }
+
+ data_pos += offset;
+ }
+
+ /* Read CRCs */
+ ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset);
+ if (ret != 1) {
+ dev_err(dev, "Bad format\n");
+ ret = -EINVAL;
+ goto release;
+ }
+ data_pos += offset;
+
+ ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset);
+ if (ret != 1) {
+ dev_err(dev, "Bad format\n");
+ ret = -EINVAL;
+ goto release;
+ }
+ data_pos += offset;
+
+ /* The Info Block CRC is calculated over mxt_info and the object table
+ * If it does not match then we are trying to load the configuration
+ * from a different chip or firmware version, so the configuration CRC
+ * is invalid anyway. */
+ if (info_crc == data->info_block_crc) {
+ if (config_crc == 0 || data->config_crc == 0) {
+ dev_info(dev, "CRC zero, attempting to apply config\n");
+ } else if (config_crc == data->config_crc) {
+ dev_info(dev, "Config CRC 0x%06X: OK\n", data->config_crc);
+ ret = 0;
+ goto release;
+ } else {
+ dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
+ data->config_crc, config_crc);
+ }
+ } else {
+ dev_warn(dev, "Info block CRC mismatch - attempting to apply config\n");
+ }
+
+ /* Malloc memory to store configuration */
+ config_start_offset = MXT_OBJECT_START
+ + data->info.object_num * MXT_OBJECT_SIZE;
+ config_mem_size = data->mem_size - config_start_offset;
+ config_mem = kzalloc(config_mem_size, GFP_KERNEL);
+ if (!config_mem) {
+ dev_err(dev, "Failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ while (data_pos < cfg->size) {
+ /* Read type, instance, length */
+ ret = sscanf(cfg->data + data_pos, "%x %x %x%n",
+ &type, &instance, &size, &offset);
+ if (ret == 0) {
+ /* EOF */
+ break;
+ } else if (ret != 3) {
+ dev_err(dev, "Bad format\n");
+ ret = -EINVAL;
+ goto release_mem;
+ }
+ data_pos += offset;
+ if (type == 35) {
+ if (instance == 0) {
+ type = 150 + add_num;
+ add_num ++;
+ } else
+ type = 150 + add_num - 1;
+ }
+
+ pr_info("write to type = %d, instance = %d, size = %d, offset = %d\n",
+ (int)type, (int)instance, (int)size, (int)offset);
+
+ object = mxt_get_object(data, type);
+ if (!object) {
+ ret = -EINVAL;
+ goto release_mem;
+ }
+
+ if (instance >= object->instances) {
+ dev_err(dev, "Object instances exceeded!\n");
+ ret = -EINVAL;
+ goto release_mem;
+ }
+
+ reg = object->start_address + object->size * instance;
+
+ if (size > object->size) {
+ /* Either we are in fallback mode due to wrong
+ * config or config from a later fw version,
+ * or the file is corrupt or hand-edited */
+ dev_warn(dev, "Discarding %u bytes in T%u!\n",
+ size - object->size, type);
+ size = object->size;
+ } else if (object->size > size) {
+ /* If firmware is upgraded, new bytes may be added to
+ * end of objects. It is generally forward compatible
+ * to zero these bytes - previous behaviour will be
+ * retained. However this does invalidate the CRC and
+ * will force fallback mode until the configuration is
+ * updated. We warn here but do nothing else - the
+ * malloc has zeroed the entire configuration. */
+ dev_warn(dev, "Zeroing %d byte(s) in T%d\n",
+ object->size - size, type);
+ }
+
+ for (i = 0; i < size; i++) {
+ ret = sscanf(cfg->data + data_pos, "%hhx%n",
+ &val,
+ &offset);
+ if (ret != 1) {
+ dev_err(dev, "Bad format\n");
+ ret = -EINVAL;
+ goto release_mem;
+ }
+
+ byte_offset = reg + i - config_start_offset;
+
+ /* Special case for T38:
+ * Since T38 is used to store userdata, when we update the
+ * config, the userdata shall not be updated. */
+ if (get_hw_version_major() <= 4) {
+ /* T38 is stored as config info in X5,
+ * no need to protect this register */
+ if (type == MXT_SPT_USERDATA_T38 && i < MXT_USERDATA_SIZE)
+ val = data->userdata_info[i];
+ }
+
+ if ((byte_offset >= 0)
+ && (byte_offset <= config_mem_size)) {
+ *(config_mem + byte_offset) = val;
+ } else {
+ dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
+ reg, object->type, byte_offset);
+ ret = -EINVAL;
+ goto release_mem;
+ }
+
+ data_pos += offset;
+ }
+ }
+
+ /* calculate crc of the received configs (not the raw config file) */
+ if (data->T7_address < config_start_offset) {
+ dev_err(dev, "Bad T7 address, T7addr = %x, config offset %x\n",
+ data->T7_address, config_start_offset);
+ ret = 0;
+ goto release_mem;
+ }
+
+
+ /* Write configuration as blocks */
+ byte_offset = 0;
+ while (byte_offset < config_mem_size) {
+ size = config_mem_size - byte_offset;
+
+ if (size > MXT_MAX_BLOCK_WRITE)
+ size = MXT_MAX_BLOCK_WRITE;
+
+ ret = mxt_write_block(data->client,
+ config_start_offset + byte_offset,
+ size, config_mem + byte_offset);
+ if (ret != 0) {
+ dev_err(dev, "Config write error, ret=%d\n", ret);
+ goto release_mem;
+ }
+
+ byte_offset += size;
+ }
+
+ ret = 1; /* tell the caller config has been sent */
+
+release_mem:
+ kfree(config_mem);
+release:
+ release_firmware(cfg);
+ return ret;
+}
+
+static int mxt_chip_reset(struct mxt_data *data);
+
+static int mxt_set_power_cfg(struct mxt_data *data, u8 mode)
+{
+ struct device *dev = &data->client->dev;
+ int error = 0;
+ int i, cnt;
+
+ if (data->state != APPMODE) {
+ dev_err(dev, "Not in APPMODE\n");
+ return -EINVAL;
+ }
+
+ switch (mode) {
+ case MXT_POWER_CFG_DEEPSLEEP:
+ /* Touch disable */
+ cnt = ARRAY_SIZE(mxt_save);
+ for (i = 0; i < cnt; i++) {
+ if (mxt_get_object(data, mxt_save[i].suspend_obj) == NULL)
+ continue;
+ if (mxt_save[i].suspend_flags == MXT_SUSPEND_DYNAMIC)
+ error |= mxt_write_object(data,
+ mxt_save[i].suspend_obj,
+ mxt_save[i].suspend_reg,
+ mxt_save[i].suspend_val);
+ if (error) {
+ error = mxt_chip_reset(data);
+ if (error)
+ dev_err(dev, "Failed to do chip reset!\n");
+ break;
+ }
+ }
+ break;
+
+ case MXT_POWER_CFG_RUN:
+ default:
+ /* Touch enable */
+ cnt = ARRAY_SIZE(mxt_save);
+ while (cnt--) {
+ if (mxt_get_object(data, mxt_save[cnt].suspend_obj) == NULL)
+ continue;
+ error |= mxt_write_object(data,
+ mxt_save[cnt].suspend_obj,
+ mxt_save[cnt].suspend_reg,
+ mxt_save[cnt].restore_val);
+ if (error) {
+ error = mxt_chip_reset(data);
+ if (error)
+ dev_err(dev, "Failed to do chip reset!\n");
+ break;
+ }
+ }
+ break;
+ }
+
+ if (error)
+ goto i2c_error;
+
+ data->is_stopped = (mode == MXT_POWER_CFG_DEEPSLEEP) ? 1 : 0;
+
+ return 0;
+
+i2c_error:
+ dev_err(dev, "Failed to set power cfg\n");
+ return error;
+}
+
+static int mxt_read_power_cfg(struct mxt_data *data, u8 *actv_cycle_time,
+ u8 *idle_cycle_time, u8 *actv2idle_timeout)
+{
+ int error;
+
+ error = mxt_read_object(data, MXT_GEN_POWER_T7,
+ MXT_POWER_ACTVACQINT,
+ actv_cycle_time);
+ if (error)
+ return error;
+
+ error = mxt_read_object(data, MXT_GEN_POWER_T7,
+ MXT_POWER_IDLEACQINT,
+ idle_cycle_time);
+ if (error)
+ return error;
+
+ error = mxt_read_object(data, MXT_GEN_POWER_T7,
+ MXT_POWER_ACTV2IDLETO,
+ actv2idle_timeout);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int mxt_check_power_cfg_post_reset(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int error;
+
+ error = mxt_read_power_cfg(data, &data->actv_cycle_time,
+ &data->idle_cycle_time,
+ &data->actv2idle_timeout);
+ if (error)
+ return error;
+
+ /* Power config is zero, select free run */
+ if (data->actv_cycle_time == 0 || data->idle_cycle_time == 0) {
+ dev_dbg(dev, "Overriding power cfg to free run\n");
+ data->actv_cycle_time = 255;
+ data->idle_cycle_time = 255;
+
+ error = mxt_set_power_cfg(data, MXT_POWER_CFG_RUN);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+static int mxt_probe_power_cfg(struct mxt_data *data)
+{
+ int error;
+
+ data->slowscan_actv_cycle_time = 120; /* 120mS */
+ data->slowscan_idle_cycle_time = 10; /* 10mS */
+ data->slowscan_actv2idle_timeout = 100; /* 10 seconds */
+
+ error = mxt_read_power_cfg(data, &data->actv_cycle_time,
+ &data->idle_cycle_time,
+ &data->actv2idle_timeout);
+ if (error)
+ return error;
+
+ /* If in deep sleep mode, attempt reset */
+ if (data->actv_cycle_time == 0 || data->idle_cycle_time == 0) {
+ error = mxt_soft_reset(data, MXT_RESET_VALUE);
+ if (error)
+ return error;
+
+ error = mxt_check_power_cfg_post_reset(data);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+static int mxt_read_internal_gpio(struct mxt_data *data)
+{
+ int ret;
+ int timeout = 1000;
+ int i = 0;
+ bool is_timeout = true;
+ struct device *dev = &data->client->dev;
+ u8 val;
+
+ ret = mxt_write_object(data, MXT_SPT_GPIOPWM_T19,
+ MXT_GPIOPWM_INTPULLUP, 0xFF);
+ if (ret) {
+ dev_err(dev, "Failed to enable internal pull-up resistor!\n");
+ return ret;
+ }
+
+ ret = mxt_write_object(data, MXT_SPT_GPIOPWM_T19,
+ MXT_GPIOPWM_CTRL, MXT_GPIO_FORCERPT);
+ if (ret) {
+ dev_err(dev, "Failed to write force report to GPIO !\n");
+ return ret;
+ }
+
+ while (i < timeout) {
+ ret = mxt_read_object(data, MXT_SPT_GPIOPWM_T19,
+ MXT_GPIOPWM_CTRL, &val);
+ if (ret) {
+ dev_err(dev, "Failed to read GPIO ctrl status !\n");
+ return ret;
+ }
+
+ if ((val & MXT_GPIO_FORCERPT) == 0x3) {
+ is_timeout = false;
+ break;
+ }
+ i++;
+ msleep(1);
+ }
+
+ if (is_timeout) {
+ dev_err(dev, "polling forcerpt bit timeout !\n");
+ return -ETIMEDOUT;
+ }
+
+ mxt_read_t9_messages_until_invalid(data);
+
+ ret = mxt_write_object(data, MXT_SPT_GPIOPWM_T19,
+ MXT_GPIOPWM_INTPULLUP, 0);
+ if (ret) {
+ dev_err(dev, "Failed to disable internal pull-up resistor!\n");
+ return ret;
+ }
+
+ ret = mxt_write_object(data, MXT_SPT_GPIOPWM_T19,
+ MXT_GPIOPWM_CTRL, MXT_GPIO_DISABLEOUTPUT);
+ if (ret) {
+ dev_err(dev, "Failed to disable reading GPIO status!\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const char * mxt_get_config(struct mxt_data *data, bool is_default)
+{
+ const struct mxt_platform_data *pdata = data->pdata;
+ int i;
+
+ if (pdata->default_config == -1) {
+ /* no default config is set */
+ is_default = false;
+ }
+
+ for (i = 0; i < pdata->config_array_size; i++) {
+ if (data->info.family_id== pdata->config_array[i].family_id &&
+ data->info.variant_id == pdata->config_array[i].variant_id &&
+ data->info.version == pdata->config_array[i].version &&
+ data->info.build == pdata->config_array[i].build &&
+ data->rev_id == pdata->config_array[i].rev_id &&
+ data->vendor_id == pdata->config_array[i].vendor_id) {
+ break;
+ }
+ }
+
+ if (i >= pdata->config_array_size) {
+ /* No matching config */
+ if (!is_default)
+ return NULL;
+ else
+ i = pdata->default_config;
+ }
+
+ dev_info(&data->client->dev, "Choose config %d: %s, is_default = %d\n",
+ i, pdata->config_array[i].mxt_cfg_name, is_default);
+
+ data->current_index = i;
+ return pdata->config_array[i].mxt_cfg_name;
+}
+
+static int mxt_backup_nv(struct mxt_data *data)
+{
+ int error;
+ u8 command_register;
+ int timeout_counter = 0;
+
+ /* Backup to memory */
+ mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_BACKUPNV,
+ MXT_BACKUP_VALUE);
+ msleep(MXT_BACKUP_TIME);
+
+ do {
+ error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_BACKUPNV,
+ &command_register);
+ if (error)
+ return error;
+
+ msleep(20);
+
+ } while ((command_register != 0) && (++timeout_counter <= 100));
+
+ if (timeout_counter > 100) {
+ dev_err(&data->client->dev, "No response after backup!\n");
+ return -EIO;
+ }
+
+ /* Soft reset */
+ error = mxt_soft_reset(data, MXT_RESET_VALUE);
+ if (error) {
+ dev_err(&data->client->dev, "Failed to do reset!\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static int mxt_read_rev(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+ int i = 0;
+ u8 val;
+
+ ret = mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_DIAGNOSTIC, 0x80);
+ if (ret) {
+ dev_err(dev, "Failed to send rev read command!\n");
+ return ret;
+ }
+
+ while (i < 100) {
+ ret = mxt_read_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_DIAGNOSTIC, &val);
+ if (ret) {
+ dev_err(dev, "Failed to read diagnostic!\n");
+ return ret;
+ }
+
+ if (val == 0)
+ break;
+ i++;
+ msleep(10);
+ }
+
+ ret = mxt_read_object(data, MXT_DEBUG_DIAGNOSTIC_T37,
+ MXT_DIAG_REV_ID, &data->rev_id);
+ if (ret) {
+ dev_err(dev, "Failed to read rev id!\n");
+ return ret;
+ }
+
+ dev_info(dev, "read rev_id = 0x%x\n", data->rev_id);
+
+ return 0;
+}
+
+static int mxt_read_userdata_info(struct mxt_data *data)
+{
+ int ret = 0;
+ struct mxt_object *object;
+ u16 reg;
+
+ object = mxt_get_object(data, MXT_SPT_USERDATA_T38);
+ if (!object)
+ return -EINVAL;
+
+ reg = object->start_address;
+ ret = mxt_read_reg(data->client, reg,
+ MXT_USERDATA_SIZE, data->userdata_info);
+ if (ret)
+ dev_err(&data->client->dev, "Failed to read T38\n");
+
+ return ret;
+}
+
+static int mxt_read_lockdown_info(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ struct mxt_object *object;
+ int ret, i = 0;
+ u8 val;
+ u16 reg;
+
+ ret = mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_DIAGNOSTIC, 0x81);
+ if (ret) {
+ dev_err(dev, "Failed to send lockdown info read command!\n");
+ return ret;
+ }
+
+ while (i < 100) {
+ ret = mxt_read_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_DIAGNOSTIC, &val);
+ if (ret) {
+ dev_err(dev, "Failed to read diagnostic!\n");
+ return ret;
+ }
+
+ if (val == 0)
+ break;
+
+ i++;
+ msleep(10);
+ }
+
+ object = mxt_get_object(data, MXT_DEBUG_DIAGNOSTIC_T37);
+ if (!object)
+ return -EINVAL;
+
+ reg = object->start_address;
+ ret = mxt_read_reg(data->client, reg + MXT_LOCKDOWN_OFFSET,
+ MXT_LOCKDOWN_SIZE, data->lockdown_info);
+ if (ret)
+ dev_err(dev, "Failed to read lockdown info!\n");
+
+ return 0;
+}
+
+static int mxt_check_reg_init(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+ const char* config_name = NULL;
+ bool is_recheck = false, use_default_cfg = false;
+
+ if (data->firmware_updated)
+ use_default_cfg = true;
+
+start:
+ ret = mxt_read_rev(data);
+ if (ret) {
+ dev_err(dev, "Can not get rev!\n");
+ is_recheck = true;
+ } else {
+ is_recheck = false;
+ }
+
+ ret = mxt_read_internal_gpio(data);
+ if (ret) {
+ dev_err(dev, "Can not get internal gpio status!\n");
+ is_recheck = true;
+ } else {
+ is_recheck = false;
+ }
+
+ if (get_hw_version_major() >= 5) {
+ /*
+ * Firmware 1.5.AA supports lockdown info, which is only
+ * used for X5
+ */
+ ret = mxt_read_lockdown_info(data);
+ if (ret) {
+ dev_err(dev, "Cannot get lockdown info, set lockdown info to 0xFF!\n");
+ memset(data->lockdown_info, 0xFF, MXT_LOCKDOWN_SIZE);
+ }
+
+ dev_info(dev, "Got lockdown info: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ data->lockdown_info[0], data->lockdown_info[1],
+ data->lockdown_info[2], data->lockdown_info[3],
+ data->lockdown_info[4], data->lockdown_info[5],
+ data->lockdown_info[6], data->lockdown_info[7]);
+
+ /* In X5, we use lockdown info for storing TP vendor info */
+ data->vendor_id = data->lockdown_info[0];
+
+ /* Lockdown info is not flashed into some old TP panels,
+ * set the default vendor id to 0x38 */
+ if (data->vendor_id == 0) {
+ dev_err(dev, "TP maker info is empty, use the default one!\n");
+ data->vendor_id = 0x38; /* Default vendor is sharp */
+ }
+ }
+
+ config_name = mxt_get_config(data, use_default_cfg);
+
+ /* If we need to recheck, we shall not get a default config */
+ if (use_default_cfg)
+ use_default_cfg = false;
+
+ ret = mxt_read_userdata_info(data);
+ if (ret) {
+ dev_err(dev, "Can not get userdata info(T38)!\n");
+ } else {
+ dev_info(dev, "Got userdata info: %02X %02X %02X %02X %02X %02X %02X %02X",
+ data->userdata_info[0], data->userdata_info[1],
+ data->userdata_info[2], data->userdata_info[3],
+ data->userdata_info[4], data->userdata_info[5],
+ data->userdata_info[6], data->userdata_info[7]);
+ }
+
+ if (config_name == NULL) {
+ dev_info(dev, "Not found matched config!\n");
+ return -ENOENT;
+ }
+
+ ret = mxt_download_config(data, config_name);
+ if (ret < 0)
+ return ret;
+ else if (ret == 0)
+ /* CRC matched, or no config file, or config parse failure
+ * - no need to reset */
+ return 0;
+
+ /* Backup to memory */
+ ret = mxt_backup_nv(data);
+ if (ret) {
+ dev_err(dev, "back nv failed!\n");
+ return ret;
+ }
+
+ if (is_recheck)
+ goto start;
+
+ ret = mxt_check_power_cfg_post_reset(data);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mxt_read_info_block_crc(struct mxt_data *data)
+{
+ int ret;
+ u16 offset;
+ u8 buf[3];
+
+ offset = MXT_OBJECT_START + MXT_OBJECT_SIZE * data->info.object_num;
+
+ ret = mxt_read_reg(data->client, offset, sizeof(buf), buf);
+ if (ret)
+ return ret;
+
+ data->info_block_crc = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+ return 0;
+}
+
+static int mxt_get_object_table(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ struct device *dev = &data->client->dev;
+ int ret;
+ int i;
+ u16 end_address;
+ u8 reportid = 0;
+ u8 buf[data->info.object_num][MXT_OBJECT_SIZE];
+ int add_num = 0;
+ data->mem_size = 0;
+
+ data->object_table = kcalloc(data->info.object_num,
+ sizeof(struct mxt_object), GFP_KERNEL);
+ if (!data->object_table) {
+ dev_err(dev, "Failed to allocate object table\n");
+ return -ENOMEM;
+ }
+
+ ret = mxt_read_reg(client, MXT_OBJECT_START, sizeof(buf), buf);
+ if (ret)
+ goto free_object_table;
+
+ for (i = 0; i < data->info.object_num; i++) {
+ struct mxt_object *object = data->object_table + i;
+
+ object->type = buf[i][0];
+ if (object->type == 35) {
+ object->type = 150 + add_num;
+ add_num ++;
+ }
+ object->start_address = (buf[i][2] << 8) | buf[i][1];
+ object->size = buf[i][3] + 1;
+ object->instances = buf[i][4] + 1;
+ object->num_report_ids = buf[i][5];
+
+ if (object->num_report_ids) {
+ reportid += object->num_report_ids * object->instances;
+ object->max_reportid = reportid;
+ object->min_reportid = object->max_reportid -
+ object->instances * object->num_report_ids + 1;
+ }
+
+ end_address = object->start_address
+ + object->size * object->instances - 1;
+
+ if (end_address >= data->mem_size)
+ data->mem_size = end_address + 1;
+
+ /* save data for objects used when processing interrupts */
+ switch (object->type) {
+ case MXT_TOUCH_MULTI_T9:
+ data->T9_reportid_max = object->max_reportid;
+ data->T9_reportid_min = object->min_reportid;
+ data->num_touchids = object->num_report_ids * object->instances;
+ break;
+ case MXT_GEN_COMMAND_T6:
+ data->T6_reportid = object->max_reportid;
+ break;
+ case MXT_GEN_MESSAGE_T5:
+ if (data->info.family_id == 0x80) {
+ /* On mXT224 must read and discard CRC byte
+ * otherwise DMA reads are misaligned */
+ data->T5_msg_size = object->size;
+ } else {
+ /* CRC not enabled, therefore don't read last byte */
+ data->T5_msg_size = object->size - 1;
+ }
+ data->T5_address = object->start_address;
+ break;
+ case MXT_GEN_POWER_T7:
+ data->T7_address = object->start_address;
+ break;
+ case MXT_TOUCH_KEYARRAY_T15:
+ data->T15_reportid_max = object->max_reportid;
+ data->T15_reportid_min = object->min_reportid;
+ break;
+ case MXT_SPT_GPIOPWM_T19:
+ data->T19_reportid_max = object->max_reportid;
+ data->T19_reportid_min = object->min_reportid;
+ break;
+ case MXT_SPT_SELFTEST_T25:
+ data->T25_reportid_max = object->max_reportid;
+ data->T25_reportid_min = object->min_reportid;
+ break;
+ case MXT_DEBUG_DIAGNOSTIC_T37:
+ data->T37_address = object->start_address;
+ break;
+ case MXT_PROCI_TOUCHSUPPRESSION_T42:
+ data->T42_reportid_max = object->max_reportid;
+ data->T42_reportid_min = object->min_reportid;
+ break;
+ case MXT_SPT_MESSAGECOUNT_T44:
+ data->T44_address = object->start_address;
+ break;
+ case MXT_SPT_NOISESUPPRESSION_T48:
+ data->T48_reportid = object->max_reportid;
+ break;
+ case MXT_PROCI_ACTIVE_STYLUS_T63:
+ data->T63_reportid_max = object->max_reportid;
+ data->T63_reportid_min = object->min_reportid;
+ data->num_stylusids =
+ object->num_report_ids * object->instances;
+ break;
+ case MXT_SPT_GOLDENREF_T66:
+ data->T66_reportid = object->max_reportid;
+ break;
+ case MXT_TOUCH_MORE_GESTURE_T81:
+ data->T81_reportid_min = object->min_reportid;
+ data->T81_reportid_max = object->max_reportid;
+ break;
+ case MXT_TOUCH_GESTURE_T92:
+ data->T92_reportid_min = object->min_reportid;
+ data->T92_reportid_max = object->max_reportid;
+ break;
+ case MXT_TOUCH_MULTI_T100:
+ data->T100_reportid_max = object->max_reportid;
+ data->T100_reportid_min = object->min_reportid;
+ data->num_touchids = object->num_report_ids * object->instances;
+ break;
+ case MXT_SPT_SELFCAPGLOBALCONFIG_T109:
+ data->T109_reportid = object->max_reportid;
+ break;
+ }
+
+ dev_dbg(dev, "T%u, start:%u size:%u instances:%u "
+ "min_reportid:%u max_reportid:%u\n",
+ object->type, object->start_address, object->size,
+ object->instances,
+ object->min_reportid, object->max_reportid);
+ }
+
+ /* Store maximum reportid */
+ data->max_reportid = reportid;
+
+ /* If T44 exists, T9 position has to be directly after */
+ if (data->T44_address && (data->T5_address != data->T44_address + 1)) {
+ dev_err(dev, "Invalid T44 position\n");
+ ret = -EINVAL;
+ goto free_object_table;
+ }
+
+ /* Allocate message buffer */
+ data->msg_buf = kcalloc(data->max_reportid, data->T5_msg_size, GFP_KERNEL);
+ if (!data->msg_buf) {
+ dev_err(dev, "Failed to allocate message buffer\n");
+ ret = -ENOMEM;
+ goto free_object_table;
+ }
+
+ return 0;
+
+free_object_table:
+ kfree(data->object_table);
+ return ret;
+}
+
+static int mxt_read_resolution(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ int error;
+ unsigned int x_range, y_range;
+ unsigned char orient;
+ unsigned char val;
+
+ /* Update matrix size in info struct */
+ error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, 1, &val);
+ if (error)
+ return error;
+ data->info.matrix_xsize = val;
+
+ error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, 1, &val);
+ if (error)
+ return error;
+ data->info.matrix_ysize = val;
+
+ if (mxt_get_object(data, MXT_TOUCH_MULTI_T100) != NULL) {
+ /* Read X/Y size of touchscreen */
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_XRANGE_MSB, &val);
+ if (error)
+ return error;
+ x_range = val << 8;
+
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_XRANGE_LSB, &val);
+ if (error)
+ return error;
+ x_range |= val;
+
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_YRANGE_MSB, &val);
+ if (error)
+ return error;
+ y_range = val << 8;
+
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_YRANGE_LSB, &val);
+ if (error)
+ return error;
+ y_range |= val;
+
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_CFG1, &val);
+ if (error)
+ return error;
+ orient = (val & 0xE0) >> 5;
+ } else {
+ /* Read X/Y size of touchscreen */
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T9,
+ MXT_TOUCH_XRANGE_MSB, &val);
+ if (error)
+ return error;
+ x_range = val << 8;
+
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T9,
+ MXT_TOUCH_XRANGE_LSB, &val);
+ if (error)
+ return error;
+ x_range |= val;
+
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T9,
+ MXT_TOUCH_YRANGE_MSB, &val);
+ if (error)
+ return error;
+ y_range = val << 8;
+
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T9,
+ MXT_TOUCH_YRANGE_LSB, &val);
+ if (error)
+ return error;
+ y_range |= val;
+
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T9,
+ MXT_TOUCH_ORIENT, &orient);
+ if (error)
+ return error;
+ }
+
+ dev_info(&client->dev, "xrange = %d, yrange = %d\n", x_range, y_range);
+ /* Handle default values */
+ if (x_range == 0)
+ x_range = 1023;
+
+ if (y_range == 0)
+ y_range = 1023;
+
+ if (orient & MXT_XY_SWITCH) {
+ data->max_x = y_range;
+ data->max_y = x_range;
+ } else {
+ data->max_x = x_range;
+ data->max_y = y_range;
+ }
+
+ dev_info(&client->dev,
+ "Matrix Size X%uY%u Touchscreen size X%uY%u\n",
+ data->info.matrix_xsize, data->info.matrix_ysize,
+ data->max_x, data->max_y);
+
+ return 0;
+}
+
+static void mxt_initialize_regulator(struct mxt_data *data)
+{
+ int ret;
+ struct i2c_client *client = data->client;
+
+ /*
+ Vdd and AVdd can be powered up in any order
+ XVdd must not be powered up until after Vdd
+ and must obey the rate-of-rise specification
+ */
+
+ data->regulator_vdd = devm_regulator_get(&client->dev, "vdd");
+ if (IS_ERR(data->regulator_vdd)) {
+ dev_info(&client->dev,
+ "Atmel regulator_get for vdd failed: %ld\n",
+ PTR_ERR(data->regulator_vdd));
+ goto err_null_regulator;
+ }
+
+ data->regulator_avdd = devm_regulator_get(&client->dev, "avdd");
+ if (IS_ERR(data->regulator_avdd)) {
+ dev_info(&client->dev,
+ "Atmel regulator_get for avdd failed: %ld\n",
+ PTR_ERR(data->regulator_avdd));
+ goto err_put_regulator_vdd;
+ }
+
+ data->regulator_vddio = devm_regulator_get(&client->dev, "vddio");
+ if (IS_ERR(data->regulator_vddio)) {
+ dev_info(&client->dev,
+ "Atmel regulator_get for avdd failed: %ld\n",
+ PTR_ERR(data->regulator_vddio));
+ goto err_put_regulator_avdd;
+ }
+
+ dev_info(&client->dev,
+ "Atmel regulator_get for vdd and avdd succeeded\n");
+
+ ret = regulator_enable(data->regulator_vdd);
+ if (ret < 0)
+ dev_err(&client->dev,
+ "Atmel regulator_enable for vdd failed; Error code:%d\n", ret);
+
+ ret = regulator_enable(data->regulator_avdd);
+ if (ret < 0)
+ dev_err(&client->dev,
+ "Atmel regulator_enable for avdd failed; Error code:%d\n", ret);
+
+ ret = regulator_enable(data->regulator_vddio);
+ if (ret < 0)
+ dev_err(&client->dev,
+ "Atmel regulator_enable for avdd failed; Error code:%d\n", ret);
+ return;
+
+err_put_regulator_avdd:
+ devm_regulator_put(data->regulator_avdd);
+err_put_regulator_vdd:
+ devm_regulator_put(data->regulator_vdd);
+err_null_regulator:
+ data->regulator_vddio = NULL;
+ data->regulator_avdd = NULL;
+ data->regulator_vdd = NULL;
+}
+
+static ssize_t mxt_update_fw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+
+static int mxt_wait_for_self_tune_msg(struct mxt_data *data, u8 expect_val)
+{
+ int time_out = 1000;
+ int i = 0;
+
+ while(i < time_out) {
+ if (data->selfcap_status.cmd == expect_val)
+ return 0;
+ i++;
+ msleep(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int mxt_do_self_tune(struct mxt_data *data, u8 cmd)
+{
+ int error;
+ struct device *dev = &data->client->dev;
+
+ memset(&data->selfcap_status, 0x0, sizeof(data->selfcap_status));
+
+ if (mxt_get_object(data, MXT_SPT_SELFCAPGLOBALCONFIG_T109) == NULL) {
+ dev_err(dev, "No T109 exist!\n");
+ return 0;
+ }
+
+ error = mxt_write_object(data, MXT_SPT_SELFCAPGLOBALCONFIG_T109,
+ MXT_SELFCAPCFG_CTRL, MXT_SELFCTL_RPTEN);
+ if (error) {
+ dev_err(dev, "Error when enable t109 report en!\n");
+ return error;
+ }
+
+ error = mxt_write_object(data, MXT_SPT_SELFCAPGLOBALCONFIG_T109,
+ MXT_SELFCAPCFG_CMD, cmd);
+ if (error) {
+ dev_err(dev, "Error when execute cmd 0x%x!\n", cmd);
+ return error;
+ }
+
+ error = mxt_wait_for_self_tune_msg(data, cmd);
+
+ if(!error) {
+ if (data->selfcap_status.error_code != 0)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mxt_get_t38_flag(struct mxt_data *data)
+{
+ int error;
+ u8 flag;
+
+ error = mxt_read_object(data, MXT_SPT_USERDATA_T38,
+ MXT_FW_UPDATE_FLAG, &flag);
+ if (error)
+ return error;
+
+ data->update_flag = flag;
+
+ return 0;
+}
+
+static int mxt_get_init_setting(struct mxt_data *data)
+{
+ int error;
+ u8 selfthr;
+ u8 intthr;
+ u8 glovectrl;
+ u8 atchthr;
+ int i;
+ struct device *dev = &data->client->dev;
+ const struct mxt_platform_data *pdata = data->pdata;
+ int index = data->current_index;
+
+ if (mxt_get_object(data, MXT_SPT_AUXTOUCHCONFIG_T104) != NULL) {
+ error = mxt_read_object(data, MXT_SPT_AUXTOUCHCONFIG_T104,
+ MXT_AUXTCHCFG_XTCHTHR, &selfthr);
+ if (error) {
+ dev_err(dev, "Failed to read self threshold from t104!\n");
+ return error;
+ }
+
+ error = mxt_read_object(data, MXT_SPT_AUXTOUCHCONFIG_T104,
+ MXT_AUXTCHCFG_INTTHRX, &intthr);
+ if (error) {
+ dev_err(dev, "Failed to read internal threshold from t104!\n");
+ return error;
+ }
+ }
+
+ if (mxt_get_object(data, MXT_PROCI_GLOVEDETECTION_T78) != NULL) {
+ error = mxt_read_object(data, MXT_PROCI_GLOVEDETECTION_T78,
+ MXT_GLOVE_CTRL, &glovectrl);
+ if (error) {
+ dev_err(dev, "Failed to read glove setting from t78!\n");
+ return error;
+ }
+ if ((glovectrl & 0x01) != 0)
+ data->sensitive_mode = 1;
+ }
+
+ if (mxt_get_object(data, MXT_PROCI_RETRANSMISSIONCOMPENSATION_T80) != NULL) {
+ error = mxt_read_object(data, MXT_PROCI_RETRANSMISSIONCOMPENSATION_T80,
+ MXT_RETRANS_ATCHTHR, &atchthr);
+ if (error) {
+ dev_err(dev, "Faield to read from t80 anti-touch threshold!\n");
+ return error;
+ }
+ data->atchthr = atchthr;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mxt_save); i++) {
+ error = mxt_read_object(data, MXT_GEN_POWER_T7,
+ i, &mxt_save[i].restore_val);
+ if (error) {
+ dev_err(dev, "Failed to read T7 byte %d\n", i);
+ return error;
+ }
+ }
+
+ if (mxt_get_object(data, MXT_PROCG_NOISESUPSELFCAP_T108) != NULL) {
+ for (i = 0; i < ARRAY_SIZE(data->adcperx_normal); i++) {
+ data->adcperx_wakeup[i] = pdata->config_array[index].wake_up_self_adcx;
+ error = mxt_read_object(data, MXT_PROCG_NOISESUPSELFCAP_T108,
+ 19 + i, &data->adcperx_normal[i]);
+ if (error) {
+ dev_err(dev, "Failed to read T108 setting %d\n", i);
+ return error;
+ }
+ }
+ }
+
+ error = mxt_read_resolution(data);
+ if (error) {
+ dev_err(dev, "Failed to initialize screen size\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static int mxt_initialize(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ struct mxt_info *info = &data->info;
+ int error;
+ u8 retry_count = 0;
+
+retry_probe:
+ /* Read info block */
+ error = mxt_read_reg(client, 0, sizeof(*info), info);
+ if (error) {
+ error = mxt_probe_bootloader(data);
+ if (error) {
+ /* Chip is not in appmode or bootloader mode */
+ return error;
+ } else {
+ if (++retry_count > 10) {
+ dev_err(&client->dev,
+ "Could not recover device from "
+ "bootloader mode\n");
+ data->state = BOOTLOADER;
+ /* this is not an error state, we can reflash
+ * from here */
+ error = mxt_update_firmware(&client->dev, NULL,
+ data->pdata->mxt_fw_name,
+ strlen(data->pdata->mxt_fw_name),
+ &data->firmware_updated);
+ if (error != strlen(data->pdata->mxt_fw_name))
+ {
+ dev_err(&client->dev, "Error when update firmware!\n");
+ return error;
+ }
+ return 0;
+ }
+
+ /* Tell bootloader to enter app mode. Ignore errors
+ * since we're in a retry loop */
+ mxt_send_bootloader_cmd(data, false);
+ msleep(MXT_FWRESET_TIME);
+ goto retry_probe;
+ }
+ }
+
+ dev_info(&client->dev,
+ "Family ID: %d Variant ID: %d Version: %d.%d.%02X "
+ "Object Num: %d\n",
+ info->family_id, info->variant_id,
+ info->version >> 4, info->version & 0xf,
+ info->build, info->object_num);
+
+ data->state = APPMODE;
+
+ /* Get object table information */
+ error = mxt_get_object_table(data);
+ if (error) {
+ dev_err(&client->dev, "Error %d reading object table\n", error);
+ return error;
+ }
+
+ error = mxt_get_t38_flag(data);
+ if (error) {
+ dev_err(&client->dev, "Error %d getting update flag\n", error);
+ return error;
+ }
+
+ /* Read information block CRC */
+ error = mxt_read_info_block_crc(data);
+ if (error) {
+ dev_err(&client->dev, "Error %d reading info block CRC\n", error);
+ }
+
+ error = mxt_probe_power_cfg(data);
+ if (error) {
+ dev_err(&client->dev, "Failed to initialize power cfg\n");
+ return error;
+ }
+
+ /* Check register init values */
+ error = mxt_check_reg_init(data);
+ if (error) {
+ dev_err(&client->dev, "Failed to initialize config\n");
+ return error;
+ }
+
+ if (mxt_get_object(data, MXT_TOUCH_MULTI_T100) != NULL)
+ {
+ error = mxt_read_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_TCHAUX,
+ &data->t100_tchaux_bits);
+ if (error) {
+ dev_err(&client->dev, "Failed to read tchaux!\n");
+ return error;
+ }
+ }
+
+ error = mxt_get_init_setting(data);
+ if (error) {
+ dev_err(&client->dev, "Failed to get init setting.\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static int strtobyte(const char *data, u8 *value)
+{
+ char str[3];
+
+ str[0] = data[0];
+ str[1] = data[1];
+ str[2] = '\0';
+
+ return kstrtou8(str, 16, value);
+}
+
+static size_t mxt_convert_text_to_binary(u8 *buffer, size_t len)
+{
+ int ret;
+ int i;
+ int j = 0;
+
+ for (i = 0; i < len; i+=2) {
+ ret = strtobyte(&buffer[i], &buffer[j]);
+ if (ret) {
+ return -EINVAL;
+ }
+ j++;
+ }
+
+ return (size_t)j;
+}
+
+static int mxt_check_firmware_format(struct device *dev, const struct firmware *fw)
+{
+ unsigned int pos = 0;
+ char c;
+
+ while (pos < fw->size) {
+ c = *(fw->data + pos);
+
+ if (c < '0' || (c > '9' && c < 'A') || c > 'F')
+ return 0;
+
+ pos++;
+ }
+
+ /* To convert file try
+ * xxd -r -p mXTXXX__APP_VX-X-XX.enc > maxtouch.fw */
+ dev_err(dev, "Aborting: firmware file must be in binary format\n");
+
+ return -1;
+}
+
+static void mxt_reset_toggle(struct mxt_data *data)
+{
+ const struct mxt_platform_data *pdata = data->pdata;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ gpio_set_value_cansleep(pdata->reset_gpio, 0);
+ msleep(1);
+ gpio_set_value_cansleep(pdata->reset_gpio, 1);
+ msleep(60);
+ }
+
+ gpio_set_value_cansleep(pdata->reset_gpio, 1);
+}
+
+static int mxt_load_fw(struct device *dev, const char *fn)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ const struct firmware *fw = NULL;
+ unsigned int frame_size;
+ unsigned int pos = 0;
+ unsigned int retry = 0;
+ unsigned int frame= 0;
+ int ret;
+ unsigned short ori_addr = data->client->addr;
+ size_t len = 0;
+ u8 *buffer;
+
+ ret = request_firmware(&fw, fn, dev);
+ if (ret < 0) {
+ dev_err(dev, "Unable to open firmware %s\n", fn);
+ return ret;
+ }
+
+ buffer = kmalloc(fw->size ,GFP_KERNEL);
+ if (!buffer) {
+ dev_err(dev, "malloc firmware buffer failed!\n");
+ return -ENOMEM;
+ }
+ memcpy(buffer, fw->data, fw->size);
+ len = fw->size;
+
+ ret = mxt_check_firmware_format(dev, fw);
+ if (ret) {
+ dev_info(dev, "text format, convert it to binary!\n");
+ len = mxt_convert_text_to_binary(buffer, len);
+ if (len <= 0)
+ goto release_firmware;
+ }
+
+
+ if (data->state != BOOTLOADER) {
+ /* Change to the bootloader mode */
+ mxt_reset_toggle(data);
+
+ ret = mxt_get_bootloader_address(data);
+ if (ret)
+ goto release_firmware;
+
+ data->client->addr = data->bootloader_addr;
+ data->state = BOOTLOADER;
+ }
+
+ ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD);
+ if (ret) {
+ mxt_wait_for_chg(data);
+ /* Bootloader may still be unlocked from previous update
+ * attempt */
+ ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
+ if (ret) {
+ data->state = FAILED;
+ goto release_firmware;
+ }
+ } else {
+ dev_info(dev, "Unlocking bootloader\n");
+
+ /* Unlock bootloader */
+ ret = mxt_send_bootloader_cmd(data, true);
+ if (ret) {
+ data->state = FAILED;
+ goto release_firmware;
+ }
+ }
+
+ while (pos < len) {
+ mxt_wait_for_chg(data);
+ ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA);
+ if (ret) {
+ data->state = FAILED;
+ goto release_firmware;
+ }
+
+ frame_size = ((*(buffer + pos) << 8) | *(buffer + pos + 1));
+
+ /* Take account of CRC bytes */
+ frame_size += 2;
+
+ /* Write one frame to device */
+ ret = mxt_bootloader_write(data,buffer + pos, frame_size);
+ if (ret) {
+ data->state = FAILED;
+ goto release_firmware;
+ }
+
+ mxt_wait_for_chg(data);
+ ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS);
+
+ if (ret) {
+ retry ++;
+
+ /* Back off by 20ms per retry */
+ msleep(retry * 20);
+
+ if (retry > 20) {
+ data->state = FAILED;
+ goto release_firmware;
+ }
+ } else {
+ retry ++;
+ pos += frame_size;
+ frame ++;
+ }
+
+ if (frame % 10 == 0) {
+ dev_info(dev, "Updated %d frames, %d/%zd bytes\n", frame, pos, len);
+ }
+ }
+
+ dev_info(dev, "Finished, sent %d frames, %zd bytes\n", frame, pos);
+
+ data->state = INIT;
+
+release_firmware:
+ data->client->addr = ori_addr;
+ release_firmware(fw);
+ kfree(buffer);
+ return ret;
+}
+
+static ssize_t mxt_update_firmware(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count, bool *upgraded)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int error;
+ char *fw_name;
+ int len = 0;
+
+ if (upgraded)
+ *upgraded = false;
+
+ if (count <= 0)
+ return -EINVAL;
+
+ len = strnlen(buf, count);
+ fw_name = kmalloc(len + 1, GFP_KERNEL);
+ if (fw_name == NULL)
+ return -ENOMEM;
+
+ if (count > 0) {
+ strncpy(fw_name, buf, len);
+ if (fw_name[len - 1] == '\n')
+ fw_name[len - 1] = 0;
+ else
+ fw_name[len] = 0;
+ }
+
+ dev_info(dev, "Identify firmware name :%s\n", fw_name);
+ mxt_disable_irq(data);
+
+ error = mxt_load_fw(dev, fw_name);
+ if (error) {
+ dev_err(dev, "The firmware update failed(%d)\n", error);
+ count = error;
+ } else {
+ dev_info(dev, "The firmware update succeeded\n");
+
+ /* Wait for reset */
+ msleep(MXT_FWRESET_TIME);
+
+ kfree(data->object_table);
+ data->object_table = NULL;
+ kfree(data->msg_buf);
+ data->msg_buf = NULL;
+
+ if (upgraded)
+ *upgraded = true;
+
+ mxt_initialize(data);
+ }
+
+ if (data->state == APPMODE) {
+ mxt_enable_irq(data);
+ }
+
+ kfree(fw_name);
+ return count;
+}
+
+static ssize_t mxt_update_fw_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+
+ ssize_t count = sprintf(buf,
+ "family_id=0x%02x, variant_id=0x%02x, version=0x%02x, build=0x%02x, vendor=0x%02x\n",
+ data->info.family_id, data->info.variant_id,
+ data->info.version, data->info.build,
+ data->vendor_id);
+ return count;
+}
+
+static ssize_t mxt_update_fw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return mxt_update_firmware(dev, attr, buf, count, NULL);
+}
+
+static ssize_t mxt_keys_off_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+ char c;
+
+ c = data->keys_off ? '1' : '0';
+ count = sprintf(buf, "%c\n", c);
+
+ return count;
+}
+
+static ssize_t mxt_keys_off_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int i;
+
+ if (sscanf(buf, "%u", &i) == 1 && i < 2) {
+ data->keys_off = (i == 1);
+
+ dev_dbg(dev, "%s\n", i ? "hw keys off" : "hw keys on");
+ return count;
+ } else {
+ dev_dbg(dev, "keys_off write error\n");
+ return -EINVAL;
+ }
+}
+
+static ssize_t mxt_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count = 0;
+
+ count += sprintf(buf + count, "%d", data->info.version);
+ count += sprintf(buf + count, "\n");
+
+ return count;
+}
+
+static ssize_t mxt_build_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count = 0;
+
+ count += sprintf(buf + count, "%d", data->info.build);
+ count += sprintf(buf + count, "\n");
+
+ return count;
+}
+
+static ssize_t mxt_pause_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ ssize_t count;
+ char c;
+
+ c = data->driver_paused ? '1' : '0';
+ count = sprintf(buf, "%c\n", c);
+
+ return count;
+}
+
+static ssize_t mxt_pause_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int i;
+
+ if (sscanf(buf, "%u", &i) == 1 && i < 2) {
+ data->driver_paused = (i == 1);
+ dev_dbg(dev, "%s\n", i ? "paused" : "unpaused");
+ return count;
+ } else {
+ dev_dbg(dev, "pause_driver write error\n");
+ return -EINVAL;
+ }
+}
+
+static ssize_t mxt_debug_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+ char c;
+
+ c = data->debug_enabled ? '1' : '0';
+ count = sprintf(buf, "%c\n", c);
+
+ return count;
+}
+
+static ssize_t mxt_debug_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int i;
+
+ if (sscanf(buf, "%u", &i) == 1 && i < 2) {
+ data->debug_enabled = (i == 1);
+
+ dev_dbg(dev, "%s\n", i ? "debug enabled" : "debug disabled");
+ return count;
+ } else {
+ dev_dbg(dev, "debug_enabled write error\n");
+ return -EINVAL;
+ }
+}
+
+static int mxt_check_mem_access_params(struct mxt_data *data, loff_t off,
+ size_t *count)
+{
+ if (data->state != APPMODE) {
+ dev_err(&data->client->dev, "Not in APPMODE\n");
+ return -EINVAL;
+ }
+
+ if (off >= data->mem_size)
+ return -EIO;
+
+ if (off + *count > data->mem_size)
+ *count = data->mem_size - off;
+
+ if (*count > MXT_MAX_BLOCK_WRITE)
+ *count = MXT_MAX_BLOCK_WRITE;
+
+ return 0;
+}
+
+static ssize_t mxt_slowscan_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count = 0;
+ int error;
+ u8 actv_cycle_time;
+ u8 idle_cycle_time;
+ u8 actv2idle_timeout;
+ dev_info(dev, "Calling mxt_slowscan_show()\n");
+
+ error = mxt_read_object(data, MXT_GEN_POWER_T7,
+ MXT_POWER_ACTVACQINT,
+ &actv_cycle_time);
+
+ if (error)
+ return error;
+
+ error = mxt_read_object(data, MXT_GEN_POWER_T7,
+ MXT_POWER_IDLEACQINT,
+ &idle_cycle_time);
+
+ if (error)
+ return error;
+
+ error = mxt_read_object(data, MXT_GEN_POWER_T7,
+ MXT_POWER_ACTV2IDLETO,
+ &actv2idle_timeout);
+
+ if (error)
+ return error;
+
+ count += sprintf(buf + count,
+ "SLOW SCAN (enable/disable) = %s.\n",
+ data->slowscan_enabled ? "enabled" : "disabled");
+ count += sprintf(buf + count,
+ "SLOW SCAN (actv_cycle_time) = %umS.\n",
+ data->slowscan_actv_cycle_time);
+ count += sprintf(buf + count,
+ "SLOW SCAN (idle_cycle_time) = %umS.\n",
+ data->slowscan_idle_cycle_time);
+ count += sprintf(buf + count,
+ "SLOW SCAN (actv2idle_timeout) = %u.%0uS.\n",
+ data->slowscan_actv2idle_timeout / 10,
+ data->slowscan_actv2idle_timeout % 10);
+ count += sprintf(buf + count,
+ "CURRENT (actv_cycle_time) = %umS.\n",
+ actv_cycle_time);
+ count += sprintf(buf + count,
+ "CURRENT (idle_cycle_time) = %umS.\n",
+ idle_cycle_time);
+ count += sprintf(buf + count,
+ "CURRENT (actv2idle_timeout) = %u.%0uS.\n",
+ actv2idle_timeout / 10, actv2idle_timeout % 10);
+
+ return count;
+}
+
+static ssize_t mxt_slowscan_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int fn;
+ int val;
+ int ret;
+
+ dev_info(dev, "Calling mxt_slowscan_store()\n");
+ ret = sscanf(buf, "%u %u", &fn, &val);
+ if ((ret == 1) || (ret == 2)) {
+ switch (fn) {
+ case SLOSCAN_DISABLE:
+ if (data->slowscan_enabled) {
+ data->actv_cycle_time =
+ data->slowscan_shad_actv_cycle_time;
+ data->idle_cycle_time =
+ data->slowscan_shad_idle_cycle_time;
+ data->actv2idle_timeout =
+ data->slowscan_shad_actv2idle_timeout;
+ data->slowscan_enabled = 0;
+ mxt_set_power_cfg(data, 0);
+ }
+ break;
+
+ case SLOSCAN_ENABLE:
+ if (!data->slowscan_enabled) {
+ data->slowscan_shad_actv_cycle_time =
+ data->actv_cycle_time;
+ data->slowscan_shad_idle_cycle_time =
+ data->idle_cycle_time;
+ data->slowscan_shad_actv2idle_timeout =
+ data->actv2idle_timeout;
+ data->actv_cycle_time =
+ data->slowscan_actv_cycle_time;
+ data->idle_cycle_time =
+ data->slowscan_idle_cycle_time;
+ data->actv2idle_timeout =
+ data->slowscan_actv2idle_timeout;
+ data->slowscan_enabled = 1;
+ mxt_set_power_cfg(data, 0);
+ }
+ break;
+
+ case SLOSCAN_SET_ACTVACQINT:
+ data->slowscan_actv_cycle_time = val;
+ break;
+
+ case SLOSCAN_SET_IDLEACQINT:
+ data->slowscan_idle_cycle_time = val;
+ break;
+
+ case SLOSCAN_SET_ACTV2IDLETO:
+ data->slowscan_actv2idle_timeout = val;
+ break;
+ }
+ }
+ return count;
+}
+
+static void mxt_self_tune(struct mxt_data *data, u8 save_cmd)
+{
+ struct device *dev = &data->client->dev;
+ int retry_times = 10;
+ int i = 0;
+ int error;
+
+ while(i++ < retry_times) {
+ error = mxt_do_self_tune(data, MXT_SELFCMD_TUNE);
+ if (error) {
+ dev_err(dev, "Self tune cmd failed!\n");
+ continue;
+ }
+ error = mxt_do_self_tune(data, save_cmd);
+ if (!error)
+ return;
+ else {
+ dev_err(dev, "Self store cmd failed!\n");
+ continue;
+ }
+ }
+
+ dev_err(dev, "Even retry self tuning for 10 times, still can't pass.!\n");
+}
+
+static bool mxt_self_tune_pass(struct mxt_data *data, bool is_hover_mode)
+{
+ int error;
+ struct device *dev = &data->client->dev;
+ u16 addr = data->T37_address;
+ u8 mode = MXT_DIAG_SELF_REF;
+ size_t bufsize = MXT_DIAG_SELF_SIZE;
+ int read_size = 0;
+ int i, j = 0;
+ u8 *buf;
+ short val;
+ int bound[] = {32, 68};
+ int start[] = {40, 80};
+
+ buf = kmalloc(MXT_DIAG_TOTAL_SIZE, GFP_KERNEL);
+ if (buf == NULL) {
+ dev_err(dev, "Failed to alloc buffer for delta getting!\n");
+ return false;
+ }
+
+ error = mxt_do_diagnostic(data, mode);
+ if (error) {
+ dev_err(dev, "Failed to do diagnostic!\n");
+ kfree(buf);
+ return false;
+ }
+
+ if (is_hover_mode) {
+ error = mxt_do_diagnostic(data, MXT_DIAG_PAGE_UP);
+ if (error) {
+ dev_err(dev, "do diagnostic 0x%02x failed\n", MXT_DIAG_PAGE_UP);
+ kfree(buf);
+ return false;
+ }
+ }
+
+ while (read_size < bufsize) {
+ error = mxt_read_reg(data->client, addr + 2,
+ MXT_DIAG_PAGE_SIZE, buf + read_size);
+ if (error) {
+ dev_err(dev, "Read from T37 failed!\n");
+ kfree(buf);
+ return false;
+ }
+
+ read_size += MXT_DIAG_PAGE_SIZE;
+
+ error = mxt_do_diagnostic(data, MXT_DIAG_PAGE_UP);
+ if (error) {
+ dev_err(dev, "do diagnostic 0x%02x failed!\n", MXT_DIAG_PAGE_UP);
+ kfree(buf);
+ return false;
+ }
+ }
+
+ for (i = 0; i < bufsize; i += 2) {
+ if (i == bound[j]) {
+ i = start[j];
+ j++;
+ }
+ val = (buf[i+1] << 8) | buf[i];
+ pr_info("tune val [%d] = %d\n", i, val);
+ if (val > 17384 || val < 15384) {
+ kfree(buf);
+ return false;
+ }
+ }
+
+ kfree(buf);
+ return true;
+}
+
+static void mxt_hover_loading_work(struct work_struct* work)
+{
+ struct mxt_data *data = container_of(work, struct mxt_data, hover_loading_work);
+ int error;
+
+ if (data->rev_id == REV_D) {
+ error = mxt_do_self_tune(data, MXT_SELFCMD_AFN_TUNE);
+ if (error)
+ dev_err(&data->client->dev,
+ "Failed to load hover ref from flash!\n");
+ }
+}
+
+static void mxt_self_tuning_work(struct work_struct* work)
+{
+ struct mxt_data *data = container_of(work, struct mxt_data, self_tuning_work);
+
+ if (data->rev_id == REV_D) {
+ do {
+ mxt_self_tune(data, MXT_SELFCMD_STCR_TUNE);
+ if (mxt_self_tune_pass(data, false))
+ break;
+ } while (1);
+ }
+}
+
+static ssize_t mxt_self_tune_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ u8 execute_cmd;
+ struct mxt_data *data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%hhu", &execute_cmd) == 1)
+ mxt_self_tune(data, MXT_SELFCMD_STCR_TUNE);
+ else
+ return -EINVAL;
+
+ return count;
+}
+
+static void mxt_do_calibration(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ int error, i;
+ u8 val;
+ int time_out = 100;
+
+ error = mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_CALIBRATE, 1);
+ if (error) {
+ dev_err(dev, "failed to do calibration!\n");
+ return;
+ }
+
+ for (i = 0; i < time_out; i++) {
+ error = mxt_read_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_CALIBRATE, &val);
+ if (error) {
+ dev_err(dev, "failed to read calibration!\n");
+ return;
+ }
+
+ if (val == 0)
+ break;
+ msleep(10);
+ }
+}
+
+static void mxt_calibration_delayed_work(struct work_struct *work)
+{
+ struct delayed_work *delayed_work = to_delayed_work(work);
+ struct mxt_data *data = container_of(delayed_work, struct mxt_data,
+ calibration_delayed_work);
+
+ mxt_do_calibration(data);
+}
+
+static ssize_t mxt_update_fw_flag_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+ int i;
+
+ if (sscanf(buf, "%u", &i) == 1) {
+ dev_dbg(dev, "write fw update flag %d to t38\n", i);
+ ret = mxt_write_object(data, MXT_SPT_USERDATA_T38,
+ MXT_FW_UPDATE_FLAG, (u8)i);
+ if (ret < 0)
+ return ret;
+ ret = mxt_backup_nv(data);
+ if (ret)
+ return ret;
+ }
+
+ return count;
+}
+
+static ssize_t mxt_selftest_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%02x, %02x, %02x, %02x, %02x, %02x\n",
+ data->test_result[0], data->test_result[1],
+ data->test_result[2], data->test_result[3],
+ data->test_result[4], data->test_result[5]);
+}
+
+static ssize_t mxt_selftest_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int error;
+ u8 selftest_cmd;
+
+ /* run all selftest */
+ error = mxt_write_object(data,
+ MXT_SPT_SELFTEST_T25,
+ 0x01, 0xfe);
+ if (!error) {
+ while (true) {
+ msleep(10);
+ error = mxt_read_object(data,
+ MXT_SPT_SELFTEST_T25,
+ 0x01, &selftest_cmd);
+ if (error || selftest_cmd == 0)
+ break;
+ }
+ }
+
+ return error ? : count;
+}
+
+static int mxt_stylus_mode_switch(struct mxt_data *data, bool mode_on)
+{
+ struct device *dev = &data->client->dev;
+ const struct mxt_platform_data *pdata = data->pdata;
+ int error;
+ u8 ctrl;
+ u8 mult_intthr;
+ u8 mult_tchthr;
+ int index = data->current_index;
+
+ error = mxt_read_object(data, MXT_PROCI_STYLUS_T47,
+ MXT_PSTYLUS_CTRL, &ctrl);
+ if (error) {
+ dev_err(dev, "Failed to read from T47!\n");
+ return error;
+ }
+
+ if (mode_on) {
+ ctrl |= MXT_PSTYLUS_ENABLE;
+ mult_intthr = pdata->config_array[index].mult_intthr_sensitive;
+ mult_tchthr = pdata->config_array[index].mult_tchthr_sensitive;
+ }
+ else {
+ ctrl &= ~(MXT_PSTYLUS_ENABLE);
+ if (!data->sensitive_mode) {
+ mult_intthr = pdata->config_array[index].mult_intthr_not_sensitive;
+ mult_tchthr = pdata->config_array[index].mult_tchthr_not_sensitive;
+ }
+ else {
+ mult_intthr = pdata->config_array[index].mult_intthr_sensitive;
+ mult_tchthr = pdata->config_array[index].mult_tchthr_sensitive;
+ }
+ }
+
+ error = mxt_write_object(data, MXT_PROCI_STYLUS_T47,
+ MXT_PSTYLUS_CTRL, ctrl);
+ if (error) {
+ dev_err(dev, "Failed to read from t47!\n");
+ return error;
+ }
+
+ error = mxt_write_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_INTTHR, mult_intthr);
+ if (error) {
+ dev_err(dev, "Failed in writing t100 intthr!\n");
+ return error;
+ }
+
+ if (mult_tchthr != 0) {
+ error = mxt_write_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_TCHTHR, mult_tchthr);
+ if (error) {
+ dev_err(dev, "Failed in writing t100 tchthr!\n");
+ return error;
+ }
+
+ error = mxt_write_object(data, MXT_SPT_DYMDATA_T71,
+ pdata->config_array[index].t71_tchthr_pos, mult_tchthr);
+ if (error) {
+ dev_err(dev, "Failed in writing t71 tchthr!\n");
+ return error;
+ }
+ }
+
+ data->stylus_mode = (u8)mode_on;
+ return 0;
+}
+
+static ssize_t mxt_stylus_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+
+ count = sprintf(buf, "%d\n", (int)data->stylus_mode);
+
+ return count;
+}
+
+static ssize_t mxt_stylus_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int error, i;
+
+ if (sscanf(buf, "%u", &i) == 1) {
+ if (i == 1) {
+ error = mxt_stylus_mode_switch(data, true);
+ if (error) {
+ dev_err(dev, "Failed to enable stylus mode!\n");
+ return error;
+ }
+ }
+ else if (i == 0) {
+ error = mxt_stylus_mode_switch(data, false);
+ if (error) {
+ dev_err(dev, "Failed to disable stylus mode!\n");
+ return error;
+ }
+ }
+ else
+ return -EINVAL;
+
+ }
+
+ return count;
+}
+
+static int mxt_get_diag_data(struct mxt_data *data, char *buf)
+{
+ struct device *dev = &data->client->dev;
+ int error;
+ int read_size = 0;
+ u16 addr = data->T37_address;
+
+ error = mxt_do_diagnostic(data, data->diag_mode);
+ if (error) {
+ dev_err(dev, "do diagnostic 0x%02x failed!\n", data->diag_mode);
+ return error;
+ }
+
+ while (read_size < MXT_DIAG_TOTAL_SIZE) {
+ error = mxt_read_reg(data->client, addr + 2,
+ MXT_DIAG_PAGE_SIZE, buf + read_size);
+ if (error) {
+ dev_err(dev, "Read from T37 failed!\n");
+ return error;
+ }
+
+ read_size += MXT_DIAG_PAGE_SIZE;
+
+ error = mxt_do_diagnostic(data, MXT_DIAG_PAGE_UP);
+ if (error) {
+ dev_err(dev, "do diagnostic 0x%02x failed!\n", MXT_DIAG_PAGE_UP);
+ return error;
+ }
+ }
+
+ if (data->debug_enabled)
+ print_hex_dump(KERN_DEBUG, "Data: ", DUMP_PREFIX_NONE, 16, 1,
+ buf, MXT_DIAG_TOTAL_SIZE, false);
+
+ return 0;
+}
+
+static ssize_t mxt_diagnostic_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int error;
+ int i = 0;
+ int len = 0;
+ int remain_size, transfer_size;
+ int row_size = 16;
+ int group_size = 1;
+ char *tmp_buffer = kmalloc(MXT_DIAG_TOTAL_SIZE, GFP_KERNEL);
+ if (tmp_buffer == NULL)
+ return -ENOMEM;
+
+ error = mxt_get_diag_data(data, tmp_buffer);
+ if (error) {
+ kfree(tmp_buffer);
+ return error;
+ }
+
+ remain_size = MXT_DIAG_TOTAL_SIZE % row_size;
+ transfer_size = MXT_DIAG_TOTAL_SIZE - remain_size;
+ while (i < transfer_size) {
+ hex_dump_to_buffer(tmp_buffer + i, row_size, row_size, group_size,
+ buf + len, PAGE_SIZE - len, false);
+ i += row_size;
+ len = strlen(buf);
+ buf[len] = '\n';
+ len ++;
+ }
+
+ if (remain_size != 0)
+ hex_dump_to_buffer(tmp_buffer + i, remain_size, row_size, group_size,
+ buf + len, PAGE_SIZE - len, false);
+
+ kfree(tmp_buffer);
+ return strlen(buf);
+}
+
+static ssize_t mxt_diagnostic_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int i;
+ u8 mode;
+
+ if (sscanf(buf, "%u", &i) == 1) {
+ mode = (u8)i;
+ dev_info(dev, "Diag mode = 0x%02x\n", mode);
+ data->diag_mode = mode;
+ }
+
+ return count;
+}
+
+static int mxt_sensitive_mode_switch(struct mxt_data *data, bool mode_on)
+{
+ int error;
+ struct device *dev = &data->client->dev;
+ const struct mxt_platform_data *pdata = data->pdata;
+ int index = data->current_index;
+ u8 key_ctrl;
+ u8 mult_intthr;
+ u8 atchthr;
+ u8 mult_tchthr;
+
+ error = mxt_read_object(data, MXT_TOUCH_KEYARRAY_T15,
+ MXT_KEYARRAY_CTRL, &key_ctrl);
+ if (error) {
+ dev_err(dev, "Failed to read from T15 ctrl!\n");
+ return error;
+ }
+
+ if (mode_on) {
+ error = mxt_write_object(data, MXT_PROCI_GLOVEDETECTION_T78,
+ MXT_GLOVE_CTRL, MXT_GLOVECTL_ALL_ENABLE);
+ if (error)
+ return error;
+
+ key_ctrl |= MXT_KEY_ADAPTTHREN;
+ mult_intthr = pdata->config_array[index].mult_intthr_sensitive;
+ mult_tchthr = pdata->config_array[index].mult_tchthr_sensitive;
+ atchthr = pdata->config_array[index].atchthr_sensitive;
+ } else {
+ error = mxt_write_object(data, MXT_PROCI_GLOVEDETECTION_T78,
+ MXT_GLOVE_CTRL, 0x0);
+ if (error)
+ return error;
+
+ key_ctrl &= (~MXT_KEY_ADAPTTHREN);
+ if (!data->stylus_mode) {
+ mult_intthr = pdata->config_array[index].mult_intthr_not_sensitive;
+ mult_tchthr = pdata->config_array[index].mult_tchthr_not_sensitive;
+ }
+ else {
+ mult_intthr = pdata->config_array[index].mult_intthr_sensitive;
+ mult_tchthr = pdata->config_array[index].mult_tchthr_sensitive;
+ }
+ atchthr = data->atchthr;
+ }
+
+ error = mxt_write_object(data, MXT_PROCI_RETRANSMISSIONCOMPENSATION_T80,
+ MXT_RETRANS_ATCHTHR, atchthr);
+ if (error) {
+ dev_err(dev, "Failed in writing t80 atchthr!\n");
+ return error;
+ }
+
+ error = mxt_write_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_INTTHR, mult_intthr);
+ if (error) {
+ dev_err(dev, "Failed in writing t100 intthr!\n");
+ return error;
+ }
+ if (mult_tchthr != 0) {
+ error = mxt_write_object(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_TCHTHR, mult_tchthr);
+ if (error) {
+ dev_err(dev, "Failed in writing t100 tchthr!\n");
+ return error;
+ }
+
+ error = mxt_write_object(data, MXT_SPT_DYMDATA_T71,
+ pdata->config_array[index].t71_tchthr_pos, mult_tchthr);
+ if (error) {
+ dev_err(dev, "Failed in writing t71 tchthr!\n");
+ return error;
+ }
+ }
+
+ error = mxt_write_object(data, MXT_TOUCH_KEYARRAY_T15,
+ MXT_KEYARRAY_CTRL, key_ctrl);
+ if (error) {
+ dev_err(dev, "Failed in writing t15 key ctrl!\n");
+ return error;
+ }
+
+ data->sensitive_mode = (u8)mode_on;
+
+ return error;
+}
+
+static ssize_t mxt_wakeup_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+
+ count = sprintf(buf, "%d\n", (int)data->wakeup_gesture_mode);
+
+ return count;
+}
+
+static void mxt_enable_gesture_mode(struct mxt_data *data)
+{
+ u8 t81_val;
+ int error;
+
+ if (data->wakeup_gesture_mode)
+ t81_val = 7;
+ else
+ t81_val = 0;
+
+ error = mxt_write_object(data, MXT_TOUCH_MORE_GESTURE_T81,
+ MXT_GESTURE_CTRL, t81_val);
+ if (error)
+ dev_info(&data->client->dev, "write to t81 enabled failed!\n");
+}
+
+static ssize_t mxt_wakeup_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ const struct mxt_platform_data *pdata = data->pdata;
+ int index = data->current_index;
+ unsigned long val;
+ int error;
+
+ if (pdata->config_array[index].wake_up_self_adcx == 0)
+ return count;
+
+ error = strict_strtoul(buf, 0, &val);
+
+ if (!error)
+ data->wakeup_gesture_mode = (u8)val;
+
+ mxt_enable_gesture_mode(data);
+
+ return error ? : count;
+}
+
+static ssize_t mxt_sensitive_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+
+ count = sprintf(buf, "%d\n", (int)data->sensitive_mode);
+
+ return count;
+}
+
+static ssize_t mxt_sensitive_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ int error;
+
+ error = strict_strtoul(buf, 0, &val);
+ if (!error) {
+ if (val == 1) {
+ error = mxt_sensitive_mode_switch(data, true);
+ if (error)
+ dev_err(dev, "Failed to open sensitive mode!\n");
+ } else if (val == 0) {
+ error = mxt_sensitive_mode_switch(data, false);
+ if (error)
+ dev_err(dev, "Failed to close sensitive mode!\n");
+ }
+ }
+
+ return error ? : count;
+}
+
+
+static void mxt_control_hover(struct mxt_data *data, bool enable)
+{
+ int error;
+ u8 t8_val, t101_val;
+ struct device *dev = &data->client->dev;
+
+ if (enable) {
+ t8_val = 0x0F;
+ t101_val = 0x01;
+ } else {
+ t8_val = 0x0B;
+ t101_val = 0x00;
+ }
+
+ error = mxt_write_object(data, MXT_GEN_ACQUIRE_T8,
+ MXT_ACQUIRE_MEASALLOW, t8_val);
+ if (error) {
+ dev_err(dev, "Failed to set t8 value!\n");
+ return;
+ }
+
+ error = mxt_write_object(data, MXT_SPT_TOUCHSCREENHOVER_T101,
+ MXT_HOVER_CTRL, t101_val);
+ if (error)
+ dev_err(dev, "Failed to set t101 value!\n");
+}
+
+static ssize_t mxt_hover_tune_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+
+ count = sprintf(buf, "%d\n", (int)data->hover_tune_status);
+
+ return count;
+}
+
+static ssize_t mxt_hover_tune_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ int error;
+
+ error = strict_strtoul(buf, 0, &val);
+ if (!error) {
+ if (val == 1 && data->rev_id == REV_D) {
+ mxt_control_hover(data, true);
+ mxt_self_tune(data, MXT_SELFCMD_STM_TUNE);
+ if (mxt_self_tune_pass(data, true))
+ data->hover_tune_status = 1;
+ else
+ data->hover_tune_status = 0;
+ mxt_control_hover(data, false);
+ }
+ }
+
+ return error ? : count;
+}
+
+static ssize_t mxt_hover_from_flash_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ int error;
+
+ error = strict_strtoul(buf, 0, &val);
+ if (!error && val == 0)
+ schedule_work(&data->self_tuning_work);
+
+ return error ? : count;
+}
+
+static ssize_t mxt_panel_color_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+
+ if (get_hw_version_major() >= 5) {
+ /* Panel color only supported in X5.
+ * Color info is stored in lockdown info byte2 */
+ count = snprintf(buf, PAGE_SIZE, "%c\n",
+ data->lockdown_info[2]);
+ } else {
+ count = snprintf(buf, PAGE_SIZE, "%s\n",
+ "Unknown");
+ }
+
+ return count;
+}
+
+static int mxt_chip_reset(struct mxt_data *data)
+{
+ int error;
+
+ mxt_disable_irq(data);
+ if (get_hw_version_major() <= 4) {
+ /* Keep same behaviour in X4 */
+ gpio_set_value(data->pdata->power_gpio, 0);
+ msleep(20);
+ gpio_set_value(data->pdata->power_gpio, 1);
+ } else {
+ /* In X5, power is controlled by both LCD an TP, so just toggle the reset pin */
+ if (data->pdata->cut_off_power)
+ gpio_direction_output(data->pdata->reset_gpio, 1);
+
+ gpio_set_value(data->pdata->reset_gpio, 0);
+ msleep(20);
+ gpio_set_value(data->pdata->reset_gpio, 1);
+
+ if (data->pdata->cut_off_power)
+ gpio_direction_input(data->pdata->reset_gpio);
+ }
+ msleep(10);
+ mxt_wait_for_chg(data);
+ mxt_enable_irq(data);
+ error = mxt_soft_reset(data, MXT_RESET_VALUE);
+ if (error)
+ return error;
+
+ error = mxt_initialize(data);
+
+ schedule_work(&data->hover_loading_work);
+
+ return error;
+}
+
+static ssize_t mxt_chip_reset_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int error;
+ struct mxt_data *data = dev_get_drvdata(dev);
+
+ error = mxt_chip_reset(data);
+ if (error)
+ return error;
+ else
+ return count;
+}
+
+static ssize_t mxt_chg_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int count;
+ int chg_state;
+
+ chg_state = gpio_get_value(data->pdata->irq_gpio);
+ count = sprintf(buf, "%d\n", chg_state);
+
+ return count;
+}
+
+static void mxt_switch_mode_work(struct work_struct *work)
+{
+ struct mxt_mode_switch *ms = container_of(work, struct mxt_mode_switch, switch_mode_work);
+ struct mxt_data *data = ms->data;
+ const struct mxt_platform_data *pdata = data->pdata;
+ int index = data->current_index;
+ u8 value = ms->mode;
+
+ if (value == MXT_INPUT_EVENT_SENSITIVE_MODE_ON ||
+ value == MXT_INPUT_EVENT_SENSITIVE_MODE_OFF)
+ mxt_sensitive_mode_switch(data, (bool)(value - MXT_INPUT_EVENT_SENSITIVE_MODE_OFF));
+ else if (value == MXT_INPUT_EVENT_STYLUS_MODE_ON ||
+ value == MXT_INPUT_EVENT_STYLUS_MODE_OFF)
+ mxt_stylus_mode_switch(data, (bool)(value - MXT_INPUT_EVENT_STYLUS_MODE_OFF));
+ else if (value == MXT_INPUT_EVENT_WAKUP_MODE_ON ||
+ value == MXT_INPUT_EVENT_WAKUP_MODE_OFF) {
+ if (pdata->config_array[index].wake_up_self_adcx != 0) {
+ data->wakeup_gesture_mode = value - MXT_INPUT_EVENT_WAKUP_MODE_OFF;
+ mxt_enable_gesture_mode(data);
+ }
+ }
+
+ if (ms != NULL) {
+ kfree(ms);
+ ms = NULL;
+ }
+}
+
+static int mxt_input_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+{
+ struct mxt_data *data = input_get_drvdata(dev);
+ char buffer[16];
+ struct mxt_mode_switch *ms;
+
+ if (type == EV_SYN && code == SYN_CONFIG) {
+ if (data->debug_enabled) {
+ dev_info(&data->client->dev,
+ "event write value = %d \n", value);
+ }
+ sprintf(buffer, "%d", value);
+
+ if (value >= MXT_INPUT_EVENT_START && value <= MXT_INPUT_EVENT_END) {
+ ms = (struct mxt_mode_switch*)kmalloc(sizeof(struct mxt_mode_switch), GFP_ATOMIC);
+ if (ms != NULL) {
+ ms->data = data;
+ ms->mode = (u8)value;
+ INIT_WORK(&ms->switch_mode_work, mxt_switch_mode_work);
+ schedule_work(&ms->switch_mode_work);
+ } else {
+ dev_err(&data->client->dev,
+ "Failed in allocating memory for mxt_mode_switch!\n");
+ return -ENOMEM;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t mxt_mem_access_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = mxt_check_mem_access_params(data, off, &count);
+ if (ret < 0)
+ return ret;
+
+ if (count > 0)
+ ret = mxt_read_reg(data->client, off, count, buf);
+
+ return ret == 0 ? count : ret;
+}
+
+static ssize_t mxt_mem_access_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off,
+ size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = mxt_check_mem_access_params(data, off, &count);
+ if (ret < 0)
+ return ret;
+
+ if (count > 0)
+ ret = mxt_write_block(data->client, off, count, buf);
+
+ return ret == 0 ? count : 0;
+}
+
+static DEVICE_ATTR(update_fw, S_IWUSR | S_IRUSR, mxt_update_fw_show, mxt_update_fw_store);
+static DEVICE_ATTR(debug_enable, S_IWUSR | S_IRUSR, mxt_debug_enable_show,
+ mxt_debug_enable_store);
+static DEVICE_ATTR(keys_off, S_IWUSR | S_IRUSR, mxt_keys_off_show,
+ mxt_keys_off_store);
+static DEVICE_ATTR(pause_driver, S_IWUSR | S_IRUSR, mxt_pause_show,
+ mxt_pause_store);
+static DEVICE_ATTR(version, S_IRUGO, mxt_version_show, NULL);
+static DEVICE_ATTR(build, S_IRUGO, mxt_build_show, NULL);
+static DEVICE_ATTR(slowscan_enable, S_IWUSR | S_IRUSR,
+ mxt_slowscan_show, mxt_slowscan_store);
+static DEVICE_ATTR(self_tune, S_IWUSR, NULL, mxt_self_tune_store);
+static DEVICE_ATTR(update_fw_flag, S_IWUSR, NULL, mxt_update_fw_flag_store);
+static DEVICE_ATTR(selftest, S_IWUSR | S_IRUSR, mxt_selftest_show, mxt_selftest_store);
+static DEVICE_ATTR(stylus, S_IWUSR | S_IRUSR, mxt_stylus_show, mxt_stylus_store);
+static DEVICE_ATTR(diagnostic, S_IWUSR | S_IRUSR, mxt_diagnostic_show, mxt_diagnostic_store);
+static DEVICE_ATTR(sensitive_mode, S_IWUSR | S_IRUSR, mxt_sensitive_mode_show, mxt_sensitive_mode_store);
+static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, mxt_chip_reset_store);
+static DEVICE_ATTR(chg_state, S_IRUGO, mxt_chg_state_show, NULL);
+static DEVICE_ATTR(wakeup_mode, S_IWUSR | S_IRUSR, mxt_wakeup_mode_show, mxt_wakeup_mode_store);
+static DEVICE_ATTR(hover_tune, S_IWUSR | S_IRUSR, mxt_hover_tune_show, mxt_hover_tune_store);
+static DEVICE_ATTR(hover_from_flash, S_IWUSR, NULL, mxt_hover_from_flash_store);
+static DEVICE_ATTR(panel_color, S_IRUSR, mxt_panel_color_show, NULL);
+
+static struct attribute *mxt_attrs[] = {
+ &dev_attr_update_fw.attr,
+ &dev_attr_debug_enable.attr,
+ &dev_attr_pause_driver.attr,
+ &dev_attr_version.attr,
+ &dev_attr_keys_off.attr,
+ &dev_attr_build.attr,
+ &dev_attr_slowscan_enable.attr,
+ &dev_attr_self_tune.attr,
+ &dev_attr_update_fw_flag.attr,
+ &dev_attr_selftest.attr,
+ &dev_attr_stylus.attr,
+ &dev_attr_diagnostic.attr,
+ &dev_attr_sensitive_mode.attr,
+ &dev_attr_chip_reset.attr,
+ &dev_attr_chg_state.attr,
+ &dev_attr_wakeup_mode.attr,
+ &dev_attr_hover_tune.attr,
+ &dev_attr_hover_from_flash.attr,
+ &dev_attr_panel_color.attr,
+ NULL
+};
+
+static const struct attribute_group mxt_attr_group = {
+ .attrs = mxt_attrs,
+};
+
+static void mxt_set_t7_for_gesture(struct mxt_data *data, bool enable)
+{
+ int error, i;
+ u8 t7_gesture_enable[] = {
+ 135, 35, 20
+ };
+ u8 t7_gesture_disable[] = {
+ 32, 9, 20
+ };
+ u8 *t7_val;
+
+ if (enable)
+ t7_val = t7_gesture_enable;
+ else
+ t7_val = t7_gesture_disable;
+
+ for (i = 0; i < sizeof(t7_gesture_enable); i++) {
+ error = mxt_write_object(data, MXT_GEN_POWER_T7,
+ i, t7_val[i]);
+ if (error) {
+ pr_info("write to t7 byte %d failed!\n", i);
+ return;
+ }
+ }
+}
+
+static void mxt_set_gesture_wake_up(struct mxt_data *data, bool enable)
+{
+ int error, i;
+ struct device *dev = &data->client->dev;
+ u8 *t108_val;
+
+ if (enable)
+ t108_val = data->adcperx_wakeup;
+ else
+ t108_val = data->adcperx_normal;
+
+ for (i = 0; i < sizeof(data->adcperx_normal); i++) {
+ error = mxt_write_object(data, MXT_PROCG_NOISESUPSELFCAP_T108,
+ i + 19, t108_val[i]);
+ if (error) {
+ dev_err(dev, "write to t108 byte %d failed!\n", i);
+ return;
+ }
+ }
+
+ if (enable) {
+ error = mxt_set_clr_reg(data, MXT_PROCG_NOISESUPPRESSION_T72,
+ MXT_NOISESUP_CTRL, 0, MXT_NOICTRL_ENABLE);
+ } else {
+ error = mxt_set_clr_reg(data, MXT_PROCG_NOISESUPPRESSION_T72,
+ MXT_NOISESUP_CTRL, MXT_NOICTRL_ENABLE, 0);
+ }
+
+ if (error) {
+ dev_err(dev, "write to t72 failed!\n");
+ return;
+ }
+
+ if (enable) {
+ error = mxt_set_clr_reg(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_CTRL, 0, MXT_T100_CTRL_RPTEN);
+ } else {
+ error = mxt_set_clr_reg(data, MXT_TOUCH_MULTI_T100,
+ MXT_MULTITOUCH_CTRL, MXT_T100_CTRL_RPTEN, 0);
+ }
+
+ if (error) {
+ dev_err(dev, "write to t100 failed!\n");
+ return;
+ }
+
+ if (enable) {
+ error = mxt_set_clr_reg(data, MXT_TOUCH_KEYARRAY_T15,
+ MXT_KEYARRAY_CTRL, 0, MXT_KEY_RPTEN);
+ } else {
+ error = mxt_set_clr_reg(data, MXT_TOUCH_KEYARRAY_T15,
+ MXT_KEYARRAY_CTRL, MXT_KEY_RPTEN, 0);
+ }
+
+ if (error)
+ dev_err(dev, "write to t15 failed!\n");
+}
+
+static void mxt_start(struct mxt_data *data)
+{
+ int error;
+ struct device *dev = &data->client->dev;
+
+ if (data->wakeup_gesture_mode) {
+ mxt_set_gesture_wake_up(data, false);
+ if (!data->is_wakeup_by_gesture)
+ mxt_set_t7_for_gesture(data, false);
+ data->is_stopped = 0;
+ return;
+ } else {
+ if (data->is_stopped == 0)
+ return;
+
+ error = mxt_set_power_cfg(data, MXT_POWER_CFG_RUN);
+ if (error)
+ return;
+ /* At this point, it may be necessary to clear state
+ * by disabling/re-enabling the noise suppression object */
+
+ /* Recalibrate since chip has been in deep sleep */
+ schedule_delayed_work(&data->calibration_delayed_work, msecs_to_jiffies(100));
+ }
+
+ dev_dbg(dev, "MXT started\n");
+}
+
+static void mxt_stop(struct mxt_data *data)
+{
+ int error;
+ struct device *dev = &data->client->dev;
+
+ if (data->wakeup_gesture_mode) {
+ data->is_wakeup_by_gesture = false;
+ mxt_set_t7_for_gesture(data, true);
+ mxt_set_gesture_wake_up(data, true);
+ data->is_stopped = 1;
+ } else {
+ if (data->is_stopped)
+ return;
+
+ cancel_delayed_work_sync(&data->calibration_delayed_work);
+ error = mxt_set_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
+
+ if (!error)
+ dev_dbg(dev, "MXT suspended\n");
+ }
+}
+
+static int mxt_input_open(struct input_dev *dev)
+{
+ struct mxt_data *data = input_get_drvdata(dev);
+
+ mxt_start(data);
+
+ return 0;
+}
+
+static void mxt_input_close(struct input_dev *dev)
+{
+ struct mxt_data *data = input_get_drvdata(dev);
+
+ mxt_stop(data);
+}
+
+static void mxt_clear_touch_event(struct mxt_data *data)
+{
+ struct input_dev *input_dev = data->input_dev;
+ int index = data->current_index;
+ int id, i;
+
+ for (id = 0; id < data->num_touchids - 2; id++) {
+ input_mt_slot(input_dev, id);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
+ data->finger_down[id] = false;
+ }
+ for (i = 0; i < data->pdata->config_array[index].key_num; i++)
+ clear_bit(data->pdata->config_array[index].key_codes[i], input_dev->key);
+
+ input_sync(input_dev);
+}
+
+static int mxt_suspend(struct device *dev)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mxt_data *data = i2c_get_clientdata(client);
+ struct input_dev *input_dev = data->input_dev;
+
+ if (data->pdata->cut_off_power) {
+ /* In the power is cut off with LCD off, wake up gesture can not be used */
+ mutex_lock(&input_dev->mutex);
+
+ if (data->is_stopped) {
+ mutex_unlock(&input_dev->mutex);
+ return 0;
+ }
+
+ mxt_disable_irq(data);
+ gpio_set_value(data->pdata->reset_gpio, 0);
+
+ mxt_clear_touch_event(data);
+
+ if (data->regulator_vdd && data->regulator_avdd && data->regulator_vddio) {
+ ret = regulator_disable(data->regulator_avdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator disable for avdd failed: %d\n", ret);
+ }
+ ret = regulator_disable(data->regulator_vdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator disable for vdd failed: %d\n", ret);
+ }
+
+ ret = regulator_disable(data->regulator_vddio);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator disable for vddio failed: %d\n", ret);
+ }
+ }
+
+ data->is_stopped = 1;
+
+ mutex_unlock(&input_dev->mutex);
+ } else {
+ if (!data->wakeup_gesture_mode)
+ mxt_disable_irq(data);
+
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ mxt_stop(data);
+
+ mutex_unlock(&input_dev->mutex);
+
+ mxt_clear_touch_event(data);
+
+ if (data->regulator_vdd && data->regulator_avdd && data->regulator_vddio) {
+ ret = regulator_disable(data->regulator_avdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator disable for avdd failed: %d\n", ret);
+ }
+ ret = regulator_disable(data->regulator_vdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator disable for vdd failed: %d\n", ret);
+ }
+ ret = regulator_disable(data->regulator_vddio);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator disable for vddio failed: %d\n", ret);
+ }
+ }
+ }
+
+
+ return 0;
+}
+
+static int mxt_resume(struct device *dev)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mxt_data *data = i2c_get_clientdata(client);
+ struct input_dev *input_dev = data->input_dev;
+
+ if (data->pdata->cut_off_power) {
+ mutex_lock(&input_dev->mutex);
+
+ if (!data->is_stopped) {
+ mutex_unlock(&input_dev->mutex);
+ return 0;
+ }
+
+ if (data->regulator_vdd && data->regulator_avdd && data->regulator_vddio) {
+ ret = regulator_enable(data->regulator_vdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator enable for vdd failed: %d\n", ret);
+ }
+ ret = regulator_enable(data->regulator_avdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator enable for avdd failed: %d\n", ret);
+ }
+ ret = regulator_enable(data->regulator_vddio);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator enable for vddio failed: %d\n", ret);
+ }
+ }
+
+ mxt_wait_for_chg(data);
+ mxt_enable_irq(data);
+ schedule_delayed_work(&data->calibration_delayed_work, msecs_to_jiffies(100));
+ data->is_stopped = false;
+
+ mutex_unlock(&input_dev->mutex);
+ } else {
+ if (!data->wakeup_gesture_mode)
+ mxt_enable_irq(data);
+
+ if (data->regulator_vdd && data->regulator_avdd && data->regulator_vddio) {
+ ret = regulator_enable(data->regulator_vdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator enable for vdd failed: %d\n", ret);
+ }
+ ret = regulator_enable(data->regulator_avdd);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator enable for avdd failed: %d\n", ret);
+ }
+ ret = regulator_enable(data->regulator_vddio);
+ if (ret < 0) {
+ dev_err(dev,
+ "Atmel regulator enable for vddio failed: %d\n", ret);
+ }
+ }
+
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ mxt_start(data);
+
+ mutex_unlock(&input_dev->mutex);
+ }
+ return 0;
+}
+
+static int mxt_input_enable(struct input_dev *in_dev)
+{
+ int error = 0;
+ struct mxt_data *ts = input_get_drvdata(in_dev);
+
+ error = mxt_resume(&ts->client->dev);
+ if (error)
+ dev_err(&ts->client->dev, "%s: failed\n", __func__);
+
+ return error;
+}
+
+static int mxt_input_disable(struct input_dev *in_dev)
+{
+ int error = 0;
+ struct mxt_data *ts = input_get_drvdata(in_dev);
+
+ error = mxt_suspend(&ts->client->dev);
+ if (error)
+ dev_err(&ts->client->dev, "%s: failed\n", __func__);
+
+ return error;
+}
+
+#ifdef CONFIG_FB
+static int fb_notifier_cb(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ int *blank;
+ struct mxt_data *mxt_data =
+ container_of(self, struct mxt_data, fb_notif);
+
+ if (evdata && evdata->data && event == FB_EVENT_BLANK && mxt_data) {
+ blank = evdata->data;
+ if (*blank == FB_BLANK_UNBLANK) {
+ dev_info(&mxt_data->client->dev, "##### UNBLANK SCREEN #####\n");
+ mxt_input_enable(mxt_data->input_dev);
+ } else if (*blank == FB_BLANK_POWERDOWN) {
+ dev_info(&mxt_data->client->dev, "##### BLANK SCREEN #####\n");
+ mxt_input_disable(mxt_data->input_dev);
+ }
+ }
+
+ return 0;
+}
+
+static void configure_sleep(struct mxt_data *data)
+{
+ int ret;
+
+ data->fb_notif.notifier_call = fb_notifier_cb;
+ ret = fb_register_client(&data->fb_notif);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "Unable to register fb_notifier, err: %d\n", ret);
+ }
+}
+#else
+static void configure_sleep(struct mxt_data *data)
+{
+ data->input_dev->enable = mxt_input_enable;
+ data->input_dev->disable = mxt_input_disable;
+ data->input_dev->enabled = true;
+}
+#endif
+
+static int mxt_initialize_input_device(struct mxt_data *data)
+{
+ struct device *dev = &data->client->dev;
+ struct input_dev *input_dev;
+ int ret;
+ int i;
+ int index = data->current_index;
+
+ /* Initialize input device */
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ dev_err(dev, "Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ if (data->pdata->input_name) {
+ input_dev->name = data->pdata->input_name;
+ } else {
+ input_dev->name = "atmel-maxtouch";
+ }
+
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = dev;
+ input_dev->open = mxt_input_open;
+ input_dev->close = mxt_input_close;
+ input_dev->event = mxt_input_event;
+
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+
+ /* For multi touch */
+ input_mt_init_slots(input_dev,
+ data->num_touchids + data->num_stylusids);
+ if (data->t100_tchaux_bits & MXT_T100_AREA) {
+ dev_info(dev, "report area\n");
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, MXT_MAX_AREA, 0, 0);
+ }
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, data->max_x, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, data->max_y, 0, 0);
+ if (data->t100_tchaux_bits & MXT_T100_AMPL) {
+ dev_info(dev, "report pressure\n");
+ input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+ 0, 255, 0, 0);
+ }
+ if (data->t100_tchaux_bits & MXT_T100_VECT) {
+ dev_info(dev, "report vect\n");
+ input_set_abs_params(input_dev, ABS_MT_ORIENTATION,
+ 0, 255, 0, 0);
+ }
+
+ /* For T63 active stylus */
+ if (data->T63_reportid_min) {
+ __set_bit(BTN_STYLUS, input_dev->keybit);
+ __set_bit(BTN_STYLUS2, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
+ 0, MT_TOOL_MAX, 0, 0);
+ }
+
+ /* For T15 key array */
+ if (data->pdata->config_array[index].key_codes) {
+ for (i = 0; i < data->pdata->config_array[index].key_num; i++) {
+ if (data->pdata->config_array[index].key_codes[i])
+ input_set_capability(input_dev, EV_KEY,
+ data->pdata->config_array[index].key_codes[i]);
+ }
+ }
+
+ input_set_drvdata(input_dev, data);
+
+ ret = input_register_device(input_dev);
+ if (ret) {
+ dev_err(dev, "Error %d registering input device\n", ret);
+ input_free_device(input_dev);
+ return ret;
+ }
+
+ data->input_dev = input_dev;
+
+ configure_sleep(data);
+
+ return 0;
+}
+
+static struct dentry *debug_base;
+
+static int mxt_debugfs_object_show(struct seq_file *m, void *v)
+{
+ struct mxt_data *data = m->private;
+ struct mxt_object *object;
+ struct device *dev = &data->client->dev;
+ int i, j, k;
+ int error;
+ int obj_size;
+ u8 val;
+
+ seq_printf(m,
+ "Family ID: %02X Variant ID: %02X Version: %d.%d Build: 0x%02X"
+ "\nObject Num: %dMatrix X Size: %d Matrix Y Size: %d\n",
+ data->info.family_id, data->info.variant_id,
+ data->info.version >> 4, data->info.version & 0xf,
+ data->info.build, data->info.object_num,
+ data->info.matrix_xsize, data->info.matrix_ysize);
+
+ for (i = 0; i < data->info.object_num; i++) {
+ object = data->object_table + i;
+ obj_size = object->size + 1;
+
+ for (j = 0; j < object->instances; j++) {
+ seq_printf(m, "Type %d NumId %d MaxId %d\n",
+ object->type, object->num_report_ids,
+ object->max_reportid);
+
+ for (k = 0; k < obj_size; k++) {
+ error = mxt_read_object(data, object->type,
+ j * obj_size + k, &val);
+ if (error) {
+ dev_err(dev,
+ "Failed to read object %d "
+ "instance %d at offset %d\n",
+ object->type, j, k);
+ return error;
+ }
+
+ seq_printf(m, "%02x ", val);
+ if (k % 10 == 9 || k + 1 == obj_size)
+ seq_printf(m, "\n");
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t mxt_debugfs_object_store(struct file *file,
+ const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct seq_file *m = file->private_data;
+ struct mxt_data *data = m->private;
+ u8 type, offset, val;
+ int error;
+
+ if (sscanf(buf, "%hhu:%hhu=%hhx", &type, &offset, &val) == 3) {
+ error = mxt_write_object(data, type, offset, val);
+ if (error)
+ count = error;
+ } else
+ count = -EINVAL;
+
+ return count;
+}
+
+static int mxt_debugfs_object_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mxt_debugfs_object_show, inode->i_private);
+}
+
+static const struct file_operations mxt_object_fops = {
+ .owner = THIS_MODULE,
+ .open = mxt_debugfs_object_open,
+ .read = seq_read,
+ .write = mxt_debugfs_object_store,
+ .release = single_release,
+};
+
+static void __devinit mxt_debugfs_init(struct mxt_data *data)
+{
+ debug_base = debugfs_create_dir(MXT_DEBUGFS_DIR, NULL);
+ if (IS_ERR_OR_NULL(debug_base))
+ pr_err("atmel_mxt_ts: Failed to create debugfs dir\n");
+ if (IS_ERR_OR_NULL(debugfs_create_file(MXT_DEBUGFS_FILE,
+ 0444,
+ debug_base,
+ data,
+ &mxt_object_fops))) {
+ pr_err("atmel_mxt_ts: Failed to create object file\n");
+ debugfs_remove_recursive(debug_base);
+ }
+}
+
+static void mxt_update_fw_by_flag(struct mxt_data *data)
+{
+ const struct mxt_platform_data *pdata = data->pdata;
+ int error;
+
+ if (data->update_flag == 0x01) {
+ error = mxt_update_fw_flag_store(&data->client->dev, NULL, "0", 2);
+ if (error != 2) {
+ dev_err(&data->client->dev, "Failed to set T38 flag to 0!\n");
+ return;
+ }
+ else {
+ error = mxt_update_fw_store(&data->client->dev, NULL,
+ pdata->mxt_fw_name, strlen(pdata->mxt_fw_name));
+ if (error) {
+ dev_err(&data->client->dev, "Unable to update firmware!\n");
+ return;
+ }
+ }
+ }
+
+}
+
+static void mxt_dump_value(struct device *dev, struct mxt_platform_data *pdata)
+{
+ int i = 0;
+
+ dev_info(dev, "reset gpio= %d\n", pdata->reset_gpio);
+ dev_info(dev, "irq gpio= %d\n", pdata->irq_gpio);
+ dev_info(dev, "power gpio= %d\n", pdata->power_gpio);
+ dev_info(dev, "fw name = %s\n", pdata->mxt_fw_name);
+ dev_info(dev, "config size = %d\n", pdata->config_array_size);
+ dev_info(dev, "gpio mask = 0x%x\n", pdata->gpio_mask);
+ dev_info(dev, "cut off power = %d\n", (int)pdata->cut_off_power);
+
+ for (i = 0; i < pdata->config_array_size; i++) {
+ dev_info(dev, "family_id = 0x%x\n", pdata->config_array[i].family_id);
+ dev_info(dev, "variant_id = 0x%x\n", pdata->config_array[i].variant_id);
+ dev_info(dev, "version = 0x%x\n", pdata->config_array[i].version);
+ dev_info(dev, "build = 0x%x\n", pdata->config_array[i].build);
+ dev_info(dev, "mxt_cfg_name = %s\n", pdata->config_array[i].mxt_cfg_name);
+ dev_info(dev, "vendor_id = 0x%x\n", pdata->config_array[i].vendor_id);
+ dev_info(dev, "rev_id = 0x%x\n", pdata->config_array[i].rev_id);
+ dev_info(dev, "wakeup self adcx = 0x%x\n", pdata->config_array[i].wake_up_self_adcx);
+ }
+}
+
+#ifdef CONFIG_OF
+static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
+{
+ int ret;
+ struct mxt_config_info *info;
+ struct device_node *temp, *np = dev->of_node;
+ u32 temp_val;
+
+ /* reset, irq, power gpio info */
+ pdata->reset_gpio = of_get_named_gpio_flags(np, "atmel,reset-gpio",
+ 0, &pdata->reset_gpio_flags);
+ pdata->irq_gpio = of_get_named_gpio_flags(np, "atmel,irq-gpio",
+ 0, &pdata->irq_gpio_flags);
+ if (get_hw_version_major() <= 4)
+ pdata->power_gpio = of_get_named_gpio_flags(np, "atmel,power-gpio",
+ 0, &pdata->power_gpio_flags);
+ else
+ pdata->power_gpio = -EINVAL;
+
+ ret = of_property_read_u32(np, "atmel,irqflags", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read irqflags id\n");
+ return ret;
+ } else
+ pdata->irqflags = temp_val;
+
+ ret = of_property_read_string(np, "atmel,mxt-fw-name",
+ &pdata->mxt_fw_name);
+ if (ret && (ret != -EINVAL)) {
+ dev_err(dev, "Unable to read fw name\n");
+ return ret;
+ }
+
+ pdata->cut_off_power = of_property_read_bool(np, "atmel,cut-off-power");
+
+ ret = of_property_read_u32(np, "atmel,gpio-mask", (u32*)&temp_val);
+ if (ret)
+ dev_err(dev, "Unable to read gpio mask\n");
+ else
+ pdata->gpio_mask = (u8)temp_val;
+
+ ret = of_property_read_u32(np, "atmel,config-array-size", &pdata->config_array_size);
+ if (ret) {
+ dev_err(dev, "Unable to get array size\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "atmel,default-config", &pdata->default_config);
+ if (ret) {
+ dev_err(dev, "Unable to get default config\n");
+ pdata->default_config = -1;
+ }
+
+ pdata->config_array = devm_kzalloc(dev, pdata->config_array_size *
+ sizeof(struct mxt_config_info), GFP_KERNEL);
+ if (!pdata->config_array) {
+ dev_err(dev, "Unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ info = pdata->config_array;
+
+ for_each_child_of_node(np, temp) {
+ ret = of_property_read_u32(temp, "atmel,family-id", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read family id\n");
+ return ret;
+ } else
+ info->family_id = (u8)temp_val;
+ ret = of_property_read_u32(temp, "atmel,variant-id", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read variant id\n");
+ return ret;
+ } else
+ info->variant_id = (u8)temp_val;
+ ret = of_property_read_u32(temp, "atmel,version", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read version\n");
+ return ret;
+ } else
+ info->version = (u8)temp_val;
+ ret = of_property_read_u32(temp, "atmel,build", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read build\n");
+ return ret;
+ } else
+ info->build = (u8)temp_val;
+ ret = of_property_read_string(temp, "atmel,mxt-cfg-name",
+ &info->mxt_cfg_name);
+ if (ret && (ret != -EINVAL)) {
+ dev_err(dev, "Unable to read cfg name\n");
+ return ret;
+ }
+ ret = of_property_read_u32(temp, "atmel,vendor-id", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read vendor id\n");
+ return ret;
+ } else
+ info->vendor_id = (u8)temp_val;
+ ret = of_property_read_u32(temp, "atmel,rev-id", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read rev id\n");
+ return ret;
+ } else
+ info->rev_id = (u8)temp_val;
+
+ ret = of_property_read_u32(temp, "atmel,key-num", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read key num id\n");
+ return ret;
+ } else
+ info->key_num = temp_val;
+ if (info->key_num != 0) {
+ info->key_codes = devm_kzalloc(dev,
+ sizeof(int) * info->key_num, GFP_KERNEL);
+ if (!info->key_codes)
+ return -ENOMEM;
+ ret = of_property_read_u32_array(temp, "atmel,key-codes",
+ info->key_codes, info->key_num);
+ if (ret) {
+ dev_err(dev, "Unable to read key codes\n");
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u32(temp, "atmel,selfintthr-stylus", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read selfintthr-stylus\n");
+ return ret;
+ } else
+ info->selfintthr_stylus = temp_val;
+ ret = of_property_read_u32(temp, "atmel,t71-tchthr-pos", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read t71-glove-ctrl-reg\n");
+ return ret;
+ } else
+ info->t71_tchthr_pos = temp_val;
+ ret = of_property_read_u32(temp, "atmel,self-chgtime-min", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read self-chgtime-min\n");
+ return ret;
+ } else
+ info->self_chgtime_min = temp_val;
+ ret = of_property_read_u32(temp, "atmel,self-chgtime-max", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read self-chgtime-max\n");
+ return ret;
+ } else
+ info->self_chgtime_max = temp_val;
+ ret = of_property_read_u32(temp, "atmel,mult-intthr-sensitive", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read mult-intthr-sensitive\n");
+ return ret;
+ } else
+ info->mult_intthr_sensitive = temp_val;
+ ret = of_property_read_u32(temp, "atmel,mult-intthr-not-sensitive", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read mult-intthr-not-sensitive\n");
+ return ret;
+ } else
+ info->mult_intthr_not_sensitive = temp_val;
+ ret = of_property_read_u32(temp, "atmel,atchthr-sensitive", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read mult-intthr-not-sensitive\n");
+ return ret;
+ } else
+ info->atchthr_sensitive = temp_val;
+ ret = of_property_read_u32(temp, "atmel,mult-tchthr-sensitive", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read mult-tchthr-sensitive\n");
+ return ret;
+ } else
+ info->mult_tchthr_sensitive = temp_val;
+ ret = of_property_read_u32(temp, "atmel,mult-tchthr-not-sensitive", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read mult-tchthr-not-sensitive\n");
+ return ret;
+ } else
+ info->mult_tchthr_not_sensitive = temp_val;
+
+ ret = of_property_read_u32(temp, "atmel,wake-up-self-adcx", &temp_val);
+ if (ret) {
+ dev_err(dev, "Unable to read wake-up-self-adcx\n");
+ return ret;
+ } else
+ info->wake_up_self_adcx = (u8)temp_val;
+
+
+ info++;
+ }
+
+ mxt_dump_value(dev, pdata);
+
+ return 0;
+}
+#else
+static int mxt_parse_dt(struct device *dev, struct mxt_platform_data *pdata)
+{
+ return -ENODEV;
+}
+#endif
+
+static int __devinit mxt_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mxt_platform_data *pdata;
+ struct mxt_data *data;
+ int error;
+ struct gpiomux_setting old_rst_setting, old_int_setting;
+
+ if (get_hw_version_major() < 4)
+ return -ENODEV;
+
+ if (client->dev.of_node) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct mxt_platform_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ error = mxt_parse_dt(&client->dev, pdata);
+ if (error)
+ return error;
+ } else
+ pdata = client->dev.platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ data->state = INIT;
+
+ data->client = client;
+ data->pdata = pdata;
+ data->irq = client->irq;
+
+ /* In X5 platform, we do not need to control touchscreen power,
+ which is enabled by LCD */
+ if (get_hw_version_major() <= 4) {
+ /* In X4 platform, we need to control power gpio by ourselves */
+ if (gpio_is_valid(pdata->power_gpio)) {
+ error = gpio_request(pdata->power_gpio, "mxt_gpio_power");
+ if (!error) {
+ error = gpio_direction_output(pdata->power_gpio, 1);
+ if (error) {
+ pr_err("%s: unable to set direction gpio %d\n",
+ __func__, pdata->power_gpio);
+ goto err_disable_regulator;
+ }
+ } else {
+ pr_err("%s: unable to request power gpio %d\n",
+ __func__, pdata->power_gpio);
+ goto err_free_data;
+ }
+ }
+ } else {
+ /* In X5 platform, if we need to cut off power when lcd is off,
+ * we should also control the power regulator */
+ if (pdata->cut_off_power)
+ mxt_initialize_regulator(data);
+ }
+
+ if (gpio_is_valid(pdata->irq_gpio)) {
+ /* configure touchscreen irq gpio */
+ error = gpio_request(pdata->irq_gpio, "mxt_irq_gpio");
+ if (error) {
+ pr_err("%s: unable to request gpio [%d]\n", __func__,
+ pdata->irq_gpio);
+ goto err_disable_regulator;
+ }
+ error = gpio_direction_input(pdata->irq_gpio);
+ if (error) {
+ pr_err("%s: unable to set_direction for gpio [%d]\n",
+ __func__, pdata->irq_gpio);
+ goto err_irq_gpio_req;
+ }
+ }
+
+ if (gpio_is_valid(pdata->reset_gpio)) {
+ /* configure touchscreen reset out gpio */
+ error = gpio_request(pdata->reset_gpio, "mxt_reset_gpio");
+ if (error) {
+ pr_err("%s: unable to request reset gpio %d\n",
+ __func__, pdata->reset_gpio);
+ goto err_irq_gpio_req;
+ }
+
+ error = gpio_direction_output(pdata->reset_gpio, 1);
+ if (error) {
+ pr_err("%s: unable to set direction for gpio %d\n",
+ __func__, pdata->reset_gpio);
+ goto err_reset_gpio_req;
+ }
+ }
+
+ i2c_set_clientdata(data->client, data);
+ mdelay(10);
+ mxt_wait_for_chg(data);
+ INIT_WORK(&data->self_tuning_work, mxt_self_tuning_work);
+ INIT_WORK(&data->hover_loading_work, mxt_hover_loading_work);
+ INIT_DELAYED_WORK(&data->calibration_delayed_work,
+ mxt_calibration_delayed_work);
+ /* Initialize i2c device */
+retry:
+ error = mxt_initialize(data);
+ if (error)
+ {
+ if (gpio_is_valid(pdata->power_gpio))
+ pr_err("power gpio = %d\n", (int)gpio_get_value(pdata->power_gpio));
+ pr_err("reset gpio = %d\n", (int)gpio_get_value(pdata->reset_gpio));
+ pr_err("chg gpio = %d\n", (int)gpio_get_value(pdata->irq_gpio));
+
+ if (error != -ENOENT) {
+ if (client->addr == 0x4a)
+ goto err_reset_gpio_req;
+ else {
+ client->addr = 0x4a;
+ goto retry;
+ }
+ }
+ else {
+ error = mxt_update_firmware(&client->dev, NULL,
+ pdata->mxt_fw_name, strlen(pdata->mxt_fw_name), &data->firmware_updated);
+ if (error != strlen(pdata->mxt_fw_name))
+ {
+ dev_err(&client->dev, "Error when update firmware!\n");
+ goto err_reset_gpio_req;
+ }
+ }
+ }
+
+ /*
+ * In X5 platform, since we will cut off lcd power when display is off.
+ * To avoid a powerup issue, we will set RST pin to HI-Z and disable
+ * internal pull-up resistor on INT pin
+ */
+ if (get_hw_version_major() == 5 && pdata->cut_off_power) {
+ if (msm_gpiomux_write(pdata->reset_gpio, GPIOMUX_ACTIVE,
+ &mxt_rst_cutoff_pwr_cfg, &old_rst_setting)) {
+ dev_err(&client->dev, "Failed to set RESET pinmux setting\n");
+ goto err_free_object;
+ }
+
+ if (msm_gpiomux_write(pdata->irq_gpio, GPIOMUX_ACTIVE,
+ &mxt_int_cutoff_pwr_cfg, &old_int_setting)) {
+ dev_err(&client->dev, "Failed to set INT pinmux setting\n");
+ goto err_restore_rst_gpio_setting;
+ }
+
+ if (gpio_direction_input(pdata->reset_gpio)) {
+ dev_err(&client->dev, "Failed to set RESET pin to input\n");
+ goto err_restore_int_gpio_setting;
+ }
+ mdelay(10);
+ mxt_wait_for_chg(data);
+ }
+
+ if (0)
+ mxt_update_fw_by_flag(data);
+
+ error = mxt_initialize_input_device(data);
+ if (error)
+ goto err_restore_int_gpio_setting;
+
+ error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
+ pdata->irqflags, client->dev.driver->name, data);
+ if (error) {
+ dev_err(&client->dev, "Error %d registering irq\n", error);
+ goto err_free_input_device;
+ }
+ data->irq_enabled = true;
+
+ device_init_wakeup(&client->dev, 1);
+
+ error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
+ if (error) {
+ dev_err(&client->dev, "Failure %d creating sysfs group\n",
+ error);
+ goto err_free_irq;
+ }
+
+
+ sysfs_bin_attr_init(&data->mem_access_attr);
+ data->mem_access_attr.attr.name = "mem_access";
+ data->mem_access_attr.attr.mode = S_IRUGO | S_IWUSR;
+ data->mem_access_attr.read = mxt_mem_access_read;
+ data->mem_access_attr.write = mxt_mem_access_write;
+ data->mem_access_attr.size = data->mem_size;
+
+ if (sysfs_create_bin_file(&client->dev.kobj,
+ &data->mem_access_attr) < 0) {
+ dev_err(&client->dev, "Failed to create %s\n",
+ data->mem_access_attr.attr.name);
+ goto err_remove_sysfs_group;
+ }
+
+ mxt_debugfs_init(data);
+ schedule_work(&data->hover_loading_work);
+
+ return 0;
+
+err_remove_sysfs_group:
+ sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
+err_free_irq:
+ free_irq(client->irq, data);
+err_free_input_device:
+ input_unregister_device(data->input_dev);
+err_free_object:
+ kfree(data->msg_buf);
+ kfree(data->object_table);
+err_restore_int_gpio_setting:
+ if (get_hw_version_major() == 5 && pdata->cut_off_power)
+ msm_gpiomux_write(pdata->irq_gpio, GPIOMUX_ACTIVE,
+ &old_int_setting, NULL);
+err_restore_rst_gpio_setting:
+ if (get_hw_version_major() == 5 && pdata->cut_off_power)
+ msm_gpiomux_write(pdata->reset_gpio, GPIOMUX_ACTIVE,
+ &old_rst_setting, NULL);
+err_reset_gpio_req:
+ if (gpio_is_valid(pdata->reset_gpio))
+ gpio_free(pdata->reset_gpio);
+err_irq_gpio_req:
+ if (gpio_is_valid(pdata->irq_gpio))
+ gpio_free(pdata->irq_gpio);
+err_disable_regulator:
+ if (gpio_is_valid(pdata->power_gpio)) {
+ gpio_set_value_cansleep(pdata->power_gpio, 0);
+ gpio_free(pdata->power_gpio);
+ }
+ if (data->regulator_vdd)
+ regulator_disable(data->regulator_vdd);
+ if (data->regulator_avdd)
+ regulator_disable(data->regulator_avdd);
+ if (data->regulator_vddio)
+ regulator_disable(data->regulator_vddio);
+err_free_data:
+ kfree(data);
+ return error;
+}
+
+static int __devexit mxt_remove(struct i2c_client *client)
+{
+ struct mxt_data *data = i2c_get_clientdata(client);
+ const struct mxt_platform_data *pdata = data->pdata;
+
+ sysfs_remove_bin_file(&client->dev.kobj, &data->mem_access_attr);
+ sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
+ free_irq(data->irq, data);
+ input_unregister_device(data->input_dev);
+ kfree(data->msg_buf);
+ data->msg_buf = NULL;
+ kfree(data->object_table);
+ data->object_table = NULL;
+ if (gpio_is_valid(pdata->power_gpio)) {
+ gpio_set_value_cansleep(pdata->power_gpio, 0);
+ gpio_free(pdata->power_gpio);
+ }
+ if (data->regulator_vdd)
+ regulator_disable(data->regulator_vdd);
+ if (data->regulator_avdd)
+ regulator_disable(data->regulator_avdd);
+ if (data->regulator_vddio)
+ regulator_disable(data->regulator_vddio);
+
+ if (gpio_is_valid(pdata->irq_gpio))
+ gpio_free (pdata->irq_gpio);
+
+ if (gpio_is_valid(pdata->reset_gpio))
+ gpio_free(pdata->reset_gpio);
+
+ kfree(data);
+ data = NULL;
+
+ return 0;
+}
+
+static void mxt_shutdown(struct i2c_client *client)
+{
+ struct mxt_data *data = i2c_get_clientdata(client);
+
+ mxt_disable_irq(data);
+ data->state = SHUTDOWN;
+}
+
+#ifdef CONFIG_PM
+static int mxt_ts_suspend(struct device *dev)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev) &&
+ data->wakeup_gesture_mode) {
+ dev_info(dev, "touch enable irq wake\n");
+ mxt_disable_irq(data);
+ enable_irq_wake(data->client->irq);
+ }
+
+ return 0;
+}
+
+static int mxt_ts_resume(struct device *dev)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev) &&
+ data->wakeup_gesture_mode) {
+ dev_info(dev, "touch disable irq wake\n");
+ disable_irq_wake(data->client->irq);
+ mxt_enable_irq(data);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops mxt_touchscreen_pm_ops = {
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = mxt_ts_suspend,
+ .resume = mxt_ts_resume,
+#endif
+};
+#endif
+
+static const struct i2c_device_id mxt_id[] = {
+ { "qt602240_ts", 0 },
+ { "atmel_mxt_ts_640t", 0 },
+ { "mXT224", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mxt_id);
+
+#ifdef CONFIG_OF
+static struct of_device_id mxt_match_table[] = {
+ { .compatible = "atmel,mxt-ts-640t",},
+ { },
+};
+#else
+#define mxt_match_table NULL
+#endif
+
+static struct i2c_driver mxt_driver = {
+ .driver = {
+ .name = "atmel_mxt_ts_640t",
+ .owner = THIS_MODULE,
+ .of_match_table = mxt_match_table,
+#ifdef CONFIG_PM
+ .pm = &mxt_touchscreen_pm_ops,
+#endif
+ },
+ .probe = mxt_probe,
+ .remove = __devexit_p(mxt_remove),
+ .shutdown = mxt_shutdown,
+ .id_table = mxt_id,
+};
+
+static int __init mxt_init(void)
+{
+ return i2c_add_driver(&mxt_driver);
+}
+
+static void __exit mxt_exit(void)
+{
+ i2c_del_driver(&mxt_driver);
+}
+
+late_initcall(mxt_init);
+module_exit(mxt_exit);
+
+/* Module information */
+MODULE_AUTHOR("Lionel Zhang <zhangbo_a@xiaomi.com>");
+MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/doubletap2wake.c b/drivers/input/touchscreen/doubletap2wake.c
deleted file mode 100644
index 40a1801..0000000
--- a/drivers/input/touchscreen/doubletap2wake.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * drivers/input/touchscreen/doubletap2wake.c
- *
- *
- * Copyright (c) 2013, Dennis Rassmann <showp1984@gmail.com>
- * Copyright (c) 2015, Vineeth Raj <contact.twn@openmailbox.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/input/doubletap2wake.h>
-#include <linux/input/wake_helpers.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/input.h>
-#include <linux/hrtimer.h>
-#include <asm-generic/cputime.h>
-
-/* uncomment since no touchscreen defines android touch, do that here */
-//#define ANDROID_TOUCH_DECLARED
-
-/* uncomment if dt2w_scr_suspended is updated automagically */
-//#define WAKE_HOOKS_DEFINED
-
-#ifndef WAKE_HOOKS_DEFINED
-#ifndef CONFIG_HAS_EARLYSUSPEND
-#include <linux/lcd_notify.h>
-#else
-#include <linux/earlysuspend.h>
-#endif
-#endif // WAKE_HOOKS_DEFINED
-
-/* if Sweep2Wake is compiled it will already have taken care of this */
-//#ifdef CONFIG_TOUCHSCREEN_SWEEP2WAKE
-//#define ANDROID_TOUCH_DECLARED
-//#endif
-
-/* Version, author, desc, etc */
-#define DRIVER_AUTHOR "Dennis Rassmann <showp1984@gmail.com>"
-#define DRIVER_DESCRIPTION "Doubletap2wake for almost any device"
-#define DRIVER_VERSION "1.4"
-#define LOGTAG "[doubletap2wake]: "
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPLv2");
-
-/* Tuneables */
-#define DT2W_DEBUG 0
-#define DT2W_DEFAULT 1
-
-#define DT2W_PWRKEY_DUR 60
-#define DT2W_FEATHER 200
-#define DT2W_TIME 700
-
-#if defined(CONFIG_ARCH_MSM8974)
-#define DT2W_X_MAX 1080
-#define DT2W_Y_LIMIT 1920
-#elif defined(CONFIG_MACH_PICO)
-#define DT2W_X_MAX 1024
-#define DT2W_Y_LIMIT 910
-#else
-/* defaults */
-#define DT2W_X_MAX 1540
-#define DT2W_Y_LIMIT 2350
-#endif
-
-#define DT2W_Y_B1 300
-#define DT2W_Y_B2 DT2W_Y_LIMIT-300
-
-#define DT2W_X_B1 200
-#define DT2W_X_B2 DT2W_X_MAX-200
-
-/* Resources */
-int dt2w_switch = DT2W_DEFAULT;
-static cputime64_t tap_time_pre = 0;
-static int touch_x = 0, touch_y = 0, touch_nr = 0, x_pre = 0, y_pre = 0;
-static bool touch_x_called = false, touch_y_called = false, touch_cnt = true;
-static bool exec_count = true;
-bool dt2w_scr_suspended = false;
-static int key_code = KEY_POWER;
-int dt2w_sent_play_pause = 0;
-#ifndef WAKE_HOOKS_DEFINED
-#ifndef CONFIG_HAS_EARLYSUSPEND
-static struct notifier_block dt2w_lcd_notif;
-#endif
-#endif // WAKE_HOOKS_DEFINED
-static struct input_dev * doubletap2wake_pwrdev;
-static DEFINE_MUTEX(pwrkeyworklock);
-static struct workqueue_struct *dt2w_input_wq;
-static struct work_struct dt2w_input_work;
-
-/* Read cmdline for dt2w */
-static int __init read_dt2w_cmdline(char *dt2w)
-{
- if (strcmp(dt2w, "1") == 0) {
- pr_info("[cmdline_dt2w]: DoubleTap2Wake enabled. | dt2w='%s'\n", dt2w);
- dt2w_switch = 1;
- } else if (strcmp(dt2w, "2") == 0) {
- pr_info("[cmdline_dt2w]: DoubleTap2Wake (MusiqMod) enabled. | dt2w='%s'\n", dt2w);
- dt2w_switch = 2;
- } else if (strcmp(dt2w, "0") == 0) {
- pr_info("[cmdline_dt2w]: DoubleTap2Wake disabled. | dt2w='%s'\n", dt2w);
- dt2w_switch = 0;
- } else {
- pr_info("[cmdline_dt2w]: No valid input found. Going with default: | dt2w='%u'\n", dt2w_switch);
- }
- return 1;
-}
-__setup("dt2w=", read_dt2w_cmdline);
-
-/* reset on finger release */
-static void doubletap2wake_reset(void) {
- exec_count = true;
- touch_nr = 0;
- tap_time_pre = 0;
- x_pre = 0;
- y_pre = 0;
-}
-
-/* PowerKey work func */
-static void doubletap2wake_presspwr(struct work_struct * doubletap2wake_presspwr_work) {
- if (!mutex_trylock(&pwrkeyworklock))
- return;
- pr_warn("got inout event");
- input_event(doubletap2wake_pwrdev, EV_KEY, key_code, 1);
- input_event(doubletap2wake_pwrdev, EV_SYN, 0, 0);
- msleep(DT2W_PWRKEY_DUR);
- input_event(doubletap2wake_pwrdev, EV_KEY, key_code, 0);
- input_event(doubletap2wake_pwrdev, EV_SYN, 0, 0);
- msleep(DT2W_PWRKEY_DUR);
- mutex_unlock(&pwrkeyworklock);
- return;
-}
-static DECLARE_WORK(doubletap2wake_presspwr_work, doubletap2wake_presspwr);
-
-/* PowerKey trigger */
-static void doubletap2wake_pwrtrigger(void) {
- schedule_work(&doubletap2wake_presspwr_work);
- return;
-}
-
-/* unsigned */
-static unsigned int calc_feather(int coord, int prev_coord) {
- int calc_coord = 0;
- calc_coord = coord-prev_coord;
- if (calc_coord < 0)
- calc_coord = calc_coord * (-1);
- return calc_coord;
-}
-
-/* init a new touch */
-static void new_touch(int x, int y) {
- tap_time_pre = ktime_to_ms(ktime_get());
- x_pre = x;
- y_pre = y;
- touch_nr++;
-}
-
-/* Doubletap2wake main function */
-static void detect_doubletap2wake(int x, int y, bool st)
-{
- bool single_touch = st;
-#if DT2W_DEBUG
- pr_info(LOGTAG"x,y(%4d,%4d) single:%s\n",
- x, y, (single_touch) ? "true" : "false");
-#endif
- if (x < 100 || x > 980) {
- return;
- }
-
- if (y < 960) {
- return;
- }
-
- if ((single_touch) && (dt2w_switch > 0) && (exec_count) && (touch_cnt)) {
- touch_cnt = false;
- if (touch_nr == 0) {
- new_touch(x, y);
- } else if (touch_nr == 1) {
- if ((calc_feather(x, x_pre) < DT2W_FEATHER) &&
- (calc_feather(y, y_pre) < DT2W_FEATHER) &&
- ((ktime_to_ms(ktime_get())-tap_time_pre) < DT2W_TIME))
- touch_nr++;
- else {
- doubletap2wake_reset();
- new_touch(x, y);
- }
- } else {
- doubletap2wake_reset();
- new_touch(x, y);
- }
- if ((touch_nr > 1)) {
- exec_count = false;
- if ((dt2w_switch == 2) && (is_headset_in_use() || dt2w_sent_play_pause)) {
- if ((y > DT2W_Y_B1) && (y < DT2W_Y_B2)) {
- if ((x > DT2W_X_B1) && (x < DT2W_X_B2)) {
- pr_info(LOGTAG"MusiqMod: play_pause\n");
- key_code = KEY_PLAYPAUSE;
- dt2w_sent_play_pause = 1;
- doubletap2wake_pwrtrigger();
- } else if (x < DT2W_X_B1) {
- pr_info(LOGTAG"MusiqMod: previous song\n");
- key_code = KEY_PREVIOUSSONG;
- dt2w_sent_play_pause = 1;
- doubletap2wake_pwrtrigger();
- } else if (x > DT2W_X_B2) {
- pr_info(LOGTAG"MusiqMod: next song\n");
- key_code = KEY_NEXTSONG;
- dt2w_sent_play_pause = 1;
- doubletap2wake_pwrtrigger();
- }
- } else {
- doubletap2wake_reset();
- }
- } else {
- pr_info(LOGTAG"on_off\n");
- key_code = KEY_POWER;
- dt2w_sent_play_pause = 0;
- doubletap2wake_pwrtrigger();
- }
- doubletap2wake_reset();
- }
- }
-}
-
-static void dt2w_input_callback(struct work_struct *unused) {
- if (in_phone_call()) {
-#if DT2W_DEBUG
- pr_info("DoubleTap2Wake: in phone call! return!\n");
-#endif
- return;
- }
-
- detect_doubletap2wake(touch_x, touch_y, true);
-
- return;
-}
-
-static void dt2w_input_event(struct input_handle *handle, unsigned int type,
- unsigned int code, int value) {
-#if DT2W_DEBUG
- pr_info("doubletap2wake: code: %s|%u, val: %i\n",
- ((code==ABS_MT_POSITION_X) ? "X" :
- (code==ABS_MT_POSITION_Y) ? "Y" :
- (code==ABS_MT_TRACKING_ID) ? "ID" :
- "undef"), code, value);
-#endif
- if (!dt2w_scr_suspended)
- return;
-
- if (code == ABS_MT_SLOT) {
- doubletap2wake_reset();
- return;
- }
-
- if (code == ABS_MT_TRACKING_ID && value == -1) {
- touch_cnt = true;
- return;
- }
-
- if (code == ABS_MT_POSITION_X) {
- touch_x = value;
- touch_x_called = true;
- }
-
- if (code == ABS_MT_POSITION_Y) {
- touch_y = value;
- touch_y_called = true;
- }
-
- if (touch_x_called || touch_y_called) {
- touch_x_called = false;
- touch_y_called = false;
- queue_work_on(0, dt2w_input_wq, &dt2w_input_work);
- }
-}
-
-static int input_dev_filter(struct input_dev *dev) {
- /*if (strstr(dev->name, "atmel-maxtouch")
- ||strstr(dev->name, "ist30xx_ts")
- ||strstr(dev->name, "Goodix-CTP")
- ||strstr(dev->name, "himax-touchscreen")
- )*/
- return 0;
-}
-
-static int dt2w_input_connect(struct input_handler *handler,
- struct input_dev *dev, const struct input_device_id *id) {
- struct input_handle *handle;
- int error;
-
- if (input_dev_filter(dev))
- return -ENODEV;
-
- handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
- if (!handle)
- return -ENOMEM;
-
- handle->dev = dev;
- handle->handler = handler;
- handle->name = "dt2w";
-
- error = input_register_handle(handle);
- if (error)
- goto err2;
-
- error = input_open_device(handle);
- if (error)
- goto err1;
-
- return 0;
-err1:
- input_unregister_handle(handle);
-err2:
- kfree(handle);
- return error;
-}
-
-static void dt2w_input_disconnect(struct input_handle *handle) {
- input_close_device(handle);
- input_unregister_handle(handle);
- kfree(handle);
-}
-
-static const struct input_device_id dt2w_ids[] = {
- { .driver_info = 1 },
- { },
-};
-
-static struct input_handler dt2w_input_handler = {
- .event = dt2w_input_event,
- .connect = dt2w_input_connect,
- .disconnect = dt2w_input_disconnect,
- .name = "dt2w_inputreq",
- .id_table = dt2w_ids,
-};
-
-#ifndef WAKE_HOOKS_DEFINED
-#ifndef CONFIG_HAS_EARLYSUSPEND
-static int lcd_notifier_callback(struct notifier_block *this,
- unsigned long event, void *data)
-{
- switch (event) {
- case LCD_EVENT_ON_END:
- dt2w_scr_suspended = false;
- dt2w_sent_play_pause = 0;
- break;
- case LCD_EVENT_OFF_END:
- dt2w_scr_suspended = true;
- break;
- default:
- break;
- }
-
- return 0;
-}
-#else
-static void dt2w_early_suspend(struct early_suspend *h) {
- dt2w_scr_suspended = true;
-}
-
-static void dt2w_late_resume(struct early_suspend *h) {
- dt2w_scr_suspended = false;
-}
-
-static struct early_suspend dt2w_early_suspend_handler = {
- .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN,
- .suspend = dt2w_early_suspend,
- .resume = dt2w_late_resume,
-};
-#endif
-#endif // WAKE_HOOKS_DEFINED
-
-/*
- * SYSFS stuff below here
- */
-static ssize_t dt2w_doubletap2wake_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count = 0;
-
- count += sprintf(buf, "%d\n", dt2w_switch);
-
- return count;
-}
-
-static ssize_t dt2w_doubletap2wake_dump(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- if (buf[0] >= '0' && buf[0] <= '2' && buf[1] == '\n')
- if (dt2w_switch != buf[0] - '0') {
- dt2w_switch = buf[0] - '0';
- dt2w_sent_play_pause = 0;
- }
-
- return count;
-}
-
-static DEVICE_ATTR(doubletap2wake, (S_IWUSR|S_IRUGO),
- dt2w_doubletap2wake_show, dt2w_doubletap2wake_dump);
-
-static ssize_t dt2w_version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count = 0;
-
- count += sprintf(buf, "%s\n", DRIVER_VERSION);
-
- return count;
-}
-
-static ssize_t dt2w_version_dump(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- return count;
-}
-
-static DEVICE_ATTR(doubletap2wake_version, (S_IWUSR|S_IRUGO),
- dt2w_version_show, dt2w_version_dump);
-
-/*
- * INIT / EXIT stuff below here
- */
-extern struct kobject *android_touch_kobj;
-static int __init doubletap2wake_init(void)
-{
- int rc = 0;
-
- doubletap2wake_pwrdev = input_allocate_device();
- if (!doubletap2wake_pwrdev) {
- pr_err("Can't allocate suspend autotest power button\n");
- goto err_alloc_dev;
- }
-
- input_set_capability(doubletap2wake_pwrdev, EV_KEY, KEY_POWER);
- input_set_capability(doubletap2wake_pwrdev, EV_KEY, KEY_PLAYPAUSE);
- input_set_capability(doubletap2wake_pwrdev, EV_KEY, KEY_NEXTSONG);
- input_set_capability(doubletap2wake_pwrdev, EV_KEY, KEY_PREVIOUSSONG);
- doubletap2wake_pwrdev->name = "dt2w_pwrkey";
- doubletap2wake_pwrdev->phys = "dt2w_pwrkey/input0";
-
- rc = input_register_device(doubletap2wake_pwrdev);
- if (rc) {
- pr_err("%s: input_register_device err=%d\n", __func__, rc);
- goto err_input_dev;
- }
-
- dt2w_input_wq = create_workqueue("dt2wiwq");
- if (!dt2w_input_wq) {
- pr_err("%s: Failed to create dt2wiwq workqueue\n", __func__);
- return -EFAULT;
- }
- INIT_WORK(&dt2w_input_work, dt2w_input_callback);
- rc = input_register_handler(&dt2w_input_handler);
- if (rc)
- pr_err("%s: Failed to register dt2w_input_handler\n", __func__);
-
-#ifndef WAKE_HOOKS_DEFINED
-#ifndef CONFIG_HAS_EARLYSUSPEND
- dt2w_lcd_notif.notifier_call = lcd_notifier_callback;
- if (lcd_register_client(&dt2w_lcd_notif) != 0) {
- pr_err("%s: Failed to register lcd callback\n", __func__);
- }
-#else
- register_early_suspend(&dt2w_early_suspend_handler);
-#endif
-#endif // WAKE_HOOKS_DEFINED
-
- rc = sysfs_create_file(android_touch_kobj, &dev_attr_doubletap2wake.attr);
- if (rc) {
- pr_warn("%s: sysfs_create_file failed for doubletap2wake\n", __func__);
- }
- rc = sysfs_create_file(android_touch_kobj, &dev_attr_doubletap2wake_version.attr);
- if (rc) {
- pr_warn("%s: sysfs_create_file failed for doubletap2wake_version\n", __func__);
- }
-
-err_input_dev:
- input_free_device(doubletap2wake_pwrdev);
-err_alloc_dev:
- pr_info(LOGTAG"%s done\n", __func__);
-
- return 0;
-}
-
-static void __exit doubletap2wake_exit(void)
-{
-#ifndef WAKE_HOOKS_DEFINED
-#ifndef CONFIG_HAS_EARLYSUSPEND
- lcd_unregister_client(&dt2w_lcd_notif);
-#endif
-#endif
- input_unregister_handler(&dt2w_input_handler);
- destroy_workqueue(dt2w_input_wq);
- input_unregister_device(doubletap2wake_pwrdev);
- input_free_device(doubletap2wake_pwrdev);
- return;
-}
-
-module_init(doubletap2wake_init);
-module_exit(doubletap2wake_exit);
-
diff --git a/drivers/input/touchscreen/sweep2wake.c b/drivers/input/touchscreen/sweep2wake.c
deleted file mode 100644
index 3808d48..0000000
--- a/drivers/input/touchscreen/sweep2wake.c
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * drivers/input/touchscreen/sweep2wake.c
- *
- *
- * Copyright (c) 2013, Dennis Rassmann <showp1984@gmail.com>
- *
- * Wake Gestures
- * Copyright (c) 2014, Aaron Segaert <asegaert@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/input/sweep2wake.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/input.h>
-#ifndef CONFIG_HAS_EARLYSUSPEND
-#include <linux/lcd_notify.h>
-#else
-#include <linux/earlysuspend.h>
-#endif
-#include <linux/hrtimer.h>
-
-/* uncomment since no touchscreen defines android touch, do that here */
-//#define ANDROID_TOUCH_DECLARED
-
-/* Version, author, desc, etc */
-#define DRIVER_AUTHOR "Dennis Rassmann <showp1984@gmail.com>"
-#define DRIVER_DESCRIPTION "Sweep2wake for almost any device"
-#define DRIVER_VERSION "1.5"
-#define LOGTAG "[sweep2wake]: "
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPLv2");
-
-/* Tuneables */
-#define S2W_DEBUG 0
-#define S2W_DEFAULT 0
-#define S2W_PWRKEY_DUR 60
-
-#ifdef CONFIG_ARCH_MSM8974
-/* Hammerhead aka Nexus 5 */
-#define S2W_Y_MAX 1920
-#define S2W_X_MAX 1080
-#define S2W_Y_LIMIT S2W_Y_MAX-130
-#define S2W_X_B1 400
-#define S2W_X_B2 700
-#define S2W_X_FINAL 275
-#define S2W_Y_NEXT 180
-#else
-/* defaults */
-#define S2W_Y_LIMIT 2350
-#define S2W_X_MAX 1540
-#define S2W_X_B1 500
-#define S2W_X_B2 1000
-#define S2W_X_FINAL 300
-#endif
-
-/* Wake Gestures */
-#define SWEEP_TIMEOUT 30
-#define TRIGGER_TIMEOUT 50
-#define WAKE_GESTURE 0x0b
-#define SWEEP_RIGHT 0x01
-#define SWEEP_LEFT 0x02
-#define SWEEP_UP 0x04
-#define SWEEP_DOWN 0x08
-#define VIB_STRENGTH 20
-
-int gestures_switch = S2W_DEFAULT;
-static struct input_dev *gesture_dev;
-extern void gestures_setdev(struct input_dev * input_device);
-int vib_strength = VIB_STRENGTH;
-
-/* Resources */
-int s2w_switch = S2W_DEFAULT;
-static int s2s_switch = S2W_DEFAULT;
-static int touch_x = 0, touch_y = 0;
-static bool touch_x_called = false, touch_y_called = false;
-static bool scr_suspended = false;
-static bool exec_countx = true, exec_county = true;
-static bool barrierx[2] = {false, false}, barriery[2] = {false, false};
-static int firstx = 0, firsty = 0;
-static unsigned long firstx_time = 0, firsty_time = 0;
-static unsigned long pwrtrigger_time[2] = {0, 0};
-#ifndef CONFIG_HAS_EARLYSUSPEND
-static struct notifier_block s2w_lcd_notif;
-#endif
-static struct input_dev * sweep2wake_pwrdev;
-static DEFINE_MUTEX(pwrkeyworklock);
-static struct workqueue_struct *s2w_input_wq;
-static struct work_struct s2w_input_work;
-
-/* Read cmdline for s2w */
-static int __init read_s2w_cmdline(char *s2w)
-{
- if (strcmp(s2w, "1") == 0) {
- pr_info("[cmdline_s2w]: Sweep2Wake enabled. | s2w='%s'\n", s2w);
- s2w_switch = 1;
- } else if (strcmp(s2w, "2") == 0) {
- pr_info("[cmdline_s2w]: Sweep2Wake disabled. | s2w='%s'\n", s2w);
- s2w_switch = 2;
- } else if (strcmp(s2w, "0") == 0) {
- pr_info("[cmdline_s2w]: Sweep2Wake disabled. | s2w='%s'\n", s2w);
- s2w_switch = 0;
- } else {
- pr_info("[cmdline_s2w]: No valid input found. Going with default: | s2w='%u'\n", s2w_switch);
- }
- return 1;
-}
-__setup("s2w=", read_s2w_cmdline);
-
-
-/* PowerKey work func */
-static void sweep2wake_presspwr(struct work_struct * sweep2wake_presspwr_work) {
- if (!mutex_trylock(&pwrkeyworklock))
- return;
- input_event(sweep2wake_pwrdev, EV_KEY, KEY_POWER, 1);
- input_event(sweep2wake_pwrdev, EV_SYN, 0, 0);
- msleep(S2W_PWRKEY_DUR);
- input_event(sweep2wake_pwrdev, EV_KEY, KEY_POWER, 0);
- input_event(sweep2wake_pwrdev, EV_SYN, 0, 0);
- msleep(S2W_PWRKEY_DUR);
- mutex_unlock(&pwrkeyworklock);
- return;
-}
-static DECLARE_WORK(sweep2wake_presspwr_work, sweep2wake_presspwr);
-
-/* PowerKey trigger */
-static void sweep2wake_pwrtrigger(void) {
- pwrtrigger_time[1] = pwrtrigger_time[0];
- pwrtrigger_time[0] = jiffies;
-
- if (pwrtrigger_time[0] - pwrtrigger_time[1] < TRIGGER_TIMEOUT)
- return;
-
- schedule_work(&sweep2wake_presspwr_work);
- return;
-}
-
-/* reset on finger release */
-static void sweep2wake_reset(void) {
- exec_countx = true;
- barrierx[0] = false;
- barrierx[1] = false;
- firstx = 0;
- firstx_time = 0;
-
- exec_county = true;
- barriery[0] = false;
- barriery[1] = false;
- firsty = 0;
- firsty_time = 0;
-}
-
-/* Sweep2wake main function */
-static void detect_sweep2wake_v(int x, int y, bool st)
-{
- int prevy = 0, nexty = 0;
- bool single_touch = st;
-
- if (firsty == 0) {
- firsty = y;
- firsty_time = jiffies;
- }
-
- if (x > 100 && x < 980) {
- //up
- if (firsty > 960 && single_touch && (s2w_switch & SWEEP_UP)) {
- prevy = firsty;
- nexty = prevy - S2W_Y_NEXT;
- if (barriery[0] == true || (y < prevy && y > nexty)) {
- prevy = nexty;
- nexty -= S2W_Y_NEXT;
- barriery[0] = true;
- if (barriery[1] == true || (y < prevy && y > nexty)) {
- prevy = nexty;
- barriery[1] = true;
- if (y < prevy) {
- if (y < (nexty - S2W_Y_NEXT)) {
- if (exec_county && (jiffies - firsty_time < SWEEP_TIMEOUT)) {
- pr_info(LOGTAG"sweep up\n");
- sweep2wake_pwrtrigger();
- exec_county = false;
- }
- }
- }
- }
- }
- //down
- } else if (firsty <= 960 && single_touch && (s2w_switch & SWEEP_DOWN)) {
- prevy = firsty;
- nexty = prevy + S2W_Y_NEXT;
- if (barriery[0] == true || (y > prevy && y < nexty)) {
- prevy = nexty;
- nexty += S2W_Y_NEXT;
- barriery[0] = true;
- if (barriery[1] == true || (y > prevy && y < nexty)) {
- prevy = nexty;
- barriery[1] = true;
- if (y > prevy) {
- if (y > (nexty + S2W_Y_NEXT)) {
- if (exec_county && (jiffies - firsty_time < SWEEP_TIMEOUT)) {
- pr_info(LOGTAG"sweep down\n");
- sweep2wake_pwrtrigger();
- exec_county = false;
- }
- }
- }
- }
- }
- }
- }
-}
-
-static void detect_sweep2wake_h(int x, int y, bool st, bool wake)
-{
- int prevx = 0, nextx = 0;
- bool single_touch = st;
-
- if (firstx == 0) {
- firstx = x;
- firstx_time = jiffies;
- }
-
- if (!wake && y < S2W_Y_LIMIT) {
- sweep2wake_reset();
- return;
- }
-#if S2W_DEBUG
- pr_info(LOGTAG"x,y(%4d,%4d) single:%s\n",
- x, y, (single_touch) ? "true" : "false");
-#endif
- //left->right
- if (firstx < 510 && single_touch &&
- ((wake && (s2w_switch & SWEEP_RIGHT)) || (!wake && (s2s_switch & SWEEP_RIGHT)))) {
- prevx = 0;
- nextx = S2W_X_B1;
- if ((barrierx[0] == true) ||
- ((x > prevx) && (x < nextx))) {
- prevx = nextx;
- nextx = S2W_X_B2;
- barrierx[0] = true;
- if ((barrierx[1] == true) ||
- ((x > prevx) && (x < nextx))) {
- prevx = nextx;
- barrierx[1] = true;
- if (x > prevx) {
- if (x > (S2W_X_MAX - S2W_X_FINAL)) {
- if (exec_countx && (jiffies - firstx_time < SWEEP_TIMEOUT)) {
- pr_info(LOGTAG"sweep right\n");
- sweep2wake_pwrtrigger();
- exec_countx = false;
- }
- }
- }
- }
- }
- //right->left
- } else if (firstx >= 510 && single_touch &&
- ((wake && (s2w_switch & SWEEP_LEFT)) || (!wake && (s2s_switch & SWEEP_LEFT)))) {
- prevx = (S2W_X_MAX - S2W_X_FINAL);
- nextx = S2W_X_B2;
- if ((barrierx[0] == true) ||
- ((x < prevx) && (x > nextx))) {
- prevx = nextx;
- nextx = S2W_X_B1;
- barrierx[0] = true;
- if ((barrierx[1] == true) ||
- ((x < prevx) && (x > nextx))) {
- prevx = nextx;
- barrierx[1] = true;
- if (x < prevx) {
- if (x < S2W_X_FINAL) {
- if (exec_countx) {
- pr_info(LOGTAG"sweep left\n");
- sweep2wake_pwrtrigger();
- exec_countx = false;
- }
- }
- }
- }
- }
- }
-}
-
-static void s2w_input_callback(struct work_struct *unused) {
-
- detect_sweep2wake_h(touch_x, touch_y, true, scr_suspended);
- if (scr_suspended)
- detect_sweep2wake_v(touch_x, touch_y, true);
-
- return;
-}
-
-static void s2w_input_event(struct input_handle *handle, unsigned int type,
- unsigned int code, int value) {
-#if S2W_DEBUG
- pr_info("sweep2wake: code: %s|%u, val: %i\n",
- ((code==ABS_MT_POSITION_X) ? "X" :
- (code==ABS_MT_POSITION_Y) ? "Y" :
- (code==ABS_MT_TRACKING_ID) ? "ID" :
- "undef"), code, value);
-#endif
- if (code == ABS_MT_SLOT) {
- sweep2wake_reset();
- return;
- }
-
- if (code == ABS_MT_TRACKING_ID && value == -1) {
- sweep2wake_reset();
- return;
- }
-
- if (code == ABS_MT_POSITION_X) {
- touch_x = value;
- touch_x_called = true;
- }
-
- if (code == ABS_MT_POSITION_Y) {
- touch_y = value;
- touch_y_called = true;
- }
-
- if (touch_x_called && touch_y_called) {
- touch_x_called = false;
- touch_y_called = false;
- queue_work_on(0, s2w_input_wq, &s2w_input_work);
- } else if (!scr_suspended && touch_x_called && !touch_y_called) {
- touch_x_called = false;
- touch_y_called = false;
- queue_work_on(0, s2w_input_wq, &s2w_input_work);
- }
-}
-
-static int input_dev_filter(struct input_dev *dev) {
- if (strstr(dev->name, "touch")) {
- return 0;
- } else {
- return 1;
- }
-}
-
-static int s2w_input_connect(struct input_handler *handler,
- struct input_dev *dev, const struct input_device_id *id) {
- struct input_handle *handle;
- int error;
-
- if (input_dev_filter(dev))
- return -ENODEV;
-
- handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
- if (!handle)
- return -ENOMEM;
-
- handle->dev = dev;
- handle->handler = handler;
- handle->name = "s2w";
-
- error = input_register_handle(handle);
- if (error)
- goto err2;
-
- error = input_open_device(handle);
- if (error)
- goto err1;
-
- return 0;
-err1:
- input_unregister_handle(handle);
-err2:
- kfree(handle);
- return error;
-}
-
-static void s2w_input_disconnect(struct input_handle *handle) {
- input_close_device(handle);
- input_unregister_handle(handle);
- kfree(handle);
-}
-
-static const struct input_device_id s2w_ids[] = {
- { .driver_info = 1 },
- { },
-};
-
-static struct input_handler s2w_input_handler = {
- .event = s2w_input_event,
- .connect = s2w_input_connect,
- .disconnect = s2w_input_disconnect,
- .name = "s2w_inputreq",
- .id_table = s2w_ids,
-};
-
-#ifndef CONFIG_HAS_EARLYSUSPEND
-static int lcd_notifier_callback(struct notifier_block *this,
- unsigned long event, void *data)
-{
- switch (event) {
- case LCD_EVENT_ON_END:
- scr_suspended = false;
- break;
- case LCD_EVENT_OFF_END:
- scr_suspended = true;
- break;
- default:
- break;
- }
-
- return 0;
-}
-#else
-static void s2w_early_suspend(struct early_suspend *h) {
- scr_suspended = true;
-}
-
-static void s2w_late_resume(struct early_suspend *h) {
- scr_suspended = false;
-}
-
-static struct early_suspend s2w_early_suspend_handler = {
- .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN,
- .suspend = s2w_early_suspend,
- .resume = s2w_late_resume,
-};
-#endif
-
-/*
- * SYSFS stuff below here
- */
-static ssize_t s2w_sweep2wake_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count = 0;
-
- count += sprintf(buf, "%d\n", s2w_switch);
-
- return count;
-}
-
-static ssize_t s2w_sweep2wake_dump(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- sscanf(buf, "%d ", &s2w_switch);
- if (s2w_switch < 0 || s2w_switch > 15)
- s2w_switch = 15;
-
- if (scr_suspended && !s2w_switch) {
- sweep2wake_pwrtrigger();
- }
-
- return count;
-}
-
-static DEVICE_ATTR(sweep2wake, (S_IWUSR|S_IRUGO),
- s2w_sweep2wake_show, s2w_sweep2wake_dump);
-
-static ssize_t sweep2sleep_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count = 0;
- count += sprintf(buf, "%d\n", s2s_switch);
- return count;
-}
-
-static ssize_t sweep2sleep_dump(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- if (buf[0] >= '0' && buf[0] <= '3' && buf[1] == '\n')
- if (s2s_switch != buf[0] - '0')
- s2s_switch = buf[0] - '0';
- return count;
-}
-
-static DEVICE_ATTR(sweep2sleep, (S_IWUSR|S_IRUGO),
- sweep2sleep_show, sweep2sleep_dump);
-
-static ssize_t s2w_version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count = 0;
-
- count += sprintf(buf, "%s\n", DRIVER_VERSION);
-
- return count;
-}
-
-static ssize_t s2w_version_dump(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- return count;
-}
-
-static DEVICE_ATTR(sweep2wake_version, (S_IWUSR|S_IRUGO),
- s2w_version_show, s2w_version_dump);
-
-static ssize_t wake_gestures_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count = 0;
- count += sprintf(buf, "%d\n", gestures_switch);
- return count;
-}
-
-static ssize_t wake_gestures_dump(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- if (buf[0] >= '0' && buf[0] <= '1' && buf[1] == '\n')
- if (gestures_switch != buf[0] - '0')
- gestures_switch = buf[0] - '0';
- return count;
-}
-
-static DEVICE_ATTR(wake_gestures, (S_IWUSR|S_IRUGO),
- wake_gestures_show, wake_gestures_dump);
-
-static ssize_t vib_strength_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- size_t count = 0;
- count += sprintf(buf, "%d\n", vib_strength);
- return count;
-}
-
-static ssize_t vib_strength_dump(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- sscanf(buf, "%d ",&vib_strength);
- if (vib_strength < 0 || vib_strength > 90)
- vib_strength = 20;
-
- return count;
-}
-
-static DEVICE_ATTR(vib_strength, (S_IWUSR|S_IRUGO),
- vib_strength_show, vib_strength_dump);
-
-/*
- * INIT / EXIT stuff below here
- */
-#ifdef ANDROID_TOUCH_DECLARED
-extern struct kobject *android_touch_kobj;
-#else
-struct kobject *android_touch_kobj;
-EXPORT_SYMBOL_GPL(android_touch_kobj);
-#endif
-static int __init sweep2wake_init(void)
-{
- int rc = 0;
-
- sweep2wake_pwrdev = input_allocate_device();
- if (!sweep2wake_pwrdev) {
- pr_err("Can't allocate suspend autotest power button\n");
- goto err_alloc_dev;
- }
-
- input_set_capability(sweep2wake_pwrdev, EV_KEY, KEY_POWER);
- sweep2wake_pwrdev->name = "s2w_pwrkey";
- sweep2wake_pwrdev->phys = "s2w_pwrkey/input0";
-
- rc = input_register_device(sweep2wake_pwrdev);
- if (rc) {
- pr_err("%s: input_register_device err=%d\n", __func__, rc);
- goto err_input_dev;
- }
-
- s2w_input_wq = create_workqueue("s2wiwq");
- if (!s2w_input_wq) {
- pr_err("%s: Failed to create s2wiwq workqueue\n", __func__);
- return -EFAULT;
- }
- INIT_WORK(&s2w_input_work, s2w_input_callback);
- rc = input_register_handler(&s2w_input_handler);
- if (rc)
- pr_err("%s: Failed to register s2w_input_handler\n", __func__);
-
- gesture_dev = input_allocate_device();
- if (!gesture_dev) {
- goto err_alloc_dev;
- }
-
-#ifndef CONFIG_HAS_EARLYSUSPEND
- s2w_lcd_notif.notifier_call = lcd_notifier_callback;
- if (lcd_register_client(&s2w_lcd_notif) != 0) {
- pr_err("%s: Failed to register lcd callback\n", __func__);
- }
-#else
- register_early_suspend(&s2w_early_suspend_handler);
-#endif
-
-#ifndef ANDROID_TOUCH_DECLARED
- android_touch_kobj = kobject_create_and_add("android_touch", NULL) ;
- if (android_touch_kobj == NULL) {
- pr_warn("%s: android_touch_kobj create_and_add failed\n", __func__);
- }
-#endif
- rc = sysfs_create_file(android_touch_kobj, &dev_attr_sweep2wake.attr);
- if (rc) {
- pr_warn("%s: sysfs_create_file failed for sweep2wake\n", __func__);
- }
- rc = sysfs_create_file(android_touch_kobj, &dev_attr_sweep2sleep.attr);
- if (rc) {
- pr_warn("%s: sysfs_create_file failed for sweep2sleep\n", __func__);
- }
- rc = sysfs_create_file(android_touch_kobj, &dev_attr_sweep2wake_version.attr);
- if (rc) {
- pr_warn("%s: sysfs_create_file failed for sweep2wake_version\n", __func__);
- }
- rc = sysfs_create_file(android_touch_kobj, &dev_attr_wake_gestures.attr);
- if (rc) {
- pr_warn("%s: sysfs_create_file failed for wake_gestures\n", __func__);
- }
- rc = sysfs_create_file(android_touch_kobj, &dev_attr_vib_strength.attr);
- if (rc) {
- pr_warn("%s: sysfs_create_file failed for vib_strength\n", __func__);
- }
-
-err_input_dev:
- input_free_device(sweep2wake_pwrdev);
-err_alloc_dev:
- pr_info(LOGTAG"%s done\n", __func__);
-
- return 0;
-}
-
-static void __exit sweep2wake_exit(void)
-{
-#ifndef ANDROID_TOUCH_DECLARED
- kobject_del(android_touch_kobj);
-#endif
-#ifndef CONFIG_HAS_EARLYSUSPEND
- lcd_unregister_client(&s2w_lcd_notif);
-#endif
- input_unregister_handler(&s2w_input_handler);
- destroy_workqueue(s2w_input_wq);
- input_unregister_device(sweep2wake_pwrdev);
- input_free_device(sweep2wake_pwrdev);
- return;
-}
-
-module_init(sweep2wake_init);
-module_exit(sweep2wake_exit);
-
diff --git a/drivers/input/touchscreen/wake_helpers.c b/drivers/input/touchscreen/wake_helpers.c
deleted file mode 100644
index c5544af..0000000
--- a/drivers/input/touchscreen/wake_helpers.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * drivers/input/touchscreen/wake_helpers.c
- *
- *
- * Copyright (c) 2015, Vineeth Raj <contact.twn@openmailbox.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <linux/input/wake_helpers.h>
-
-int is_headset_in_use(void) {
- return var_is_headset_in_use;
-}
-
-int in_phone_call(void) {
- return var_in_phone_call;
-}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment