diff options
Diffstat (limited to 'drivers/input/touchscreen/edt-ft5x06.c')
-rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 96 |
1 files changed, 88 insertions, 8 deletions
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index bb2e1cbffba7..82beddb28761 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -24,6 +24,7 @@ #include <linux/irq.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/property.h> #include <linux/ratelimit.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -47,6 +48,8 @@ #define M09_REGISTER_NUM_X 0x94 #define M09_REGISTER_NUM_Y 0x95 +#define M12_REGISTER_REPORT_RATE 0x88 + #define EV_REGISTER_THRESHOLD 0x40 #define EV_REGISTER_GAIN 0x41 #define EV_REGISTER_OFFSET_Y 0x45 @@ -127,9 +130,12 @@ struct edt_ft5x06_ts_data { int max_support_points; char name[EDT_NAME_LEN]; + char fw_version[EDT_NAME_LEN]; struct edt_reg_addr reg_addr; enum edt_ver version; + unsigned int crc_errors; + unsigned int header_errors; }; struct edt_i2c_chip_data { @@ -178,6 +184,7 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, crc ^= buf[i]; if (crc != buf[buflen-1]) { + tsdata->crc_errors++; dev_err_ratelimited(&tsdata->client->dev, "crc error: 0x%02x expected, got 0x%02x\n", crc, buf[buflen-1]); @@ -235,6 +242,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) if (tsdata->version == EDT_M06) { if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || rdbuf[2] != datalen) { + tsdata->header_errors++; dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n", rdbuf[0], rdbuf[1], rdbuf[2]); @@ -523,9 +531,55 @@ static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER, /* 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, EV_REGISTER_THRESHOLD, 0, 255); -/* m06: range 3 to 14, m12: (0x64: 100Hz) */ +/* m06: range 3 to 14, m12: range 1 to 255 */ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, - NO_REGISTER, NO_REGISTER, 0, 255); + M12_REGISTER_REPORT_RATE, NO_REGISTER, 0, 255); + +static ssize_t model_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + + return sysfs_emit(buf, "%s\n", tsdata->name); +} + +static DEVICE_ATTR_RO(model); + +static ssize_t fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + + return sysfs_emit(buf, "%s\n", tsdata->fw_version); +} + +static DEVICE_ATTR_RO(fw_version); + +/* m06 only */ +static ssize_t header_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + + return sysfs_emit(buf, "%d\n", tsdata->header_errors); +} + +static DEVICE_ATTR_RO(header_errors); + +/* m06 only */ +static ssize_t crc_errors_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + + return sysfs_emit(buf, "%d\n", tsdata->crc_errors); +} + +static DEVICE_ATTR_RO(crc_errors); static struct attribute *edt_ft5x06_attrs[] = { &edt_ft5x06_attr_gain.dattr.attr, @@ -534,6 +588,10 @@ static struct attribute *edt_ft5x06_attrs[] = { &edt_ft5x06_attr_offset_y.dattr.attr, &edt_ft5x06_attr_threshold.dattr.attr, &edt_ft5x06_attr_report_rate.dattr.attr, + &dev_attr_model.attr, + &dev_attr_fw_version.attr, + &dev_attr_header_errors.attr, + &dev_attr_crc_errors.attr, NULL }; @@ -820,13 +878,13 @@ static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) #endif /* CONFIG_DEBUGFS */ static int edt_ft5x06_ts_identify(struct i2c_client *client, - struct edt_ft5x06_ts_data *tsdata, - char *fw_version) + struct edt_ft5x06_ts_data *tsdata) { u8 rdbuf[EDT_NAME_LEN]; char *p; int error; char *model_name = tsdata->name; + char *fw_version = tsdata->fw_version; /* see what we find if we assume it is a M06 * * if we get less than EDT_NAME_LEN, we don't want @@ -1030,7 +1088,8 @@ static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) case EDT_M09: case EDT_M12: reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; - reg_addr->reg_report_rate = NO_REGISTER; + reg_addr->reg_report_rate = tsdata->version == EDT_M12 ? + M12_REGISTER_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; @@ -1081,7 +1140,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, struct input_dev *input; unsigned long irq_flags; int error; - char fw_version[EDT_NAME_LEN]; + u32 report_rate; dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); @@ -1194,7 +1253,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, tsdata->input = input; tsdata->factory_mode = false; - error = edt_ft5x06_ts_identify(client, tsdata, fw_version); + error = edt_ft5x06_ts_identify(client, tsdata); if (error) { dev_err(&client->dev, "touchscreen probe failed\n"); return error; @@ -1210,9 +1269,30 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, edt_ft5x06_ts_get_defaults(&client->dev, tsdata); edt_ft5x06_ts_get_parameters(tsdata); + if (tsdata->reg_addr.reg_report_rate != NO_REGISTER && + !device_property_read_u32(&client->dev, + "report-rate-hz", &report_rate)) { + if (tsdata->version == EDT_M06) + tsdata->report_rate = clamp_val(report_rate, 30, 140); + else + tsdata->report_rate = clamp_val(report_rate, 1, 255); + + if (report_rate != tsdata->report_rate) + dev_warn(&client->dev, + "report-rate %dHz is unsupported, use %dHz\n", + report_rate, tsdata->report_rate); + + if (tsdata->version == EDT_M06) + tsdata->report_rate /= 10; + + edt_ft5x06_register_write(tsdata, + tsdata->reg_addr.reg_report_rate, + tsdata->report_rate); + } + dev_dbg(&client->dev, "Model \"%s\", Rev. \"%s\", %dx%d sensors\n", - tsdata->name, fw_version, tsdata->num_x, tsdata->num_y); + tsdata->name, tsdata->fw_version, tsdata->num_x, tsdata->num_y); input->name = tsdata->name; input->id.bustype = BUS_I2C; |