* [PATCH v1 35/63] Input: atmel_mxt_ts - rely on calculated_crc rather than file config_crc
From: Jiada Wang @ 2019-08-16 8:34 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
From: Kautuk Consul <kautuk_consul@mentor.com>
We now prefer to rely on the calculated CRC and not on the CRC stored in
the file.
The new logic is as follows:
1) stored CRC of file != calculated CRC of file, then refuse the possible
corrupted file
2) calculated CRC of file != CRC of configuration in controller, then
update configuration in controller
3) calculated CRC of file == CRC of configuration in controller, then
ignore configuration file
Signed-off-by: Kautuk Consul <kautuk_consul@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 65 +++++++++++++-----------
1 file changed, 36 insertions(+), 29 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index aa913d2a0e3b..9cdb7754599c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1898,7 +1898,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
int ret;
int offset;
int i;
- u32 info_crc, config_crc, calculated_crc;
+ u32 info_crc, config_crc, calculated_crc = 0;
u16 crc_start = 0;
/* Make zero terminated copy of the OBP_RAW file */
@@ -1961,30 +1961,6 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
}
cfg.raw_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_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_dbg(dev, "Config CRC 0x%06X: OK\n",
- data->config_crc);
- ret = 0;
- goto release_raw;
- } else {
- dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
- data->config_crc, config_crc);
- }
- } else {
- dev_warn(dev,
- "Warning: Info CRC error - device=0x%06X file=0x%06X\n",
- data->info_crc, info_crc);
- }
-
/* Malloc memory to store configuration */
cfg.start_ofs = MXT_OBJECT_START +
data->info->object_num * sizeof(struct mxt_object) +
@@ -2008,14 +1984,45 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
else
dev_warn(dev, "Could not find CRC start\n");
- if (crc_start > cfg.start_ofs) {
+ if (crc_start > cfg.start_ofs)
calculated_crc = mxt_calculate_crc(cfg.mem,
crc_start - cfg.start_ofs,
cfg.mem_size);
- if (config_crc > 0 && config_crc != calculated_crc)
- dev_warn(dev, "Config CRC in file inconsistent, calculated=%06X, file=%06X\n",
- calculated_crc, config_crc);
+ /* If the CRC stored in the file is not the same as what
+ * was calculated by mxt_calculate_crc, this means we
+ * have to refuse the config file and abort download.
+ */
+ if (config_crc != calculated_crc) {
+ dev_warn(dev,
+ "Config CRC in file inconsistent, calculated=%06X, file=%06X\n",
+ calculated_crc, config_crc);
+ ret = 0;
+ goto release_mem;
+ }
+
+ /*
+ * 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_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_dbg(dev, "Config CRC 0x%06X: OK\n",
+ data->config_crc);
+ ret = 0;
+ goto release_mem;
+ } else {
+ dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
+ data->config_crc, config_crc);
+ }
+ } else {
+ dev_warn(dev,
+ "Warning: Info CRC error - device=0x%06X file=0x%06X\n",
+ data->info_crc, info_crc);
}
ret = mxt_upload_cfg_mem(data, &cfg);
--
2.19.2
^ permalink raw reply related
* [PATCH v1 36/63] Input: atmel_mxt_ts - configure and use gpios as real gpios
From: Jiada Wang @ 2019-08-16 8:34 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083525.19071-1-jiada_wang@mentor.com>
From: Kautuk Consul <kautuk_consul@mentor.com>
The upstream Atmel mXT driver implementation seems to handle the
T19 GPIO/PWM object as a key pad. Keys can be defined in the
device tree ("linux,gpio-keymap") and will be transported as key
events to the Linux input device if GPIO state changes.
With our hardware, the GPIO pins of the touch controller are
connected to a PWM/backlight controller and used as supervision
inputs. We like to read the status of the pins by a script or an
application in the sysfs.
Adding newer sysfs entries which shall be placed in the input
class directory eg:
/sys/class/input/input<n>/backlight_error1
Signed-off-by: Kautuk Consul <kautuk_consul@mentor.com>
Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
.../bindings/input/atmel,maxtouch.txt | 15 +++
drivers/input/touchscreen/atmel_mxt_ts.c | 120 ++++++++++++++++++
2 files changed, 135 insertions(+)
diff --git a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt
index d7db16920083..7afe12a93202 100644
--- a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt
+++ b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt
@@ -42,6 +42,9 @@ Optional properties for main touchpad device:
- atmel,input_name: Override name of input device from the default.
+- atmel,gpios: Specify the GPIO input pins whose status will be read via the
+ /sys/class/input/input<n>/backlight_error<x> sysfs entries.
+
Example:
touch@4b {
@@ -49,4 +52,16 @@ Example:
reg = <0x4b>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(W, 3) IRQ_TYPE_LEVEL_LOW>;
+
+ atmel,gpios {
+ backlight_error1 {
+ gpio = <3 GPIO_ACTIVE_HIGH>; /* connected to
+ * the GPIO3 pin of mXT input */
+ };
+
+ backlight_error2 {
+ gpio = <5 GPIO_ACTIVE_HIGH>; /* connected to
+ * the GPIO5 pin of mXT input */
+ };
+ };
};
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 9cdb7754599c..a8e2b927bb12 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -414,6 +414,15 @@ struct mxt_data {
/* Indicates whether device is updating configuration */
bool updating_config;
+
+ unsigned long gpio_input_pin_status;
+ struct attribute_group gpio_attrs;
+ unsigned long gpio_input_pin_status_default;
+};
+
+struct mxt_gpio_attr {
+ struct device_attribute attr;
+ int bit_index;
};
struct mxt_vb2_buffer {
@@ -1381,6 +1390,7 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
} else if (report_id == data->T19_reportid) {
mxt_input_button(data, message);
data->update_input = true;
+ data->gpio_input_pin_status = message[1];
} else if (report_id >= data->T15_reportid_min
&& report_id <= data->T15_reportid_max) {
mxt_proc_t15_messages(data, message);
@@ -2747,6 +2757,16 @@ static int mxt_initialize_input_device(struct mxt_data *data)
goto err_free_mem;
}
+ if (data->gpio_attrs.attrs) {
+ error = sysfs_create_group(&input_dev->dev.kobj,
+ &data->gpio_attrs);
+ if (error) {
+ dev_err(dev, "Failure %d creating sysfs group\n",
+ error);
+ goto err_free_mem;
+ }
+ }
+
data->input_dev = input_dev;
return 0;
@@ -3995,10 +4015,26 @@ static void mxt_input_close(struct input_dev *dev)
dev_err(&data->client->dev, "%s failed rc=%d\n", __func__, ret);
}
+static ssize_t mxt_gpio_input_pin_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ struct mxt_gpio_attr *attr_p = container_of(attr, struct mxt_gpio_attr,
+ attr);
+ int pin_status = test_bit(attr_p->bit_index,
+ &data->gpio_input_pin_status);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", pin_status);
+}
+
static int mxt_parse_device_properties(struct mxt_data *data)
{
static const char keymap_property[] = "linux,gpio-keymap";
+ static const char gpios_property[] = "atmel,gpios";
struct device *dev = &data->client->dev;
+ struct device_node *np = dev ? dev->of_node : NULL;
+ struct device_node *np_gpio;
u32 *keymap;
int n_keys;
int error;
@@ -4036,7 +4072,89 @@ static int mxt_parse_device_properties(struct mxt_data *data)
device_property_read_u32(dev, "atmel,suspend-mode", &data->suspend_mode);
+ np_gpio = of_get_child_by_name(np, gpios_property);
+ if (np_gpio) {
+ int gpio_pin;
+ struct mxt_gpio_attr *attr_p;
+ char *sysfs_gpio_file_name;
+ u8 num_gpio_pins = 0;
+
+ np_gpio = of_find_node_with_property(np_gpio, "gpio");
+ if (!np_gpio)
+ return -EINVAL;
+
+ data->gpio_attrs.attrs =
+ devm_kzalloc(dev,
+ 9 * sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!data->gpio_attrs.attrs) {
+ error = -ENOMEM;
+ goto err_gpios_property_put;
+ }
+
+ do {
+ attr_p = devm_kmalloc(dev,
+ sizeof(struct mxt_gpio_attr),
+ GFP_KERNEL);
+ if (!attr_p) {
+ error = -ENOMEM;
+ goto err_gpios_property_put;
+ }
+
+ error = of_property_read_u32_index(np_gpio, "gpio", 0,
+ &gpio_pin);
+ if (error) {
+ dev_warn(dev,
+ "Couldn't read gpio property for node : %s\n",
+ np_gpio->name);
+ error = -EINVAL;
+ goto err_gpios_property_put;
+ }
+
+ if (gpio_pin > 7) {
+ dev_warn(dev,
+ "Incorrect GPIO pin index for node %s: %u\n",
+ np_gpio->name, gpio_pin);
+ error = -EINVAL;
+ goto err_gpios_property_put;
+ }
+
+ sysfs_gpio_file_name =
+ devm_kmalloc(dev,
+ strlen(np_gpio->name) + 1,
+ GFP_KERNEL);
+ if (!sysfs_gpio_file_name) {
+ error = -ENOMEM;
+ goto err_gpios_property_put;
+ }
+
+ strcpy(sysfs_gpio_file_name, np_gpio->name);
+
+ sysfs_attr_init(&attr_p->attr.attr);
+
+ attr_p->attr.attr.name = sysfs_gpio_file_name;
+ attr_p->attr.attr.mode = 0444;
+ attr_p->attr.show = mxt_gpio_input_pin_read;
+ attr_p->attr.store = NULL;
+ attr_p->bit_index = gpio_pin;
+
+ data->gpio_input_pin_status_default |= BIT(gpio_pin);
+
+ data->gpio_attrs.attrs[num_gpio_pins++] =
+ &attr_p->attr.attr;
+ } while ((np_gpio =
+ of_find_node_with_property(np_gpio, "gpio")) &&
+ num_gpio_pins < 8);
+
+ if (np_gpio)
+ of_node_put(np_gpio);
+ }
+
return 0;
+
+err_gpios_property_put:
+ of_node_put(np_gpio);
+ return error;
}
static const struct dmi_system_id chromebook_T9_suspend_dmi[] = {
@@ -4106,6 +4224,8 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (error)
return error;
+ data->gpio_input_pin_status = data->gpio_input_pin_status_default;
+
if (data->pcfg_name)
mxt_update_file_name(&data->client->dev,
&data->cfg_name,
--
2.19.2
^ permalink raw reply related
* [PATCH v1 37/63] input: atmel_mxt_ts: export GPIO reset line via sysfs
From: Jiada Wang @ 2019-08-16 8:34 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083525.19071-1-jiada_wang@mentor.com>
From: "George G. Davis" <george_davis@mentor.com>
N.B. Modifying the atmel_mxt_ts GPIO reset line during operation will
cause problems with normal driver operation. This feature is provided
as a diagnostic debug aid. It does not take into consideration any
pending operations which may be in progress. Modifying the atmel_mxt_ts
GPIO reset line at any time will inevitably cause the driver to fail.
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Rajeev Kumar <rajeev_kumar@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index a8e2b927bb12..def9f94d73ef 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -4240,6 +4240,19 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
return error;
}
+ if (data->reset_gpio) {
+ error = gpiod_export(data->reset_gpio, 0);
+ if (error)
+ return error;
+
+ error = gpiod_export_link(&client->dev, "reset",
+ data->reset_gpio);
+ if (error) {
+ gpiod_unexport(data->reset_gpio);
+ return error;
+ }
+ }
+
if (data->suspend_mode == MXT_SUSPEND_REGULATOR) {
error = mxt_acquire_irq(data);
if (error)
@@ -4273,6 +4286,10 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
mxt_free_input_device(data);
mxt_free_object_table(data);
sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group);
+ if (data->reset_gpio) {
+ sysfs_remove_link(&client->dev.kobj, "reset");
+ gpiod_unexport(data->reset_gpio);
+ }
return error;
}
@@ -4282,6 +4299,10 @@ static int mxt_remove(struct i2c_client *client)
disable_irq(data->irq);
sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group);
+ if (data->reset_gpio) {
+ sysfs_remove_link(&client->dev.kobj, "reset");
+ gpiod_unexport(data->reset_gpio);
+ }
mxt_debug_msg_remove(data);
mxt_sysfs_remove(data);
mxt_free_input_device(data);
--
2.19.2
^ permalink raw reply related
* [PATCH v1 38/63] Input: atmel_mxt_ts: Add support for run self-test routine.
From: Jiada Wang @ 2019-08-16 8:35 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083525.19071-1-jiada_wang@mentor.com>
From: Nikhil Ravindran <Nikhil.Ravindran@in.bosch.com>
The self test object T25 runs self test routines in device to find faults
Sysfs entry add to start self test routine and read back the test results
for atmel touchcontrollers.The feature will be used for A-IVI and CAF projects.
Signed-off-by: Nikhil Ravindran <Nikhil.Ravindran@in.bosch.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 111 +++++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index def9f94d73ef..be63002c2b31 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -336,6 +336,9 @@ struct mxt_data {
u8 t100_aux_ampl;
u8 t100_aux_area;
u8 t100_aux_vect;
+ u16 T25_address;
+ u8 T25_reportid;
+ u8 t25_msg[6];
struct bin_attribute mem_access_attr;
bool debug_enabled;
bool debug_v2_enabled;
@@ -418,6 +421,8 @@ struct mxt_data {
unsigned long gpio_input_pin_status;
struct attribute_group gpio_attrs;
unsigned long gpio_input_pin_status_default;
+
+ bool t25_status;
};
struct mxt_gpio_attr {
@@ -1360,6 +1365,24 @@ static void mxt_proc_t93_messages(struct mxt_data *data, u8 *msg)
dev_info(dev, "T93 report double tap %d\n", status);
}
+static void mxt_proc_t25_messages(struct mxt_data *data, u8 *msg)
+{
+ struct device *dev = &data->client->dev;
+
+ /* Output debug if status has changed */
+ dev_dbg(dev, "T25 Status 0x%x Info: %x %x %x %x %x\n",
+ msg[1],
+ msg[2],
+ msg[3],
+ msg[4],
+ msg[5],
+ msg[6]);
+
+ /* Save current status */
+ memcpy(&data->t25_msg[0], &msg[1], sizeof(data->t25_msg));
+ data->t25_status = false;
+}
+
static int mxt_proc_message(struct mxt_data *data, u8 *message)
{
u8 report_id = message[0];
@@ -1391,6 +1414,8 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
mxt_input_button(data, message);
data->update_input = true;
data->gpio_input_pin_status = message[1];
+ } else if (report_id == data->T25_reportid) {
+ mxt_proc_t25_messages(data, message);
} else if (report_id >= data->T15_reportid_min
&& report_id <= data->T15_reportid_max) {
mxt_proc_t15_messages(data, message);
@@ -1615,6 +1640,84 @@ static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
return 0;
}
+static int mxt_t25_command(struct mxt_data *data, u8 cmd, bool wait)
+{
+ u16 reg;
+ int timeout_counter = 0;
+ int ret;
+ u8 val[2];
+
+ reg = data->T25_address;
+ val[0] = 0x3;
+ val[1] = cmd;
+
+ data->t25_status = true;
+ ret = __mxt_write_reg(data->client, reg, sizeof(val), val);
+ if (ret) {
+ data->t25_status = false;
+ return ret;
+ }
+
+ if (!wait)
+ return 0;
+
+ do {
+ msleep(MXT_WAKEUP_TIME);
+ ret = __mxt_read_reg(data->client, reg + 1, 1, &val[1]);
+ if (ret)
+ return ret;
+ } while ((val[1] != 0) && (timeout_counter++ <= 100));
+
+ if (timeout_counter > 100) {
+ dev_err(&data->client->dev, "Command failed!\n");
+ data->t25_status = false;
+ return -EIO;
+ }
+ return 0;
+}
+
+/* Firmware Version is returned as Major.Minor.Build */
+static ssize_t mxt_t25_selftest_show(struct device *dev, struct
+ device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ ssize_t offset = 0;
+
+ if (data->t25_status)
+ return -EAGAIN;
+
+ if (data->t25_msg[0] == 0xFE)
+ offset += scnprintf(buf, PAGE_SIZE, "PASS\n");
+ else
+ offset += scnprintf(buf, PAGE_SIZE, "FAILED\n");
+
+ offset += scnprintf(buf + offset, PAGE_SIZE, "%x %x %x %x %x %x\n",
+ data->t25_msg[0],
+ data->t25_msg[1],
+ data->t25_msg[2],
+ data->t25_msg[3],
+ data->t25_msg[4],
+ data->t25_msg[5]);
+ return offset;
+}
+
+static ssize_t mxt_t25_selftest_store(struct device *dev, struct
+ device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ u32 cmd;
+
+ if (sscanf(buf, "%x", &cmd) == 1) {
+ if (mxt_t25_command(data, (u8)cmd, 1) == 0)
+ return count;
+
+ dev_dbg(dev, "mxt_t25_cmd_store write cmd %x error\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int mxt_acquire_irq(struct mxt_data *data)
{
int error;
@@ -2091,6 +2194,8 @@ static void mxt_free_object_table(struct mxt_data *data)
data->T15_reportid_max = 0;
data->T18_address = 0;
data->T19_reportid = 0;
+ data->T25_address = 0;
+ data->T25_reportid = 0;
data->T42_reportid_min = 0;
data->T42_reportid_max = 0;
data->T44_address = 0;
@@ -2178,6 +2283,10 @@ static int mxt_parse_object_table(struct mxt_data *data,
case MXT_SPT_COMMSCONFIG_T18:
data->T18_address = object->start_address;
break;
+ case MXT_SPT_SELFTEST_T25:
+ data->T25_address = object->start_address;
+ data->T25_reportid = min_id;
+ break;
case MXT_PROCI_TOUCHSUPPRESSION_T42:
data->T42_reportid_min = min_id;
data->T42_reportid_max = max_id;
@@ -3823,6 +3932,7 @@ static DEVICE_ATTR(debug_enable, S_IWUSR | S_IRUSR, mxt_debug_enable_show,
static DEVICE_ATTR(debug_v2_enable, S_IWUSR | S_IRUSR, NULL,
mxt_debug_v2_enable_store);
static DEVICE_ATTR(debug_notify, S_IRUGO, mxt_debug_notify_show, NULL);
+static DEVICE_ATTR(t25, 0600, mxt_t25_selftest_show, mxt_t25_selftest_store);
static struct attribute *mxt_attrs[] = {
&dev_attr_fw_version.attr,
@@ -3833,6 +3943,7 @@ static struct attribute *mxt_attrs[] = {
&dev_attr_debug_enable.attr,
&dev_attr_debug_v2_enable.attr,
&dev_attr_debug_notify.attr,
+ &dev_attr_t25.attr,
NULL
};
--
2.19.2
^ permalink raw reply related
* [PATCH v1 39/63] Input: touchscreen: Atmel: Add device tree support for T15 key array objects
From: Jiada Wang @ 2019-08-16 8:35 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083525.19071-1-jiada_wang@mentor.com>
From: Daniel Gong <Zhanli.Gong@cn.bosch.com>
Signed-off-by: Daniel Gong <Zhanli.Gong@cn.bosch.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 29 ++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index be63002c2b31..3b9544c0a209 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -4143,10 +4143,12 @@ static int mxt_parse_device_properties(struct mxt_data *data)
{
static const char keymap_property[] = "linux,gpio-keymap";
static const char gpios_property[] = "atmel,gpios";
+ static const char buttons_property[] = "atmel,key-buttons";
struct device *dev = &data->client->dev;
struct device_node *np = dev ? dev->of_node : NULL;
struct device_node *np_gpio;
u32 *keymap;
+ u32 *buttonmap;
int n_keys;
int error;
@@ -4181,6 +4183,33 @@ static int mxt_parse_device_properties(struct mxt_data *data)
data->t19_num_keys = n_keys;
}
+ if (device_property_present(dev, buttons_property)) {
+ n_keys = device_property_read_u32_array(dev, buttons_property,
+ NULL, 0);
+ if (n_keys <= 0) {
+ error = n_keys < 0 ? n_keys : -EINVAL;
+ dev_err(dev, "invalid/malformed '%s' property: %d\n",
+ buttons_property, error);
+ return error;
+ }
+
+ buttonmap = devm_kmalloc_array(dev, n_keys, sizeof(*buttonmap),
+ GFP_KERNEL);
+ if (!buttonmap)
+ return -ENOMEM;
+
+ error = device_property_read_u32_array(dev, buttons_property,
+ buttonmap, n_keys);
+ if (error) {
+ dev_err(dev, "failed to parse '%s' property: %d\n",
+ buttons_property, error);
+ return error;
+ }
+
+ data->t15_keymap = buttonmap;
+ data->t15_num_keys = n_keys;
+ }
+
device_property_read_u32(dev, "atmel,suspend-mode", &data->suspend_mode);
np_gpio = of_get_child_by_name(np, gpios_property);
--
2.19.2
^ permalink raw reply related
* [PATCH v1 40/63] input: atmel_mxt_ts: Add Missing Delay for reset handling of Atmel touch panel controller in detachable displays.
From: Jiada Wang @ 2019-08-16 8:35 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
From: keerthikumarp <Keerthikumar.Padmanabha@in.bosch.com>
In case of attached display, the touchpanel reset is controlled
via imx gpio's from atmel driver and the delay between
touchpanel reset and the time at which the chip becomes capable to
communicate with the host processor, has be taken care.
However in case of detachable displays, the touchpanel reset is
controlled via a deserializer gpio which is triggered just before
the atmel driver is probed.The delay between touchpanel reset and
the time at which the chip becomes capable to communicate (as
specified in datasheet) was not being accounted for. This patch
introduces that delay.
Signed-off-by: keerthikumarp <Keerthikumar.Padmanabha@in.bosch.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3b9544c0a209..bc94adec6631 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -4407,6 +4407,10 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
msleep(MXT_RESET_GPIO_TIME);
gpiod_set_value(data->reset_gpio, 1);
msleep(MXT_RESET_INVALID_CHG);
+ } else {
+ dev_dbg(&client->dev,
+ "atmel reset pin not found in device tree");
+ msleep(MXT_RESET_TIME);
}
error = sysfs_create_group(&client->dev.kobj, &mxt_fw_attr_group);
--
2.19.2
^ permalink raw reply related
* [PATCH v1 41/63] Input: touchscreen: Atmel: Enable IRQ_DISABLE_UNLAZY flag for interrupt
From: Jiada Wang @ 2019-08-16 8:35 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083558.19189-1-jiada_wang@mentor.com>
From: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com>
The de-/serializer driver has defined only irq_mask "ds90ub927_irq_mask" and
irq_unmask "ds90ub927_irq_unmask" callback functions. And de-/serializer
driver doesn't implement the irq_disable and irq_enable callback functions.
Hence inorder to invoke irq_mask callback function when disable_irq_nosync is
called the IRQ_DISABLE_UNLAZY interrupt flag should be set. If not the
disable_irq_nosync will just increment the depth field in the irq
descriptor only once as shown below.
disable_irq_nosync
__disable_irq_nosync
__disable_irq (desc->depth++)
irq_disable
if irq_disable present -----------> if IRQ_DISABLE_UNLAZYflag set
| no |
yes | yes |
| |
desc->irq_data.chip->irq_disable desc->irq_data.chip->irq_unmask
(ds90ub927_irq_mask)
disable_irq
__disable_irq_nosync
__disable_irq
(desc->depth++)
But the enable_irq will try to decrement the depth field twice which generates
the backtrace stating "Unbalanced enable for irq 293". This is because there is
no IRQ_DISABLE_UNLAZY flag check while calling irq_unmask callback function
of the "ds90ub927_irq_unmask" de-/serializer via enable_irq.
enable_irq
__enable_irq (desc->depth--)
irq_enable
if irq_enable present -------------> desc->irq_data.chip->irq_unmask
| no (ds90ub927_irq_unmask)
yes | enable_irq
| __enable_irq (desc->depth--)
(desc->irq_data.chip->irq_enable)
Signed-off-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index bc94adec6631..c6ba061098c0 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -4349,6 +4349,8 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
client->adapter->nr, client->addr);
+ irq_set_status_flags(client->irq, IRQ_DISABLE_UNLAZY);
+
data->client = client;
i2c_set_clientdata(client, data);
@@ -4434,6 +4436,8 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
sysfs_remove_link(&client->dev.kobj, "reset");
gpiod_unexport(data->reset_gpio);
}
+ if (data->irq)
+ irq_clear_status_flags(data->irq, IRQ_DISABLE_UNLAZY);
return error;
}
@@ -4449,6 +4453,8 @@ static int mxt_remove(struct i2c_client *client)
}
mxt_debug_msg_remove(data);
mxt_sysfs_remove(data);
+ if (data->irq)
+ irq_clear_status_flags(data->irq, IRQ_DISABLE_UNLAZY);
mxt_free_input_device(data);
mxt_free_object_table(data);
--
2.19.2
^ permalink raw reply related
* [PATCH v2 42/63] Input: atmel_mxt_ts: Limit the max bytes transferred in an i2c transaction
From: Jiada Wang @ 2019-08-16 8:35 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083558.19189-1-jiada_wang@mentor.com>
From: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
In mxt_process_messages_until_invalid() function, driver tries to read
all possible reportid in a single i2c transaction. Number of bytes read
is limited by the max_reportid parameter.
If the max_reportid is a very large value, then a large chunk of bytes
will be requested from the controller in a single i2c transaction.
This transaction can fail due to timeout. This is visible when the
Atmel controller is connected to the SOC via a i2c mux hardware.
New property 'atmel,mtu' is created. This property limits the maximum
number of bytes that can read/transferred in an i2c transcation
Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
.../bindings/input/atmel,maxtouch.txt | 3 +++
drivers/input/touchscreen/atmel_mxt_ts.c | 26 +++++++++++++++++--
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt
index 7afe12a93202..a7f9a8e551f7 100644
--- a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt
+++ b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt
@@ -45,6 +45,8 @@ Optional properties for main touchpad device:
- atmel,gpios: Specify the GPIO input pins whose status will be read via the
/sys/class/input/input<n>/backlight_error<x> sysfs entries.
+- atmel,mtu: Maximum number of bytes that can read/transferred in an i2c transaction
+
Example:
touch@4b {
@@ -52,6 +54,7 @@ Example:
reg = <0x4b>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(W, 3) IRQ_TYPE_LEVEL_LOW>;
+ atmel,mtu = <200>
atmel,gpios {
backlight_error1 {
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c6ba061098c0..e315ad3a8d2a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -421,6 +421,7 @@ struct mxt_data {
unsigned long gpio_input_pin_status;
struct attribute_group gpio_attrs;
unsigned long gpio_input_pin_status_default;
+ unsigned int mtu;
bool t25_status;
};
@@ -1522,13 +1523,30 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
return IRQ_HANDLED;
}
+static u8 mxt_max_msg_read_count(struct mxt_data *data)
+{
+ u8 count_limit = data->mtu / data->T5_msg_size;
+
+ if (!data->mtu)
+ return data->max_reportid;
+
+ if (data->mtu < data->T5_msg_size) {
+ WARN(1, "mtu set is lesser than the T5 message size\n");
+ /* Return count of 1, as fallback */
+ return 1;
+ }
+
+ return min(count_limit, data->max_reportid);
+}
+
static int mxt_process_messages_until_invalid(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
int count, read;
- u8 tries = 2;
+ int tries;
- count = data->max_reportid;
+ count = mxt_max_msg_read_count(data);
+ tries = (data->max_reportid / count) + 1;
/* Read messages until we force an invalid */
do {
@@ -4290,6 +4308,10 @@ static int mxt_parse_device_properties(struct mxt_data *data)
of_node_put(np_gpio);
}
+ device_property_read_u32(dev, "atmel,mtu", &data->mtu);
+ if (data->mtu)
+ dev_dbg(dev, "mtu is set as %d\n", data->mtu);
+
return 0;
err_gpios_property_put:
--
2.19.2
^ permalink raw reply related
* [PATCH v1 43/63] Input: atmel_mxt_ts: update stale use_retrigen_workaround flag
From: Jiada Wang @ 2019-08-16 8:35 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083558.19189-1-jiada_wang@mentor.com>
From: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
If after configuration update, retrigen status is enabled, the
mxt_check_retrigen() function, called after configuration update,
does not clear the use_retrigen_workaround flag, if it was previously
set.
Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index e315ad3a8d2a..b3d40390abb6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1857,6 +1857,8 @@ static int mxt_check_retrigen(struct mxt_data *data)
int error;
int val;
+ data->use_retrigen_workaround = false;
+
if (irq_get_trigger_type(data->irq) & IRQF_TRIGGER_LOW)
return 0;
--
2.19.2
^ permalink raw reply related
* [PATCH v1 44/63] Input: atmel_mxt_ts: return error from mxt_process_messages_until_invalid()
From: Jiada Wang @ 2019-08-16 8:35 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083558.19189-1-jiada_wang@mentor.com>
From: Dean Jenkins <Dean_Jenkins@mentor.com>
mxt_process_messages_until_invalid() failed to propagate the error
code from mxt_read_and_process_messages() so return the error code.
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
Signed-off-by: Deepak Das <deepak_das@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b3d40390abb6..ed5b98c067e8 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1551,6 +1551,8 @@ static int mxt_process_messages_until_invalid(struct mxt_data *data)
/* Read messages until we force an invalid */
do {
read = mxt_read_and_process_messages(data, count);
+ if (read < 0)
+ return read;
if (read < count)
return 0;
} while (--tries);
--
2.19.2
^ permalink raw reply related
* [PATCH v1 45/63] Input: Atmel: improve error handling in mxt_start()
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
From: Deepak Das <deepak_das@mentor.com>
mxt_start() does not return error in any of
the failure cases which will allow input_dev->open()
to return success even in case of any failure.
This commit modifies mxt_start() to return error
in failure cases.
Signed-off-by: Deepak Das <deepak_das@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 31 ++++++++++++------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ed5b98c067e8..232262736029 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -4043,12 +4043,13 @@ static int mxt_start(struct mxt_data *data)
switch (data->suspend_mode) {
case MXT_SUSPEND_T9_CTRL:
- mxt_soft_reset(data);
-
+ ret = mxt_soft_reset(data);
+ if (ret)
+ break;
/* Touch enable */
/* 0x83 = SCANEN | RPTEN | ENABLE */
- mxt_write_object(data,
- MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83);
+ ret = mxt_write_object(data,
+ MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83);
break;
case MXT_SUSPEND_REGULATOR:
@@ -4062,27 +4063,26 @@ static int mxt_start(struct mxt_data *data)
* Discard any touch messages still in message buffer
* from before chip went to sleep
*/
- mxt_process_messages_until_invalid(data);
+ ret = mxt_process_messages_until_invalid(data);
+ if (ret)
+ break;
ret = mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
if (ret)
- return ret;
+ break;
/* Recalibrate since chip has been in deep sleep */
ret = mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
if (ret)
- return ret;
+ break;
ret = mxt_acquire_irq(data);
- if (ret)
- return ret;
-
- break;
}
- data->suspended = false;
+ if (!ret)
+ data->suspended = false;
- return 0;
+ return ret;
}
static int mxt_stop(struct mxt_data *data)
@@ -4511,6 +4511,7 @@ static int __maybe_unused mxt_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
+ int ret = 0;
if (!input_dev)
return 0;
@@ -4518,11 +4519,11 @@ static int __maybe_unused mxt_resume(struct device *dev)
mutex_lock(&input_dev->mutex);
if (input_dev->users)
- mxt_start(data);
+ ret = mxt_start(data);
mutex_unlock(&input_dev->mutex);
- return 0;
+ return ret;
}
static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
--
2.19.2
^ permalink raw reply related
* [PATCH v1 46/63] Input: Atmel: improve error handling in mxt_initialize()
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083724.19341-1-jiada_wang@mentor.com>
From: Deepak Das <deepak_das@mentor.com>
Currently mxt_initialize() tries to probe bootloader mode
even if valid bootloader address is not specified.
This commit modifies mxt_initialize() to return error
if Device is not in appmode and bootloader address is
not specified.
This commit also returns error code from mxt_send_bootloader_cmd()
in mxt_initialize().
Signed-off-by: Deepak Das <deepak_das@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 33 +++++++++++++++++-------
1 file changed, 23 insertions(+), 10 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 232262736029..3999d3e31a6a 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -718,17 +718,13 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
return 0;
}
-static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address)
+static int mxt_probe_bootloader(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
int error;
u8 buf[3];
bool crc_failure, extended_id;
- error = mxt_lookup_bootloader_address(data, alt_address);
- if (error)
- return error;
-
/* Check bootloader status and version information */
error = mxt_bootloader_read(data, buf, sizeof(buf));
if (error)
@@ -2930,13 +2926,25 @@ static int mxt_initialize(struct mxt_data *data)
if (!error)
break;
+ dev_info(&client->dev,
+ "info block read failed (%d), so try bootloader method\n",
+ error);
+
+ error = mxt_lookup_bootloader_address(data, false);
+ if (error) {
+ dev_info(&client->dev,
+ "Bootloader address is not specified\n");
+ return error;
+ }
/* Check bootloader state */
- error = mxt_probe_bootloader(data, false);
+ error = mxt_probe_bootloader(data);
if (error) {
dev_info(&client->dev, "Trying alternate bootloader address\n");
- error = mxt_probe_bootloader(data, true);
+ mxt_lookup_bootloader_address(data, true);
+ error = mxt_probe_bootloader(data);
if (error) {
- /* Chip is not in appmode or bootloader mode */
+ dev_err(&client->dev,
+ "Chip is not in appmode or bootloader mode\n");
return error;
}
}
@@ -2953,7 +2961,9 @@ static int mxt_initialize(struct mxt_data *data)
}
/* Attempt to exit bootloader into app mode */
- mxt_send_bootloader_cmd(data, false);
+ error = mxt_send_bootloader_cmd(data, false);
+ if (error)
+ return error;
msleep(MXT_FW_RESET_TIME);
}
@@ -3645,8 +3655,11 @@ static int mxt_enter_bootloader(struct mxt_data *data)
msleep(MXT_RESET_TIME);
+ ret = mxt_lookup_bootloader_address(data, false);
+ if (ret)
+ return ret;
/* Do not need to scan since we know family ID */
- ret = mxt_probe_bootloader(data, 0);
+ ret = mxt_probe_bootloader(data);
if (ret)
return ret;
--
2.19.2
^ permalink raw reply related
* [PATCH v1 47/63] Input: Atmel: improve error handling in mxt_update_cfg()
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083724.19341-1-jiada_wang@mentor.com>
From: Deepak Das <deepak_das@mentor.com>
mxt_update_cfg() failed to propagate the error
code from mxt_init_t7_power_cfg() so return the error code.
Signed-off-by: Deepak Das <deepak_das@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 3999d3e31a6a..dec9f2b2c64d 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2173,7 +2173,9 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
dev_info(dev, "Config successfully updated\n");
/* T7 config may have changed */
- mxt_init_t7_power_cfg(data);
+ ret = mxt_init_t7_power_cfg(data);
+ if (ret)
+ dev_warn(dev, "Power Config failed to update\n");
release_mem:
kfree(cfg.mem);
--
2.19.2
^ permalink raw reply related
* [PATCH v1 48/63] input: atmel_mxt_ts: move bootloader probe from mxt_initialize()
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083724.19341-1-jiada_wang@mentor.com>
From: Deepak Das <deepak_das@mentor.com>
Validity of bootloader address is now checked before checking the
bootloader status so mxt_lookup_bootloader_address() was moved
from mxt_probe_bootloader() to mxt_initialize().
Above changes added lot of bootloader mode verification code into
mxt_initialize() which made this function longer and unreadable.
mxt_bootloader_status() moves bootloader mode verification code from
mxt_initialize() to make it cleaner.
Signed-off-by: Deepak Das <deepak_das@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 45 +++++++++++++++---------
1 file changed, 28 insertions(+), 17 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index dec9f2b2c64d..27b908a50b66 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2917,6 +2917,32 @@ static void mxt_config_cb(const struct firmware *cfg, void *ctx)
release_firmware(cfg);
}
+static int mxt_bootloader_status(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ int error;
+
+ error = mxt_lookup_bootloader_address(data, false);
+ if (error) {
+ dev_info(&client->dev,
+ "Bootloader address is not specified\n");
+ return error;
+ }
+ /* Check bootloader state */
+ error = mxt_probe_bootloader(data);
+ if (error) {
+ dev_info(&client->dev, "Trying alternate bootloader address\n");
+ mxt_lookup_bootloader_address(data, true);
+ error = mxt_probe_bootloader(data);
+ if (error) {
+ dev_err(&client->dev,
+ "Chip is not in appmode or bootloader mode\n");
+ return error;
+ }
+ }
+ return 0;
+}
+
static int mxt_initialize(struct mxt_data *data)
{
struct i2c_client *client = data->client;
@@ -2932,24 +2958,9 @@ static int mxt_initialize(struct mxt_data *data)
"info block read failed (%d), so try bootloader method\n",
error);
- error = mxt_lookup_bootloader_address(data, false);
- if (error) {
- dev_info(&client->dev,
- "Bootloader address is not specified\n");
+ error = mxt_bootloader_status(data);
+ if (error)
return error;
- }
- /* Check bootloader state */
- error = mxt_probe_bootloader(data);
- if (error) {
- dev_info(&client->dev, "Trying alternate bootloader address\n");
- mxt_lookup_bootloader_address(data, true);
- error = mxt_probe_bootloader(data);
- if (error) {
- dev_err(&client->dev,
- "Chip is not in appmode or bootloader mode\n");
- return error;
- }
- }
/* OK, we are in bootloader, see if we can recover */
if (++recovery_attempts > 1) {
--
2.19.2
^ permalink raw reply related
* [PATCH v1 49/63] Input: Atmel: Improve error handling in mxt_initialize_input_device()
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083724.19341-1-jiada_wang@mentor.com>
From: Deepak Das <deepak_das@mentor.com>
Currently Driver probe continues with a warning message when it fails to
get the proper multitouch object configurations like TouchScreen resolution.
But Driver probe should fail in case of above scneario because it will not behave
as expected without the proper touchscreen configurations.
This commit modifies mxt_initialize_input_device() to return error when it fails
to get the proper touch screen configurations.
Signed-off-by: Deepak Das <deepak_das@mentor.com>
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 27b908a50b66..b17af89a4711 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2749,15 +2749,19 @@ static int mxt_initialize_input_device(struct mxt_data *data)
case MXT_TOUCH_MULTI_T9:
num_mt_slots = data->T9_reportid_max - data->T9_reportid_min + 1;
error = mxt_read_t9_resolution(data);
- if (error)
- dev_warn(dev, "Failed to initialize T9 resolution\n");
+ if (error) {
+ dev_err(dev, "Failed to initialize T9 resolution\n");
+ return error;
+ }
break;
case MXT_TOUCH_MULTITOUCHSCREEN_T100:
num_mt_slots = data->num_touchids;
error = mxt_read_t100_config(data);
- if (error)
- dev_warn(dev, "Failed to read T100 config\n");
+ if (error) {
+ dev_err(dev, "Failed to read T100 config\n");
+ return error;
+ }
break;
default:
--
2.19.2
^ permalink raw reply related
* [PATCH v1 50/63] Input: Atmel: handle ReportID "0x00" while processing T5 messages
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
From: Deepak Das <deepak_das@mentor.com>
ReportID "0x00" is reserved by Atmel and should not be used by any
Atmel touch controller.
reportID is the first byte retrieved from T5 message payload.
Currently Atmel driver continues to process the T5 messages even if
the reportID "0x00" is returned by Touch Controller.
This commit modifies Atmel touch driver to return -EINVAL if ReportID
"0x00" is received while processing T5 messages.
Signed-off-by: Deepak Das <deepak_das@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index b17af89a4711..2041a82a4551 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -76,6 +76,7 @@
#define MXT_PROCI_TOUCHSEQUENCELOGGER 93
#define MXT_TOUCH_MULTITOUCHSCREEN_T100 100
#define MXT_PROCI_ACTIVESTYLUS_T107 107
+#define MXT_RPTID_RESERVED 0
/* MXT_GEN_MESSAGE_T5 object */
#define MXT_RPTID_NOMSG 0xff
@@ -1385,6 +1386,11 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
u8 report_id = message[0];
bool dump = data->debug_enabled;
+ if (report_id == MXT_RPTID_RESERVED) {
+ dev_err(&data->client->dev,
+ "Received Reserved ReportID 0x00\n");
+ return -EINVAL;
+ }
if (report_id == MXT_RPTID_NOMSG)
return 0;
@@ -1456,6 +1462,8 @@ static int mxt_read_and_process_messages(struct mxt_data *data, u8 count)
ret = mxt_proc_message(data,
data->msg_buf + data->T5_msg_size * i);
+ if (ret < 0)
+ return ret;
if (ret == 1)
num_valid++;
}
--
2.19.2
^ permalink raw reply related
* [PATCH v1 51/63] input: Atmel: limit the max bytes transferred while reading T5 messages
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083757.19449-1-jiada_wang@mentor.com>
From: Deepak Das <deepak_das@mentor.com>
"a008387 Input: atmel_mxt_ts: Limit the max bytes transferred in an i2c
transaction" limited the Max bytes transferred in i2c transaction while
reading T5 message in mxt_process_messages_until_invalid().
mxt_process_messages_t44() reads the T44 message which contains the
pending T5 message count. If the number of pending T5 messages returned
by T44 message is too high then there is a risk of i2c transaction
timeout while reading T5 messages in mxt_process_messages_t44().
To avoid i2c transaction timeout, this commit limits the max bytes
transferred in a single transaction while reading T5 messages in
mxt_process_messages_t44() depending on the property 'atmel,mtu'.
This improvement is created based on the commit "a008387 Input:
atmel_mxt_ts: Limit the max bytes transferred in an i2c
transaction"
Signed-off-by: Deepak Das <deepak_das@mentor.com>
Signed-off-by: Sanjeev Chugh <sanjeev_chugh@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 73 ++++++++++++++----------
1 file changed, 44 insertions(+), 29 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2041a82a4551..47c1e72152de 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1472,11 +1472,32 @@ static int mxt_read_and_process_messages(struct mxt_data *data, u8 count)
return num_valid;
}
+static u8 mxt_max_msg_read_count(struct mxt_data *data, u8 max_T5_msg_count)
+{
+ u8 T5_msg_count_limit = data->mtu / data->T5_msg_size;
+
+ if (!data->mtu)
+ return max_T5_msg_count;
+
+ if (data->mtu < data->T5_msg_size) {
+ WARN(1, "mtu set is lesser than the T5 message size\n");
+ /* Return count of 1, as fallback */
+ return 1;
+ }
+ /*
+ * Return maximum number of T5 messages in single i2c transaction
+ * based on "atmel,mtu" property.
+ */
+ return min(T5_msg_count_limit, max_T5_msg_count);
+}
+
static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
int ret;
- u8 count, num_left;
+ u8 T5_msg_count, total_pending;
+ u8 total_processed = 0;
+ u8 processed_valid = 0;
/* Read T44 and T5 together */
ret = __mxt_read_reg(data->client, data->T44_address,
@@ -1486,18 +1507,19 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
return IRQ_NONE;
}
- count = data->msg_buf[0];
+ T5_msg_count = data->msg_buf[0];
/*
* This condition may be caused by the CHG line being configured in
* Mode 0. It results in unnecessary I2C operations but it is benign.
*/
- if (count == 0)
+ if (!T5_msg_count)
return IRQ_NONE;
- if (count > data->max_reportid) {
- dev_warn(dev, "T44 count %d exceeded max report id\n", count);
- count = data->max_reportid;
+ if (T5_msg_count > data->max_reportid) {
+ dev_warn(dev, "T44 count %d exceeded max report id\n",
+ T5_msg_count);
+ T5_msg_count = data->max_reportid;
}
/* Process first message */
@@ -1507,16 +1529,25 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
return IRQ_NONE;
}
- num_left = count - 1;
+ total_pending = T5_msg_count - 1;
+ if (!total_pending)
+ goto end;
/* Process remaining messages if necessary */
- if (num_left) {
- ret = mxt_read_and_process_messages(data, num_left);
+ T5_msg_count = mxt_max_msg_read_count(data, total_pending);
+
+ do {
+ if ((total_pending - total_processed) < T5_msg_count)
+ T5_msg_count = total_pending - total_processed;
+ ret = mxt_read_and_process_messages(data, T5_msg_count);
if (ret < 0)
goto end;
- else if (ret != num_left)
- dev_warn(dev, "Unexpected invalid message\n");
- }
+ total_processed += T5_msg_count;
+ processed_valid += ret;
+ } while (total_processed < total_pending);
+
+ if (processed_valid != total_pending)
+ dev_warn(dev, "Unexpected invalid message\n");
end:
if (data->update_input) {
@@ -1527,29 +1558,13 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
return IRQ_HANDLED;
}
-static u8 mxt_max_msg_read_count(struct mxt_data *data)
-{
- u8 count_limit = data->mtu / data->T5_msg_size;
-
- if (!data->mtu)
- return data->max_reportid;
-
- if (data->mtu < data->T5_msg_size) {
- WARN(1, "mtu set is lesser than the T5 message size\n");
- /* Return count of 1, as fallback */
- return 1;
- }
-
- return min(count_limit, data->max_reportid);
-}
-
static int mxt_process_messages_until_invalid(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
int count, read;
int tries;
- count = mxt_max_msg_read_count(data);
+ count = mxt_max_msg_read_count(data, data->max_reportid);
tries = (data->max_reportid / count) + 1;
/* Read messages until we force an invalid */
--
2.19.2
^ permalink raw reply related
* [PATCH v1 52/63] Input: Atmel: use T44 object to process T5 messages
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083757.19449-1-jiada_wang@mentor.com>
From: Deepak Das <deepak_das@mentor.com>
T44 object returns the count of valid T5 messages in the buffer. According
to atmel, this count should be the main criteria to read the number of T5
messages.
Following is the statement from atmel confirming the same :-
"For the readout of messages we recommend to stop after the last message
is read out from the buffer. One way to identify the amount of new messages
is to read T44. The other way is to monitor the /CHG line which indicates
independent of mode 0 or mode 1 if there are still data in the buffer.
0xFF indicates that there is no message pending anymore, but it is not
recommended to use this as the main criteria to control the
data transfer."
This commit modifies the logic to readout the T5 messages on the basis
of T44 object.
Signed-off-by: Deepak Das <deepak_das@mentor.com>
Signed-off-by: Sanjeev Chugh <sanjeev_chugh@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 55 +++++++++++++++---------
1 file changed, 35 insertions(+), 20 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 47c1e72152de..5c980e74e6b0 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1491,7 +1491,7 @@ static u8 mxt_max_msg_read_count(struct mxt_data *data, u8 max_T5_msg_count)
return min(T5_msg_count_limit, max_T5_msg_count);
}
-static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
+static int mxt_process_messages_t44(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
int ret;
@@ -1504,7 +1504,7 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
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;
+ return ret;
}
T5_msg_count = data->msg_buf[0];
@@ -1514,7 +1514,7 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
* Mode 0. It results in unnecessary I2C operations but it is benign.
*/
if (!T5_msg_count)
- return IRQ_NONE;
+ return processed_valid;
if (T5_msg_count > data->max_reportid) {
dev_warn(dev, "T44 count %d exceeded max report id\n",
@@ -1526,12 +1526,14 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
ret = mxt_proc_message(data, data->msg_buf + 1);
if (ret < 0) {
dev_warn(dev, "Unexpected invalid message\n");
- return IRQ_NONE;
+ return ret;
}
total_pending = T5_msg_count - 1;
- if (!total_pending)
+ if (!total_pending) {
+ processed_valid = 1;
goto end;
+ }
/* Process remaining messages if necessary */
T5_msg_count = mxt_max_msg_read_count(data, total_pending);
@@ -1555,7 +1557,7 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data)
data->update_input = false;
}
- return IRQ_HANDLED;
+ return processed_valid;
}
static int mxt_process_messages_until_invalid(struct mxt_data *data)
@@ -1585,7 +1587,7 @@ static int mxt_process_messages_until_invalid(struct mxt_data *data)
return -EBUSY;
}
-static irqreturn_t mxt_process_messages(struct mxt_data *data)
+static int mxt_process_messages(struct mxt_data *data)
{
int total_handled, num_handled;
u8 count = data->last_message_count;
@@ -1596,7 +1598,7 @@ static irqreturn_t mxt_process_messages(struct mxt_data *data)
/* include final invalid message */
total_handled = mxt_read_and_process_messages(data, count + 1);
if (total_handled < 0)
- return IRQ_NONE;
+ return total_handled;
/* if there were invalid messages, then we are done */
else if (total_handled <= count)
goto update_count;
@@ -1605,7 +1607,7 @@ static irqreturn_t mxt_process_messages(struct mxt_data *data)
do {
num_handled = mxt_read_and_process_messages(data, 2);
if (num_handled < 0)
- return IRQ_NONE;
+ return num_handled;
total_handled += num_handled;
@@ -1621,12 +1623,13 @@ static irqreturn_t mxt_process_messages(struct mxt_data *data)
data->update_input = false;
}
- return IRQ_HANDLED;
+ return total_handled;
}
static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;
+ int ret;
complete(&data->chg_completion);
@@ -1634,17 +1637,22 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
if (data->flash && &data->flash->work)
cancel_delayed_work_sync(&data->flash->work);
- return IRQ_RETVAL(mxt_check_bootloader(data));
+ ret = mxt_check_bootloader(data);
+ return IRQ_RETVAL(ret);
}
if (!data->object_table)
return IRQ_HANDLED;
- if (data->T44_address) {
- return mxt_process_messages_t44(data);
- } else {
- return mxt_process_messages(data);
- }
+ if (data->T44_address)
+ ret = mxt_process_messages_t44(data);
+ else
+ ret = mxt_process_messages(data);
+
+ if (ret <= 0)
+ return IRQ_NONE;
+ else
+ return IRQ_HANDLED;
}
static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
@@ -1779,8 +1787,11 @@ static int mxt_acquire_irq(struct mxt_data *data)
}
if (data->object_table && data->use_retrigen_workaround) {
- error = mxt_process_messages_until_invalid(data);
- if (error)
+ if (data->T44_address)
+ error = mxt_process_messages_t44(data);
+ else
+ error = mxt_process_messages_until_invalid(data);
+ if (error < 0)
return error;
}
@@ -4116,8 +4127,12 @@ static int mxt_start(struct mxt_data *data)
* Discard any touch messages still in message buffer
* from before chip went to sleep
*/
- ret = mxt_process_messages_until_invalid(data);
- if (ret)
+
+ if (data->T44_address)
+ ret = mxt_process_messages_t44(data);
+ else
+ ret = mxt_process_messages_until_invalid(data);
+ if (ret < 0)
break;
ret = mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
--
2.19.2
^ permalink raw reply related
* [PATCH v1 53/63] Input: atmel_mxt_ts: use gpiod_set_value_cansleep for reset pin
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083757.19449-1-jiada_wang@mentor.com>
From: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
In case of remote display, touch controller will be also remote.
In such cases, the reset pin of the touch controller will be
controlled through bridging ICs like Deserilizer and Serializer.
Therefore accessing the gpio pins require transactions with the
external IC. Using the function gpiod_set_value will print a
warning like below
WARNING: CPU: 0 PID: 576 at drivers/gpio/gpiolib.c:1441 gpiod_set_value+0x34/0x60()
CPU: 0 PID: 576 Comm: modprobe Not tainted 3.14.79-08377-g84ea22f-dirty #4
Backtrace:
[<80011c58>] (dump_backtrace) from [<80011e60>] (show_stack+0x18/0x1c)
[<80011e48>] (show_stack) from [<8052d7ac>] (dump_stack+0x7c/0x9c)
[<8052d730>] (dump_stack) from [<800241bc>] (warn_slowpath_common+0x74/0x9c)
[<80024148>] (warn_slowpath_common) from [<80024288>] (warn_slowpath_null+0x24/0x2c)
[<80024264>] (warn_slowpath_null) from [<8029e070>] (gpiod_set_value+0x34/0x60)
[<8029e03c>] (gpiod_set_value) from [<7f492e98>] (mxt_probe+0x1e0/0x718 [atmel_mxt_ts])
[<7f492cb8>] (mxt_probe [atmel_mxt_ts]) from [<803c4d34>] (i2c_device_probe+0xcc/0xec)
[<803c4c68>] (i2c_device_probe) from [<803252a0>] (driver_probe_device+0xc0/0x200)
Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@mentor.com>
Signed-off-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
Signed-off-by: Sanjeev Chugh <sanjeev_chugh@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 5c980e74e6b0..79fc6561f6ad 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2492,7 +2492,7 @@ static void mxt_regulator_enable(struct mxt_data *data)
if (!data->reg_vdd || !data->reg_avdd)
return;
- gpiod_set_value(data->reset_gpio, 0);
+ gpiod_set_value_cansleep(data->reset_gpio, 0);
error = regulator_enable(data->reg_vdd);
if (error)
@@ -2510,7 +2510,7 @@ static void mxt_regulator_enable(struct mxt_data *data)
* voltage
*/
msleep(MXT_REGULATOR_DELAY);
- gpiod_set_value(data->reset_gpio, 1);
+ gpiod_set_value_cansleep(data->reset_gpio, 1);
msleep(MXT_CHG_DELAY);
retry_wait:
@@ -4501,7 +4501,7 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
disable_irq(data->irq);
} else if (data->reset_gpio) {
msleep(MXT_RESET_GPIO_TIME);
- gpiod_set_value(data->reset_gpio, 1);
+ gpiod_set_value_cansleep(data->reset_gpio, 1);
msleep(MXT_RESET_INVALID_CHG);
} else {
dev_dbg(&client->dev,
--
2.19.2
^ permalink raw reply related
* [PATCH v1 54/63] Input: atmel_mxt_ts: Avoid race condition in freeing of input device
From: Jiada Wang @ 2019-08-16 8:37 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083757.19449-1-jiada_wang@mentor.com>
From: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com>
>From the static analysis of the code it seems that there could be a
race condition leading to crash while freeing input device in
mxt_free_input_device(). The backtrace of crash is as shown below:
Unable to handle kernel NULL pointer dereference at virtual address 0000003c
Internal error: Oops: 17 [#1] PREEMPT SMP ARM
CPU: 1 PID: 229 Comm: load_firmware.s Not tainted 3.14.79-00978-g58395f0ebac4 #1
PC is at kernfs_find_ns+0x14/0xf0
LR is at kernfs_find_and_get_ns+0x34/0x50
Backtrace:
[<801745c0>] (kernfs_find_ns) from [<801746e4>] (kernfs_find_and_get_ns+0x34/0x50)
[<801746b0>] (kernfs_find_and_get_ns) from [<801730c8>] (sysfs_unmerge_group+0x20/0x60)
[<801730a8>] (sysfs_unmerge_group) from [<80328490>] (pm_qos_sysfs_remove_latency+0x18/0x20)
[<80328478>] (pm_qos_sysfs_remove_latency) from [<80329844>] (dev_pm_qos_constraints_destroy+0x20/0x128)
[<80329824>] (dev_pm_qos_constraints_destroy) from [<80328510>] (dpm_sysfs_remove+0x18/0x44)
[<803284f8>] (dpm_sysfs_remove) from [<80320514>] (device_del+0x3c/0x178)
[<803204d8>] (device_del) from [<803b5ae8>] (__input_unregister_device+0x120/0x134)
[<803b59c8>] (__input_unregister_device) from [<803b5b68>] (input_unregister_device+0x54/0x74)
[<803b5b14>] (input_unregister_device) from [<7f1288bc>] (mxt_debug_enable_store+0x1a8/0x2c4 [atmel_mxt_ts])
[<7f12888c>] (mxt_debug_enable_store [atmel_mxt_ts]) from [<7f12b534>] (mxt_update_cfg_store+0xc4/0x154 [atmel_mxt_ts])
[<7f12b470>] (mxt_update_cfg_store [atmel_mxt_ts]) from [<8031f4e8>] (dev_attr_store+0x20/0x2c)
[<8031f4c8>] (dev_attr_store) from [<80172558>] (sysfs_kf_write+0x40/0x4c)
[<80172518>] (sysfs_kf_write) from [<801756fc>] (kernfs_fop_write+0xf8/0x140)
[<80175604>] (kernfs_fop_write) from [<801136e0>] (vfs_write+0xd8/0x16c)
[<80113608>] (vfs_write) from [<80113c34>] (SyS_write+0x50/0x90)
[<80113be4>] (SyS_write) from [<8000e0a0>] (ret_fast_syscall+0x0/0x38)
Note: mxt_free_input_device() is misrepresented as mxt_debug_enable_store()
in the crash backtrace. From the disassembly of the atmel_mxt_ts.ko, address
pointed by (mxt_debug_enable_store+0x1a8/0x2c4 [atmel_mxt_ts]) refers to
mxt_free_input_device()
There is speculation that this race condition may occur while
configuration (firmware) is loading and driver is being unloaded parallely.
The solution is to take a local pointer to data->input_dev with the lock
held and then to set data->input_dev to NULL to prevent any parallel
thread from executing input_unregister_device() for a second time overall
so avoiding the crash. The lock is released and the local pointer is
safely used by input_unregister_device() so this function only runs a
single time overall.
Signed-off-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com>
Signed-off-by: Sanjeev Chugh <sanjeev_chugh@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 79fc6561f6ad..35d92751e49f 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2221,8 +2221,10 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
static void mxt_free_input_device(struct mxt_data *data)
{
if (data->input_dev) {
- input_unregister_device(data->input_dev);
+ struct input_dev *dev = data->input_dev;
+
data->input_dev = NULL;
+ input_unregister_device(dev);
}
}
--
2.19.2
^ permalink raw reply related
* [PATCH v1 55/63] Input: atmel_mxt_ts: Use msecs_to_jiffies() instead of HZ
From: Jiada Wang @ 2019-08-16 8:38 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
From: Dean Jenkins <Dean_Jenkins@mentor.com>
Replace HZ / 10 with msecs_to_jiffies(100) in the
schedule_delayed_work() calls in mxt_fw_work() and
mxt_check_bootloader() because it is cleaner.
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
Signed-off-by: Sanjeev Chugh <sanjeev_chugh@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 35d92751e49f..40263ef79e8e 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -842,7 +842,7 @@ static int mxt_check_bootloader(struct mxt_data *data)
f->previous = state;
/* Poll after 0.1s if no interrupt received */
- schedule_delayed_work(&f->work, HZ / 10);
+ schedule_delayed_work(&f->work, msecs_to_jiffies(100));
return 0;
@@ -3773,7 +3773,7 @@ static int mxt_load_fw(struct device *dev)
goto release_firmware;
/* Poll after 0.1s if no interrupt received */
- schedule_delayed_work(&data->flash->work, HZ / 10);
+ schedule_delayed_work(&data->flash->work, msecs_to_jiffies(100));
/* Wait for flash. */
ret = mxt_wait_for_completion(data, &data->flash->flash_completion,
--
2.19.2
^ permalink raw reply related
* [PATCH v1 56/63] Input: atmel_mxt_ts: Use complete when in_bootloader true
From: Jiada Wang @ 2019-08-16 8:38 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083830.19553-1-jiada_wang@mentor.com>
From: Dean Jenkins <Dean_Jenkins@mentor.com>
In mxt_interrupt(), complete(&data->chg_completion) was
called everytime mxt_interrupt() ran which is unnecessary.
mxt_regulator_enable() sets data->in_bootloader to true and
waits for the completion indication for data->chg_completion
to be set by mxt_interrupt().
mxt_interrupt() already has a test for data->in_bootloader
being true so move complete(&data->chg_completion) inside
that test.
Here is some analysis of some old commits relating to the
usage of complete(&data->chg_completion):
e6c4b6160d2 ("Input: atmel_mxt_ts - rename bl_completion to
chg_completion")
This old commit moved the "complete" statement from inside a
test for data->in_bootloader being true to run everytime
mxt_interrupt() executed. It is unclear why this was done.
This new commit reverses that modification back to the original
implementation.
4c814dd5c6ae ("Input: atmel_mxt_ts - make bootloader interrupt
driven")
This old commit modified mxt_load_fw() to no longer use the
data->chg_completion solution so only mxt_regulator_enable()
uses the data->chg_completion solution.
Therefore, only mxt_regulator_enable() now needs to be
supported by the data->chg_completion solution.
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
Signed-off-by: Sanjeev Chugh <sanjeev_chugh@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 40263ef79e8e..64a1a6815d56 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1631,9 +1631,9 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
struct mxt_data *data = dev_id;
int ret;
- complete(&data->chg_completion);
-
if (data->in_bootloader) {
+ complete(&data->chg_completion);
+
if (data->flash && &data->flash->work)
cancel_delayed_work_sync(&data->flash->work);
--
2.19.2
^ permalink raw reply related
* [PATCH v1 57/63] input: touchscreen: atmel_mxt_ts: Added sysfs entry for touchscreen status
From: Jiada Wang @ 2019-08-16 8:38 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083830.19553-1-jiada_wang@mentor.com>
From: Naveen Chakka <Naveen.Chakka@in.bosch.com>
To know the current communication status of the touch controller during
runtime, sysfs interface is added
sysfs interface: /sys/class/i2c-dev/i2c-*/device/*/touch_dev_stat
Executing the above sysfs interface provides two output values
1)Status of the touch device
value 0 represents device is inactive
value 1 represents device is active
2)Error counter
value represents the number of times device in inactive since last read
Signed-off-by: Naveen Chakka <Naveen.Chakka@in.bosch.com>
Signed-off-by: Sanjeev Chugh <sanjeev_chugh@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 111 +++++++++++++++++++++--
1 file changed, 104 insertions(+), 7 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 64a1a6815d56..234e3031ba42 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -25,6 +25,7 @@
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/gpio/consumer.h>
+#include <linux/timer.h>
#include <asm/unaligned.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
@@ -222,6 +223,7 @@ enum t100_type {
#define MXT_CHG_DELAY 100 /* msec */
#define MXT_POWERON_DELAY 150 /* msec */
#define MXT_BOOTLOADER_WAIT 36E5 /* 1 minute */
+#define MXT_WATCHDOG_TIMEOUT 1000 /* msec */
/* Command to unlock bootloader */
#define MXT_UNLOCK_CMD_MSB 0xaa
@@ -317,6 +319,12 @@ struct mxt_flash {
struct delayed_work work;
};
+struct mxt_statusinfo {
+ bool dev_status;
+ bool intp_triggered;
+ u32 error_count;
+};
+
/* Each client has this additional data */
struct mxt_data {
struct i2c_client *client;
@@ -373,6 +381,9 @@ struct mxt_data {
const char *pcfg_name;
const char *input_name;
struct mxt_flash *flash;
+ struct work_struct watchdog_work;
+ struct timer_list watchdog_timer;
+ struct mxt_statusinfo mxt_status;
/* Cached parameters from object table */
u16 T5_address;
@@ -1626,11 +1637,30 @@ static int mxt_process_messages(struct mxt_data *data)
return total_handled;
}
+static void mxt_start_wd_timer(struct mxt_data *data)
+{
+ mod_timer(&data->watchdog_timer, jiffies +
+ msecs_to_jiffies(MXT_WATCHDOG_TIMEOUT));
+}
+
+static void mxt_stop_wd_timer(struct mxt_data *data)
+{
+ /*
+ * Ensure we wait until the watchdog timer
+ * running on a different CPU finishes
+ */
+ del_timer_sync(&data->watchdog_timer);
+ cancel_work_sync(&data->watchdog_work);
+ del_timer_sync(&data->watchdog_timer);
+}
+
static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;
int ret;
+ data->mxt_status.intp_triggered = true;
+
if (data->in_bootloader) {
complete(&data->chg_completion);
@@ -1638,21 +1668,25 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
cancel_delayed_work_sync(&data->flash->work);
ret = mxt_check_bootloader(data);
- return IRQ_RETVAL(ret);
+ ret = IRQ_RETVAL(ret);
+ goto exit;
}
- if (!data->object_table)
- return IRQ_HANDLED;
+ if (!data->object_table) {
+ ret = IRQ_HANDLED;
+ goto exit;
+ }
if (data->T44_address)
ret = mxt_process_messages_t44(data);
else
ret = mxt_process_messages(data);
- if (ret <= 0)
- return IRQ_NONE;
- else
- return IRQ_HANDLED;
+ ret = (ret <= 0) ? IRQ_NONE : IRQ_HANDLED;
+
+exit:
+ data->mxt_status.intp_triggered = false;
+ return ret;
}
static int mxt_t6_command(struct mxt_data *data, u16 cmd_offset,
@@ -2983,6 +3017,38 @@ static int mxt_bootloader_status(struct mxt_data *data)
return 0;
}
+static void mxt_watchdog_timer(struct timer_list *t)
+{
+ struct mxt_data *data = from_timer(data, t, watchdog_timer);
+
+ dev_dbg(&data->client->dev, "%s: Timer triggered\n", __func__);
+
+ if (!work_pending(&data->watchdog_work)) {
+ if (!data->mxt_status.intp_triggered)
+ schedule_work(&data->watchdog_work);
+ }
+
+ mxt_start_wd_timer(data);
+}
+
+static void mxt_watchdog_work(struct work_struct *work)
+{
+ struct mxt_data *data =
+ container_of(work, struct mxt_data, watchdog_work);
+ u16 info_buf;
+ int ret = 0;
+ u8 size = 2;
+
+ ret = __mxt_read_reg(data->client, 0, size, &info_buf);
+
+ if (ret) {
+ data->mxt_status.error_count++;
+ data->mxt_status.dev_status = false;
+ } else {
+ data->mxt_status.dev_status = true;
+ }
+}
+
static int mxt_initialize(struct mxt_data *data)
{
struct i2c_client *client = data->client;
@@ -4010,6 +4076,22 @@ static const struct attribute_group mxt_fw_attr_group = {
.attrs = mxt_fw_attrs,
};
+static ssize_t mxt_touch_device_status(struct device *dev, struct
+ device_attribute *attr, char *buf)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (data->mxt_status.dev_status)
+ data->mxt_status.error_count = 0;
+
+ ret = snprintf(buf, PAGE_SIZE, "%d %d\n", data->mxt_status.dev_status,
+ data->mxt_status.error_count);
+ /* clear the error counter once it is read */
+ data->mxt_status.error_count = 0;
+ return ret;
+}
+
static DEVICE_ATTR(fw_version, S_IRUGO, mxt_fw_version_show, NULL);
static DEVICE_ATTR(hw_version, S_IRUGO, mxt_hw_version_show, NULL);
static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
@@ -4021,6 +4103,7 @@ static DEVICE_ATTR(debug_v2_enable, S_IWUSR | S_IRUSR, NULL,
mxt_debug_v2_enable_store);
static DEVICE_ATTR(debug_notify, S_IRUGO, mxt_debug_notify_show, NULL);
static DEVICE_ATTR(t25, 0600, mxt_t25_selftest_show, mxt_t25_selftest_store);
+static DEVICE_ATTR(touch_dev_stat, 0444, mxt_touch_device_status, NULL);
static struct attribute *mxt_attrs[] = {
&dev_attr_fw_version.attr,
@@ -4032,6 +4115,7 @@ static struct attribute *mxt_attrs[] = {
&dev_attr_debug_v2_enable.attr,
&dev_attr_debug_notify.attr,
&dev_attr_t25.attr,
+ &dev_attr_touch_dev_stat.attr,
NULL
};
@@ -4518,6 +4602,13 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
return error;
}
+ INIT_WORK(&data->watchdog_work, mxt_watchdog_work);
+
+ /* setup watchdog timer */
+ timer_setup(&data->watchdog_timer, mxt_watchdog_timer, 0);
+
+ mxt_start_wd_timer(data);
+
error = mxt_initialize(data);
if (error)
goto err_free_object;
@@ -4525,8 +4616,11 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
return 0;
err_free_object:
+ cancel_work_sync(&data->watchdog_work);
+ mxt_stop_wd_timer(data);
mxt_free_input_device(data);
mxt_free_object_table(data);
+ del_timer(&data->watchdog_timer);
sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group);
if (data->reset_gpio) {
sysfs_remove_link(&client->dev.kobj, "reset");
@@ -4554,6 +4648,9 @@ static int mxt_remove(struct i2c_client *client)
mxt_free_input_device(data);
mxt_free_object_table(data);
+ cancel_work_sync(&data->watchdog_work);
+ mxt_stop_wd_timer(data);
+
return 0;
}
--
2.19.2
^ permalink raw reply related
* [PATCH v1 58/63] Input: atmel_mxt_ts: Remove sysfs attributes during driver detach
From: Jiada Wang @ 2019-08-16 8:38 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083830.19553-1-jiada_wang@mentor.com>
From: Sanjeev Chugh <Sanjeev_Chugh@mentor.com>
This change prevents a scenario when sysfs attributes for Atmel touch
controller driver are being accessed by userland while touch driver
module unloading has already begun. At present, sysfs attribute files
are created at device probe but they are not removed while driver is
being detached.
This change will prevent calls to generic driver layer when the sysfs
driver attributes files are already deleted. Therefore, kernel will not
attempt to invoke driver routines for showing the sysfs atrributes.
Signed-off-by: Sanjeev Chugh <Sanjeev_Chugh@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 234e3031ba42..431c2c54eab0 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2255,10 +2255,12 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
static void mxt_free_input_device(struct mxt_data *data)
{
if (data->input_dev) {
- struct input_dev *dev = data->input_dev;
+ struct input_dev *input_dev = data->input_dev;
data->input_dev = NULL;
- input_unregister_device(dev);
+ sysfs_remove_group(&input_dev->dev.kobj,
+ &data->gpio_attrs);
+ input_unregister_device(input_dev);
}
}
--
2.19.2
^ permalink raw reply related
* [PATCH v1 59/63] Input: atmel_mxt_ts: Prevent crash due to freeing of input device
From: Jiada Wang @ 2019-08-16 8:38 UTC (permalink / raw)
To: nick, dmitry.torokhov; +Cc: linux-input, linux-kernel, jiada_wang, george_davis
In-Reply-To: <20190816083830.19553-1-jiada_wang@mentor.com>
From: Bhuvanesh Surachari <Bhuvanesh_Surachari@mentor.com>
Move sysfs creation after intializing the input device to
prevent crash due to freeing of input device by function via sysfs.
Signed-off-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com>
Signed-off-by: Sanjeev Chugh <sanjeev_chugh@mentor.com>
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 431c2c54eab0..8e95f46a30d7 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2962,6 +2962,8 @@ static int mxt_initialize_input_device(struct mxt_data *data)
goto err_free_mem;
}
+ data->input_dev = input_dev;
+
if (data->gpio_attrs.attrs) {
error = sysfs_create_group(&input_dev->dev.kobj,
&data->gpio_attrs);
@@ -2972,11 +2974,10 @@ static int mxt_initialize_input_device(struct mxt_data *data)
}
}
- data->input_dev = input_dev;
-
return 0;
err_free_mem:
+ data->input_dev = NULL;
input_free_device(input_dev);
return error;
}
@@ -4597,13 +4598,6 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
msleep(MXT_RESET_TIME);
}
- error = sysfs_create_group(&client->dev.kobj, &mxt_fw_attr_group);
- if (error) {
- dev_err(&client->dev, "Failure %d creating fw sysfs group\n",
- error);
- return error;
- }
-
INIT_WORK(&data->watchdog_work, mxt_watchdog_work);
/* setup watchdog timer */
@@ -4613,11 +4607,18 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
error = mxt_initialize(data);
if (error)
- goto err_free_object;
+ goto err_del_wd_timer;
+
+ error = sysfs_create_group(&client->dev.kobj, &mxt_fw_attr_group);
+ if (error) {
+ dev_err(&client->dev, "Failure %d creating fw sysfs group\n",
+ error);
+ goto err_del_wd_timer;
+ }
return 0;
-err_free_object:
+err_del_wd_timer:
cancel_work_sync(&data->watchdog_work);
mxt_stop_wd_timer(data);
mxt_free_input_device(data);
--
2.19.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox