|
@@ -0,0 +1,271 @@
|
|
|
+diff -Naurp a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
|
|
|
+--- a/drivers/input/touchscreen/edt-ft5x06.c 2017-01-22 23:28:20.288470982 +0100
|
|
|
++++ b/drivers/input/touchscreen/edt-ft5x06.c 2017-01-22 23:28:55.752481073 +0100
|
|
|
+@@ -54,6 +54,13 @@
|
|
|
+ #define M09_REGISTER_NUM_X 0x94
|
|
|
+ #define M09_REGISTER_NUM_Y 0x95
|
|
|
+
|
|
|
++#define M12_REGISTER_THRESHOLD 0x80
|
|
|
++#define M12_REGISTER_GAIN 0x92
|
|
|
++#define M12_REGISTER_OFFSET 0x93
|
|
|
++#define M12_REGISTER_NUM_X 0x94
|
|
|
++#define M12_REGISTER_NUM_Y 0x95
|
|
|
++#define M12_REGISTER_REPORT_RATE 0x88
|
|
|
++
|
|
|
+ #define NO_REGISTER 0xff
|
|
|
+
|
|
|
+ #define WORK_REGISTER_OPMODE 0x3c
|
|
|
+@@ -73,6 +80,7 @@
|
|
|
+ enum edt_ver {
|
|
|
+ M06,
|
|
|
+ M09,
|
|
|
++ M12,
|
|
|
+ };
|
|
|
+
|
|
|
+ struct edt_reg_addr {
|
|
|
+@@ -181,7 +189,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int
|
|
|
+ tplen = 4; /* data comes in so called frames */
|
|
|
+ datalen = 26; /* how much bytes to listen for */
|
|
|
+ break;
|
|
|
+-
|
|
|
++
|
|
|
++ case M12:
|
|
|
+ case M09:
|
|
|
+ cmd = 0x02;
|
|
|
+ offset = 1;
|
|
|
+@@ -204,8 +213,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+- /* M09 does not send header or CRC */
|
|
|
+- if (tsdata->version == M06) {
|
|
|
++ /* M09 M12 does not send header or CRC */
|
|
|
++ if (tsdata->version == M06) {
|
|
|
+ if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
|
|
|
+ rdbuf[2] != datalen) {
|
|
|
+ dev_err_ratelimited(dev,
|
|
|
+@@ -265,8 +274,9 @@ static int edt_ft5x06_register_write(str
|
|
|
+ wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
|
|
|
+ wrbuf[2] = value;
|
|
|
+ wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
|
|
|
+- return edt_ft5x06_ts_readwrite(tsdata->client, 4,
|
|
|
+- wrbuf, 0, NULL);
|
|
|
++ return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL);
|
|
|
++
|
|
|
++ case M12:
|
|
|
+ case M09:
|
|
|
+ wrbuf[0] = addr;
|
|
|
+ wrbuf[1] = value;
|
|
|
+@@ -305,6 +315,7 @@ static int edt_ft5x06_register_read(stru
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
++ case M12:
|
|
|
+ case M09:
|
|
|
+ wrbuf[0] = addr;
|
|
|
+ error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
|
|
|
+@@ -327,9 +338,10 @@ struct edt_ft5x06_attribute {
|
|
|
+ u8 limit_high;
|
|
|
+ u8 addr_m06;
|
|
|
+ u8 addr_m09;
|
|
|
++ u8 addr_m12;
|
|
|
+ };
|
|
|
+
|
|
|
+-#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \
|
|
|
++#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_m12, \
|
|
|
+ _limit_low, _limit_high) \
|
|
|
+ struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \
|
|
|
+ .dattr = __ATTR(_field, _mode, \
|
|
|
+@@ -338,6 +350,7 @@ struct edt_ft5x06_attribute {
|
|
|
+ .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \
|
|
|
+ .addr_m06 = _addr_m06, \
|
|
|
+ .addr_m09 = _addr_m09, \
|
|
|
++ .addr_m12 = _addr_m12, \
|
|
|
+ .limit_low = _limit_low, \
|
|
|
+ .limit_high = _limit_high, \
|
|
|
+ }
|
|
|
+@@ -368,6 +381,10 @@ static ssize_t edt_ft5x06_setting_show(s
|
|
|
+ addr = attr->addr_m06;
|
|
|
+ break;
|
|
|
+
|
|
|
++ case M12:
|
|
|
++ addr = attr->addr_m12;
|
|
|
++ break;
|
|
|
++
|
|
|
+ case M09:
|
|
|
+ addr = attr->addr_m09;
|
|
|
+ break;
|
|
|
+@@ -437,6 +454,10 @@ static ssize_t edt_ft5x06_setting_store(
|
|
|
+ addr = attr->addr_m06;
|
|
|
+ break;
|
|
|
+
|
|
|
++ case M12:
|
|
|
++ addr = attr->addr_m12;
|
|
|
++ break;
|
|
|
++
|
|
|
+ case M09:
|
|
|
+ addr = attr->addr_m09;
|
|
|
+ break;
|
|
|
+@@ -463,13 +484,13 @@ out:
|
|
|
+ }
|
|
|
+
|
|
|
+ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
|
|
|
+- M09_REGISTER_GAIN, 0, 31);
|
|
|
++ M09_REGISTER_GAIN, M12_REGISTER_GAIN, 0, 31);
|
|
|
+ static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
|
|
|
+- M09_REGISTER_OFFSET, 0, 31);
|
|
|
++ M09_REGISTER_OFFSET, M12_REGISTER_OFFSET, 0, 31);
|
|
|
+ static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
|
|
|
+- M09_REGISTER_THRESHOLD, 20, 80);
|
|
|
++ M09_REGISTER_THRESHOLD, M12_REGISTER_THRESHOLD, 1, 255);
|
|
|
+ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
|
|
|
+- NO_REGISTER, 3, 14);
|
|
|
++ NO_REGISTER, M12_REGISTER_REPORT_RATE, 3, 14);
|
|
|
+
|
|
|
+ static struct attribute *edt_ft5x06_attrs[] = {
|
|
|
+ &edt_ft5x06_attr_gain.dattr.attr,
|
|
|
+@@ -504,7 +525,7 @@ static int edt_ft5x06_factory_mode(struc
|
|
|
+ }
|
|
|
+
|
|
|
+ /* mode register is 0x3c when in the work mode */
|
|
|
+- if (tsdata->version == M09)
|
|
|
++ if ((tsdata->version == M09) || (tsdata->version == M12))
|
|
|
+ goto m09_out;
|
|
|
+
|
|
|
+ error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
|
|
|
+@@ -541,7 +562,7 @@ err_out:
|
|
|
+ return error;
|
|
|
+
|
|
|
+ m09_out:
|
|
|
+- dev_err(&client->dev, "No factory mode support for M09\n");
|
|
|
++ dev_err(&client->dev, "No factory mode support for M09 and M12\n");
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ }
|
|
|
+@@ -717,17 +738,26 @@ static void
|
|
|
+ edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
|
|
|
+ const char *debugfs_name)
|
|
|
+ {
|
|
|
++ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
|
|
|
++
|
|
|
+ tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
|
|
|
+ if (!tsdata->debug_dir)
|
|
|
+ return;
|
|
|
+
|
|
|
+ debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
|
|
|
+ debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
|
|
|
++ debugfs_create_u16("threshold", S_IRUSR, tsdata->debug_dir, &tsdata->threshold);
|
|
|
++ debugfs_create_u16("gain", S_IRUSR, tsdata->debug_dir, &tsdata->gain);
|
|
|
++ debugfs_create_u16("offset", S_IRUSR, tsdata->debug_dir, &tsdata->offset);
|
|
|
++
|
|
|
+
|
|
|
+ debugfs_create_file("mode", S_IRUSR | S_IWUSR,
|
|
|
+ tsdata->debug_dir, tsdata, &debugfs_mode_fops);
|
|
|
+ debugfs_create_file("raw_data", S_IRUSR,
|
|
|
+ tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
|
|
|
++
|
|
|
++ if (reg_addr->reg_report_rate != NO_REGISTER)
|
|
|
++ debugfs_create_u16("report_rate", S_IRUSR, tsdata->debug_dir, &tsdata->report_rate);
|
|
|
+ }
|
|
|
+
|
|
|
+ static void
|
|
|
+@@ -807,14 +837,16 @@ static int edt_ft5x06_ts_identify(struct
|
|
|
+ */
|
|
|
+ memset(rdbuf, 0, sizeof(rdbuf));
|
|
|
+ error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
|
|
|
+- EDT_NAME_LEN - 1, rdbuf);
|
|
|
++ EDT_NAME_LEN - 1,
|
|
|
++ rdbuf);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
++ printk(KERN_INFO "EDT-TC:: %s ::-----%s----\n", __func__, rdbuf);
|
|
|
+ /* if we find something consistent, stay with that assumption
|
|
|
+ * at least M09 won't send 3 bytes here
|
|
|
+ */
|
|
|
+- if (!(strnicmp(rdbuf + 1, "EP0", 3))) {
|
|
|
++ if ((strnicmp(rdbuf + 1, "EP0", 3) == 0) && (strnicmp(rdbuf + 6, "M12", 3) != 0)) {
|
|
|
+ tsdata->version = M06;
|
|
|
+
|
|
|
+ /* remove last '$' end marker */
|
|
|
+@@ -828,8 +860,24 @@ static int edt_ft5x06_ts_identify(struct
|
|
|
+ *p++ = '\0';
|
|
|
+ strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
|
|
|
+ strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
|
|
|
++ } else if (!(strnicmp(rdbuf + 6, "M12", 3))) {
|
|
|
++ tsdata->version = M12;
|
|
|
++
|
|
|
++ error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
|
|
|
++ 2, rdbuf);
|
|
|
++ if (error)
|
|
|
++ return error;
|
|
|
++
|
|
|
++ strlcpy(fw_version, rdbuf, 2);
|
|
|
++
|
|
|
++ error = edt_ft5x06_ts_readwrite(client, 1, "\xA8",
|
|
|
++ 1, rdbuf);
|
|
|
++ if (error)
|
|
|
++ return error;
|
|
|
++
|
|
|
++ snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M12",
|
|
|
++ rdbuf[0] >> 4, rdbuf[0] & 0x0F);
|
|
|
+ } else {
|
|
|
+- /* since there are only two versions around (M06, M09) */
|
|
|
+ tsdata->version = M09;
|
|
|
+
|
|
|
+ error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
|
|
|
+@@ -867,9 +915,25 @@ static void edt_ft5x06_ts_get_dt_default
|
|
|
+ {
|
|
|
+ struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
|
|
|
+
|
|
|
+- EDT_GET_PROP(threshold, reg_addr->reg_threshold);
|
|
|
+- EDT_GET_PROP(gain, reg_addr->reg_gain);
|
|
|
+- EDT_GET_PROP(offset, reg_addr->reg_offset);
|
|
|
++ switch (tsdata->version) {
|
|
|
++ case M12:
|
|
|
++ EDT_GET_PROP(threshold_M12, reg_addr->reg_threshold);
|
|
|
++ EDT_GET_PROP(gain_M12, reg_addr->reg_gain);
|
|
|
++ EDT_GET_PROP(offset_M12, reg_addr->reg_offset);
|
|
|
++ break;
|
|
|
++
|
|
|
++ case M09:
|
|
|
++ EDT_GET_PROP(threshold_M09, reg_addr->reg_threshold);
|
|
|
++ EDT_GET_PROP(gain_M09, reg_addr->reg_gain);
|
|
|
++ EDT_GET_PROP(offset_M09, reg_addr->reg_offset);
|
|
|
++ break;
|
|
|
++
|
|
|
++ case M06:
|
|
|
++ EDT_GET_PROP(threshold_M06, reg_addr->reg_threshold);
|
|
|
++ EDT_GET_PROP(gain_M06, reg_addr->reg_gain);
|
|
|
++ EDT_GET_PROP(offset_M06, reg_addr->reg_offset);
|
|
|
++ break;
|
|
|
++ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static void
|
|
|
+@@ -920,6 +984,15 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06
|
|
|
+ reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
|
|
|
+ break;
|
|
|
+
|
|
|
++ case M12:
|
|
|
++ reg_addr->reg_threshold = M12_REGISTER_THRESHOLD;
|
|
|
++ reg_addr->reg_report_rate = M12_REGISTER_REPORT_RATE;
|
|
|
++ reg_addr->reg_gain = M12_REGISTER_GAIN;
|
|
|
++ reg_addr->reg_offset = M12_REGISTER_OFFSET;
|
|
|
++ reg_addr->reg_num_x = M12_REGISTER_NUM_X;
|
|
|
++ reg_addr->reg_num_y = M12_REGISTER_NUM_Y;
|
|
|
++ break;
|
|
|
++
|
|
|
+ case M09:
|
|
|
+ reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
|
|
|
+ reg_addr->reg_gain = M09_REGISTER_GAIN;
|
|
|
+@@ -964,9 +1037,6 @@ static int edt_ft5x06_ts_probe(struct i2
|
|
|
+ int error;
|
|
|
+ char fw_version[EDT_NAME_LEN];
|
|
|
+
|
|
|
+-
|
|
|
+- printk(KERN_INFO "EDT-TC:: %s ::-----\n", __func__);
|
|
|
+-
|
|
|
+ dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
|
|
|
+
|
|
|
+ tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
|