summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/exc3000.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/exc3000.c')
-rw-r--r--drivers/input/touchscreen/exc3000.c61
1 files changed, 45 insertions, 16 deletions
diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c
index cbe0dd412912..28da7ba55a4b 100644
--- a/drivers/input/touchscreen/exc3000.c
+++ b/drivers/input/touchscreen/exc3000.c
@@ -7,6 +7,7 @@
* minimal implementation based on egalax_ts.c and egalax_i2c.c
*/
+#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -18,9 +19,10 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/regulator/consumer.h>
#include <linux/sizes.h>
#include <linux/timer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define EXC3000_NUM_SLOTS 10
#define EXC3000_SLOTS_PER_FRAME 5
@@ -51,6 +53,7 @@ enum eeti_dev_id {
EETI_EXC3000,
EETI_EXC80H60,
EETI_EXC80H84,
+ EETI_EXC81W32,
};
static struct eeti_dev_info exc3000_info[] = {
@@ -66,6 +69,10 @@ static struct eeti_dev_info exc3000_info[] = {
.name = "EETI EXC80H84 Touch Screen",
.max_xy = SZ_16K - 1,
},
+ [EETI_EXC81W32] = {
+ .name = "EETI EXC81W32 Touch Screen",
+ .max_xy = SZ_16K - 1,
+ },
};
struct exc3000_data {
@@ -98,7 +105,7 @@ static void exc3000_report_slots(struct input_dev *input,
static void exc3000_timer(struct timer_list *t)
{
- struct exc3000_data *data = from_timer(data, t, timer);
+ struct exc3000_data *data = timer_container_of(data, t, timer);
input_mt_sync_frame(data->input);
input_sync(data->input);
@@ -109,6 +116,11 @@ static inline void exc3000_schedule_timer(struct exc3000_data *data)
mod_timer(&data->timer, jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS));
}
+static void exc3000_shutdown_timer(void *timer)
+{
+ timer_shutdown_sync(timer);
+}
+
static int exc3000_read_frame(struct exc3000_data *data, u8 *buf)
{
struct i2c_client *client = data->client;
@@ -162,7 +174,7 @@ static int exc3000_handle_mt_event(struct exc3000_data *data)
/*
* We read full state successfully, no contacts will be "stuck".
*/
- del_timer_sync(&data->timer);
+ timer_delete_sync(&data->timer);
while (total_slots > 0) {
int slots = min(total_slots, EXC3000_SLOTS_PER_FRAME);
@@ -220,6 +232,7 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request,
{
u8 buf[EXC3000_LEN_VENDOR_REQUEST] = { 0x67, 0x00, 0x42, 0x00, 0x03 };
int ret;
+ unsigned long time_left;
mutex_lock(&data->query_lock);
@@ -233,9 +246,9 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request,
goto out_unlock;
if (response) {
- ret = wait_for_completion_timeout(&data->wait_event,
- timeout * HZ);
- if (ret <= 0) {
+ time_left = wait_for_completion_timeout(&data->wait_event,
+ timeout * HZ);
+ if (time_left == 0) {
ret = -ETIMEDOUT;
goto out_unlock;
}
@@ -317,16 +330,13 @@ static ssize_t type_show(struct device *dev,
}
static DEVICE_ATTR_RO(type);
-static struct attribute *sysfs_attrs[] = {
+static struct attribute *exc3000_attrs[] = {
&dev_attr_fw_version.attr,
&dev_attr_model.attr,
&dev_attr_type.attr,
NULL
};
-
-static struct attribute_group exc3000_attribute_group = {
- .attrs = sysfs_attrs
-};
+ATTRIBUTE_GROUPS(exc3000);
static int exc3000_probe(struct i2c_client *client)
{
@@ -354,6 +364,12 @@ static int exc3000_probe(struct i2c_client *client)
if (IS_ERR(data->reset))
return PTR_ERR(data->reset);
+ /* For proper reset sequence, enable power while reset asserted */
+ error = devm_regulator_get_enable(&client->dev, "vdd");
+ if (error && error != -ENODEV)
+ return dev_err_probe(&client->dev, error,
+ "failed to request vdd regulator\n");
+
if (data->reset) {
msleep(EXC3000_RESET_MS);
gpiod_set_value_cansleep(data->reset, 0);
@@ -385,6 +401,11 @@ static int exc3000_probe(struct i2c_client *client)
if (error)
return error;
+ error = devm_add_action_or_reset(&client->dev, exc3000_shutdown_timer,
+ &data->timer);
+ if (error)
+ return error;
+
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, exc3000_interrupt, IRQF_ONESHOT,
client->name, data);
@@ -418,10 +439,6 @@ static int exc3000_probe(struct i2c_client *client)
i2c_set_clientdata(client, data);
- error = devm_device_add_group(&client->dev, &exc3000_attribute_group);
- if (error)
- return error;
-
return 0;
}
@@ -429,6 +446,7 @@ static const struct i2c_device_id exc3000_id[] = {
{ "exc3000", EETI_EXC3000 },
{ "exc80h60", EETI_EXC80H60 },
{ "exc80h84", EETI_EXC80H84 },
+ { "exc81w32", EETI_EXC81W32 },
{ }
};
MODULE_DEVICE_TABLE(i2c, exc3000_id);
@@ -438,18 +456,29 @@ static const struct of_device_id exc3000_of_match[] = {
{ .compatible = "eeti,exc3000", .data = &exc3000_info[EETI_EXC3000] },
{ .compatible = "eeti,exc80h60", .data = &exc3000_info[EETI_EXC80H60] },
{ .compatible = "eeti,exc80h84", .data = &exc3000_info[EETI_EXC80H84] },
+ { .compatible = "eeti,exc81w32", .data = &exc3000_info[EETI_EXC81W32] },
{ }
};
MODULE_DEVICE_TABLE(of, exc3000_of_match);
#endif
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id exc3000_acpi_match[] = {
+ { "EGA00001", .driver_data = (kernel_ulong_t)&exc3000_info[EETI_EXC80H60] },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, exc3000_acpi_match);
+#endif
+
static struct i2c_driver exc3000_driver = {
.driver = {
.name = "exc3000",
+ .dev_groups = exc3000_groups,
.of_match_table = of_match_ptr(exc3000_of_match),
+ .acpi_match_table = ACPI_PTR(exc3000_acpi_match),
},
.id_table = exc3000_id,
- .probe_new = exc3000_probe,
+ .probe = exc3000_probe,
};
module_i2c_driver(exc3000_driver);