diff options
Diffstat (limited to 'drivers/input/touchscreen/edt-ft5x06.c')
-rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 110 |
1 files changed, 102 insertions, 8 deletions
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 1e18ca0d1b4e..702bfda7ee77 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -31,6 +31,7 @@ #include <linux/interrupt.h> #include <linux/input.h> #include <linux/i2c.h> +#include <linux/kernel.h> #include <linux/uaccess.h> #include <linux/delay.h> #include <linux/debugfs.h> @@ -53,6 +54,11 @@ #define M09_REGISTER_NUM_X 0x94 #define M09_REGISTER_NUM_Y 0x95 +#define EV_REGISTER_THRESHOLD 0x40 +#define EV_REGISTER_GAIN 0x41 +#define EV_REGISTER_OFFSET_Y 0x45 +#define EV_REGISTER_OFFSET_X 0x46 + #define NO_REGISTER 0xff #define WORK_REGISTER_OPMODE 0x3c @@ -73,6 +79,7 @@ enum edt_ver { EDT_M06, EDT_M09, EDT_M12, + EV_FT, GENERIC_FT, }; @@ -81,6 +88,8 @@ struct edt_reg_addr { int reg_report_rate; int reg_gain; int reg_offset; + int reg_offset_x; + int reg_offset_y; int reg_num_x; int reg_num_y; }; @@ -106,6 +115,8 @@ struct edt_ft5x06_ts_data { int threshold; int gain; int offset; + int offset_x; + int offset_y; int report_rate; int max_support_points; @@ -190,6 +201,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) case EDT_M09: case EDT_M12: + case EV_FT: case GENERIC_FT: cmd = 0x0; offset = 3; @@ -242,6 +254,10 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) x = ((buf[0] << 8) | buf[1]) & 0x0fff; y = ((buf[2] << 8) | buf[3]) & 0x0fff; + /* The FT5x26 send the y coordinate first */ + if (tsdata->version == EV_FT) + swap(x, y); + id = (buf[2] >> 4) & 0x0f; down = type != TOUCH_EVENT_UP; @@ -275,8 +291,10 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL); + /* fallthrough */ case EDT_M09: case EDT_M12: + case EV_FT: case GENERIC_FT: wrbuf[0] = addr; wrbuf[1] = value; @@ -315,8 +333,10 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, } break; + /* fallthrough */ case EDT_M09: case EDT_M12: + case EV_FT: case GENERIC_FT: wrbuf[0] = addr; error = edt_ft5x06_ts_readwrite(tsdata->client, 1, @@ -339,9 +359,10 @@ struct edt_ft5x06_attribute { u8 limit_high; u8 addr_m06; u8 addr_m09; + u8 addr_ev; }; -#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \ +#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_ev, \ _limit_low, _limit_high) \ struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ .dattr = __ATTR(_field, _mode, \ @@ -350,6 +371,7 @@ struct edt_ft5x06_attribute { .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ .addr_m06 = _addr_m06, \ .addr_m09 = _addr_m09, \ + .addr_ev = _addr_ev, \ .limit_low = _limit_low, \ .limit_high = _limit_high, \ } @@ -386,6 +408,10 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, addr = attr->addr_m09; break; + case EV_FT: + addr = attr->addr_ev; + break; + default: error = -ENODEV; goto out; @@ -457,6 +483,10 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, addr = attr->addr_m09; break; + case EV_FT: + addr = attr->addr_ev; + break; + default: error = -ENODEV; goto out; @@ -480,20 +510,28 @@ out: /* m06, m09: range 0-31, m12: range 0-5 */ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, - M09_REGISTER_GAIN, 0, 31); + M09_REGISTER_GAIN, EV_REGISTER_GAIN, 0, 31); /* m06, m09: range 0-31, m12: range 0-16 */ static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, - M09_REGISTER_OFFSET, 0, 31); + M09_REGISTER_OFFSET, NO_REGISTER, 0, 31); +/* m06, m09, m12: no supported, ev_ft: range 0-80 */ +static EDT_ATTR(offset_x, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, + EV_REGISTER_OFFSET_X, 0, 80); +/* m06, m09, m12: no supported, ev_ft: range 0-80 */ +static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, + EV_REGISTER_OFFSET_Y, 0, 80); /* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */ static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, - M09_REGISTER_THRESHOLD, 0, 255); + M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255); /* m06: range 3 to 14, m12: (0x64: 100Hz) */ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, - NO_REGISTER, 0, 255); + NO_REGISTER, NO_REGISTER, 0, 255); static struct attribute *edt_ft5x06_attrs[] = { &edt_ft5x06_attr_gain.dattr.attr, &edt_ft5x06_attr_offset.dattr.attr, + &edt_ft5x06_attr_offset_x.dattr.attr, + &edt_ft5x06_attr_offset_y.dattr.attr, &edt_ft5x06_attr_threshold.dattr.attr, &edt_ft5x06_attr_report_rate.dattr.attr, NULL @@ -605,8 +643,15 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) tsdata->threshold); edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, tsdata->gain); - edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, - tsdata->offset); + if (reg_addr->reg_offset != NO_REGISTER) + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, + tsdata->offset); + if (reg_addr->reg_offset_x != NO_REGISTER) + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, + tsdata->offset_x); + if (reg_addr->reg_offset_y != NO_REGISTER) + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, + tsdata->offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, tsdata->report_rate); @@ -867,6 +912,16 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, case 0x5a: /* Solomon Goldentek Display */ snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0"); break; + case 0x59: /* Evervision Display with FT5xx6 TS */ + tsdata->version = EV_FT; + error = edt_ft5x06_ts_readwrite(client, 1, "\x53", + 1, rdbuf); + if (error) + return error; + strlcpy(fw_version, rdbuf, 1); + snprintf(model_name, EDT_NAME_LEN, + "EVERVISION-FT5726NEi"); + break; default: snprintf(model_name, EDT_NAME_LEN, "generic ft5x06 (%02x)", @@ -902,6 +957,18 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev, edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val); tsdata->offset = val; } + + error = device_property_read_u32(dev, "offset-x", &val); + if (!error) { + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, val); + tsdata->offset_x = val; + } + + error = device_property_read_u32(dev, "offset-y", &val); + if (!error) { + edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, val); + tsdata->offset_y = val; + } } static void @@ -912,7 +979,15 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) tsdata->threshold = edt_ft5x06_register_read(tsdata, reg_addr->reg_threshold); tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); - tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); + if (reg_addr->reg_offset != NO_REGISTER) + tsdata->offset = + edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); + if (reg_addr->reg_offset_x != NO_REGISTER) + tsdata->offset_x = edt_ft5x06_register_read(tsdata, + reg_addr->reg_offset_x); + if (reg_addr->reg_offset_y != NO_REGISTER) + tsdata->offset_y = edt_ft5x06_register_read(tsdata, + reg_addr->reg_offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) tsdata->report_rate = edt_ft5x06_register_read(tsdata, reg_addr->reg_report_rate); @@ -940,6 +1015,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; reg_addr->reg_gain = WORK_REGISTER_GAIN; reg_addr->reg_offset = WORK_REGISTER_OFFSET; + reg_addr->reg_offset_x = NO_REGISTER; + reg_addr->reg_offset_y = NO_REGISTER; reg_addr->reg_num_x = WORK_REGISTER_NUM_X; reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; break; @@ -950,15 +1027,30 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) reg_addr->reg_report_rate = NO_REGISTER; reg_addr->reg_gain = M09_REGISTER_GAIN; reg_addr->reg_offset = M09_REGISTER_OFFSET; + reg_addr->reg_offset_x = NO_REGISTER; + reg_addr->reg_offset_y = NO_REGISTER; reg_addr->reg_num_x = M09_REGISTER_NUM_X; reg_addr->reg_num_y = M09_REGISTER_NUM_Y; break; + case EV_FT: + reg_addr->reg_threshold = EV_REGISTER_THRESHOLD; + reg_addr->reg_gain = EV_REGISTER_GAIN; + reg_addr->reg_offset = NO_REGISTER; + reg_addr->reg_offset_x = EV_REGISTER_OFFSET_X; + reg_addr->reg_offset_y = EV_REGISTER_OFFSET_Y; + reg_addr->reg_num_x = NO_REGISTER; + reg_addr->reg_num_y = NO_REGISTER; + reg_addr->reg_report_rate = NO_REGISTER; + 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; + reg_addr->reg_offset_x = NO_REGISTER; + reg_addr->reg_offset_y = NO_REGISTER; break; } } @@ -1155,6 +1247,7 @@ static const struct edt_i2c_chip_data edt_ft6236_data = { static const struct i2c_device_id edt_ft5x06_ts_id[] = { { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data }, + { .name = "ev-ft5726", .driver_data = (long)&edt_ft5506_data }, /* Note no edt- prefix for compatibility with the ft6236.c driver */ { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, { /* sentinel */ } @@ -1167,6 +1260,7 @@ static const struct of_device_id edt_ft5x06_of_match[] = { { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, + { .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data }, /* Note focaltech vendor prefix for compatibility with ft6236.c */ { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, { /* sentinel */ } |