Input: edt-ft5x06 - make distinction between m06/m09/generic more clear
Since the driver also is useful for some non-EDT touchscreens based on the focaltec chips introduce the concept of a "generic" focaltec based touch. Use a better heuristics for model detection and be more specific in the source. Signed-off-by: Simon Budig <simon.budig@kernelconcepts.de> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
adb77b3e51
commit
169110c364
|
@ -70,8 +70,9 @@
|
|||
#define EDT_RAW_DATA_DELAY 1000 /* usec */
|
||||
|
||||
enum edt_ver {
|
||||
M06,
|
||||
M09,
|
||||
EDT_M06,
|
||||
EDT_M09,
|
||||
GENERIC_FT,
|
||||
};
|
||||
|
||||
struct edt_reg_addr {
|
||||
|
@ -179,14 +180,15 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
|||
int error;
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
cmd = 0xf9; /* tell the controller to send touch data */
|
||||
offset = 5; /* where the actual touch data starts */
|
||||
tplen = 4; /* data comes in so called frames */
|
||||
crclen = 1; /* length of the crc data */
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case GENERIC_FT:
|
||||
cmd = 0x0;
|
||||
offset = 3;
|
||||
tplen = 6;
|
||||
|
@ -210,7 +212,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/* M09 does not send header or CRC */
|
||||
if (tsdata->version == M06) {
|
||||
if (tsdata->version == EDT_M06) {
|
||||
if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
|
||||
rdbuf[2] != datalen) {
|
||||
dev_err_ratelimited(dev,
|
||||
|
@ -233,7 +235,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
|||
continue;
|
||||
|
||||
/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
|
||||
if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN)
|
||||
if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
|
||||
continue;
|
||||
|
||||
x = ((buf[0] << 8) | buf[1]) & 0x0fff;
|
||||
|
@ -264,14 +266,15 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
|
|||
u8 wrbuf[4];
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
|
||||
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);
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case GENERIC_FT:
|
||||
wrbuf[0] = addr;
|
||||
wrbuf[1] = value;
|
||||
|
||||
|
@ -290,7 +293,7 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
|
|||
int error;
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
|
||||
wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
|
||||
wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
|
||||
|
@ -309,7 +312,8 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
|
|||
}
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case GENERIC_FT:
|
||||
wrbuf[0] = addr;
|
||||
error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
|
||||
wrbuf, 1, rdbuf);
|
||||
|
@ -368,11 +372,12 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
|
|||
}
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
addr = attr->addr_m06;
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case GENERIC_FT:
|
||||
addr = attr->addr_m09;
|
||||
break;
|
||||
|
||||
|
@ -437,11 +442,12 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
|
|||
}
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
addr = attr->addr_m06;
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
case GENERIC_FT:
|
||||
addr = attr->addr_m09;
|
||||
break;
|
||||
|
||||
|
@ -508,7 +514,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
|
|||
}
|
||||
|
||||
/* mode register is 0x3c when in the work mode */
|
||||
if (tsdata->version == M09)
|
||||
if (tsdata->version != EDT_M06)
|
||||
goto m09_out;
|
||||
|
||||
error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
|
||||
|
@ -545,7 +551,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
|
|||
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/GENERIC_FT\n");
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
@ -779,7 +785,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
|
|||
* at least M09 won't send 3 bytes here
|
||||
*/
|
||||
if (!(strncasecmp(rdbuf + 1, "EP0", 3))) {
|
||||
tsdata->version = M06;
|
||||
tsdata->version = EDT_M06;
|
||||
|
||||
/* remove last '$' end marker */
|
||||
rdbuf[EDT_NAME_LEN - 1] = '\0';
|
||||
|
@ -793,8 +799,16 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
|
|||
strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
|
||||
strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
|
||||
} else {
|
||||
/* since there are only two versions around (M06, M09) */
|
||||
tsdata->version = M09;
|
||||
/* If it is not an EDT M06 touchscreen, then the model
|
||||
* detection is a bit hairy. The different ft5x06
|
||||
* firmares around don't reliably implement the
|
||||
* identification registers. Well, we'll take a shot.
|
||||
*
|
||||
* The main difference between generic focaltec based
|
||||
* touches and EDT M09 is that we know how to retrieve
|
||||
* the max coordinates for the latter.
|
||||
*/
|
||||
tsdata->version = GENERIC_FT;
|
||||
|
||||
error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
|
||||
2, rdbuf);
|
||||
|
@ -808,8 +822,34 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
|
||||
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
|
||||
/* This "model identification" is not exact. Unfortunately
|
||||
* not all firmwares for the ft5x06 put useful values in
|
||||
* the identification registers.
|
||||
*/
|
||||
switch (rdbuf[0]) {
|
||||
case 0x35: /* EDT EP0350M09 */
|
||||
case 0x43: /* EDT EP0430M09 */
|
||||
case 0x50: /* EDT EP0500M09 */
|
||||
case 0x57: /* EDT EP0570M09 */
|
||||
case 0x70: /* EDT EP0700M09 */
|
||||
tsdata->version = EDT_M09;
|
||||
snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
|
||||
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
|
||||
break;
|
||||
case 0xa1: /* EDT EP1010ML00 */
|
||||
tsdata->version = EDT_M09;
|
||||
snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00",
|
||||
rdbuf[0] >> 4, rdbuf[0] & 0x0F);
|
||||
break;
|
||||
case 0x5a: /* Solomon Goldentek Display */
|
||||
snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0");
|
||||
break;
|
||||
default:
|
||||
snprintf(model_name, EDT_NAME_LEN,
|
||||
"generic ft5x06 (%02x)",
|
||||
rdbuf[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -853,8 +893,16 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
|
|||
if (reg_addr->reg_report_rate != NO_REGISTER)
|
||||
tsdata->report_rate = edt_ft5x06_register_read(tsdata,
|
||||
reg_addr->reg_report_rate);
|
||||
tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x);
|
||||
tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y);
|
||||
if (tsdata->version == EDT_M06 ||
|
||||
tsdata->version == EDT_M09) {
|
||||
tsdata->num_x = edt_ft5x06_register_read(tsdata,
|
||||
reg_addr->reg_num_x);
|
||||
tsdata->num_y = edt_ft5x06_register_read(tsdata,
|
||||
reg_addr->reg_num_y);
|
||||
} else {
|
||||
tsdata->num_x = -1;
|
||||
tsdata->num_y = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -863,7 +911,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
|
|||
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
|
||||
|
||||
switch (tsdata->version) {
|
||||
case M06:
|
||||
case EDT_M06:
|
||||
reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
|
||||
reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
|
||||
reg_addr->reg_gain = WORK_REGISTER_GAIN;
|
||||
|
@ -872,7 +920,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
|
|||
reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
|
||||
break;
|
||||
|
||||
case M09:
|
||||
case EDT_M09:
|
||||
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
|
||||
reg_addr->reg_report_rate = NO_REGISTER;
|
||||
reg_addr->reg_gain = M09_REGISTER_GAIN;
|
||||
|
@ -880,6 +928,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
|
|||
reg_addr->reg_num_x = M09_REGISTER_NUM_X;
|
||||
reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
|
||||
break;
|
||||
|
||||
case GENERIC_FT:
|
||||
/* this is a guesswork */
|
||||
reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
|
||||
reg_addr->reg_gain = M09_REGISTER_GAIN;
|
||||
reg_addr->reg_offset = M09_REGISTER_OFFSET;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -969,10 +1024,19 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
|||
input->id.bustype = BUS_I2C;
|
||||
input->dev.parent = &client->dev;
|
||||
|
||||
input_set_abs_params(input, ABS_MT_POSITION_X,
|
||||
0, tsdata->num_x * 64 - 1, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_Y,
|
||||
0, tsdata->num_y * 64 - 1, 0, 0);
|
||||
if (tsdata->version == EDT_M06 ||
|
||||
tsdata->version == EDT_M09) {
|
||||
input_set_abs_params(input, ABS_MT_POSITION_X,
|
||||
0, tsdata->num_x * 64 - 1, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_Y,
|
||||
0, tsdata->num_y * 64 - 1, 0, 0);
|
||||
} else {
|
||||
/* Unknown maximum values. Specify via devicetree */
|
||||
input_set_abs_params(input, ABS_MT_POSITION_X,
|
||||
0, 65535, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_Y,
|
||||
0, 65535, 0, 0);
|
||||
}
|
||||
|
||||
touchscreen_parse_properties(input, true, &tsdata->prop);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user