summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/atmel_mxt_ts.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/atmel_mxt_ts.c')
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c408
1 files changed, 317 insertions, 91 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 5c63d25ce84e..dd0544cc1bc1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Atmel maXTouch Touchscreen driver
*
@@ -7,12 +8,6 @@
* Copyright (C) 2016 Zodiac Inflight Innovations
*
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
*/
#include <linux/acpi.h>
@@ -24,16 +19,20 @@
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
+#include <dt-bindings/input/atmel-maxtouch.h>
/* Firmware files */
#define MXT_FW_NAME "maxtouch.fw"
@@ -57,6 +56,7 @@
#define MXT_TOUCH_KEYARRAY_T15 15
#define MXT_TOUCH_PROXIMITY_T23 23
#define MXT_TOUCH_PROXKEY_T52 52
+#define MXT_TOUCH_PTC_KEYS_T97 97
#define MXT_PROCI_GRIPFACE_T20 20
#define MXT_PROCG_NOISE_T22 22
#define MXT_PROCI_ONETOUCH_T24 24
@@ -134,6 +134,7 @@ struct t9_range {
/* MXT_SPT_COMMSCONFIG_T18 */
#define MXT_COMMS_CTRL 0
#define MXT_COMMS_CMD 1
+#define MXT_COMMS_RETRIGEN BIT(6)
/* MXT_DEBUG_DIAGNOSTIC_T37 */
#define MXT_DIAGNOSTIC_PAGEUP 0x01
@@ -201,6 +202,7 @@ enum t100_type {
#define MXT_CRC_TIMEOUT 1000 /* msec */
#define MXT_FW_RESET_TIME 3000 /* msec */
#define MXT_FW_CHG_TIMEOUT 300 /* msec */
+#define MXT_WAKEUP_TIME 25 /* msec */
/* Command to unlock bootloader */
#define MXT_UNLOCK_CMD_MSB 0xaa
@@ -261,16 +263,6 @@ enum v4l_dbg_inputs {
MXT_V4L_INPUT_MAX,
};
-static const struct v4l2_file_operations mxt_video_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = vb2_fop_release,
- .unlocked_ioctl = video_ioctl2,
- .read = vb2_fop_read,
- .mmap = vb2_fop_mmap,
- .poll = vb2_fop_poll,
-};
-
enum mxt_suspend_mode {
MXT_SUSPEND_DEEP_SLEEP = 0,
MXT_SUSPEND_T9_CTRL = 1,
@@ -322,7 +314,10 @@ struct mxt_data {
u8 multitouch;
struct t7_config t7_cfg;
struct mxt_dbg dbg;
+ struct regulator_bulk_data regulators[2];
struct gpio_desc *reset_gpio;
+ struct gpio_desc *wake_gpio;
+ bool use_retrigen_workaround;
/* Cached parameters from object table */
u16 T5_address;
@@ -333,8 +328,13 @@ struct mxt_data {
u16 T71_address;
u8 T9_reportid_min;
u8 T9_reportid_max;
+ u8 T15_reportid_min;
+ u8 T15_reportid_max;
+ u16 T18_address;
u8 T19_reportid;
u16 T44_address;
+ u8 T97_reportid_min;
+ u8 T97_reportid_max;
u8 T100_reportid_min;
u8 T100_reportid_max;
@@ -350,7 +350,14 @@ struct mxt_data {
u32 *t19_keymap;
unsigned int t19_num_keys;
+ u32 *t15_keymap;
+ unsigned int t15_num_keys;
+
enum mxt_suspend_mode suspend_mode;
+
+ u32 wakeup_method;
+
+ struct touchscreen_properties prop;
};
struct mxt_vb2_buffer {
@@ -379,6 +386,7 @@ static bool mxt_object_readable(unsigned int type)
case MXT_TOUCH_KEYARRAY_T15:
case MXT_TOUCH_PROXIMITY_T23:
case MXT_TOUCH_PROXKEY_T52:
+ case MXT_TOUCH_PTC_KEYS_T97:
case MXT_TOUCH_MULTITOUCHSCREEN_T100:
case MXT_PROCI_GRIPFACE_T20:
case MXT_PROCG_NOISE_T22:
@@ -488,7 +496,7 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
bootloader = appmode - 0x24;
break;
}
- /* Fall through - for normal case */
+ fallthrough; /* for normal case */
case 0x4c:
case 0x4d:
case 0x5a:
@@ -617,7 +625,6 @@ recheck:
static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
{
- int ret;
u8 buf[2];
if (unlock) {
@@ -628,17 +635,45 @@ static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
buf[1] = 0x01;
}
- ret = mxt_bootloader_write(data, buf, 2);
- if (ret)
- return ret;
+ return mxt_bootloader_write(data, buf, sizeof(buf));
+}
- return 0;
+static bool mxt_wakeup_toggle(struct i2c_client *client,
+ bool wake_up, bool in_i2c)
+{
+ struct mxt_data *data = i2c_get_clientdata(client);
+
+ switch (data->wakeup_method) {
+ case ATMEL_MXT_WAKEUP_I2C_SCL:
+ if (!in_i2c)
+ return false;
+ break;
+
+ case ATMEL_MXT_WAKEUP_GPIO:
+ if (in_i2c)
+ return false;
+
+ gpiod_set_value(data->wake_gpio, wake_up);
+ break;
+
+ default:
+ return false;
+ }
+
+ if (wake_up) {
+ dev_dbg(&client->dev, "waking up controller\n");
+
+ msleep(MXT_WAKEUP_TIME);
+ }
+
+ return true;
}
static int __mxt_read_reg(struct i2c_client *client,
u16 reg, u16 len, void *val)
{
struct i2c_msg xfer[2];
+ bool retried = false;
u8 buf[2];
int ret;
@@ -657,9 +692,13 @@ static int __mxt_read_reg(struct i2c_client *client,
xfer[1].len = len;
xfer[1].buf = val;
+retry:
ret = i2c_transfer(client->adapter, xfer, 2);
if (ret == 2) {
ret = 0;
+ } else if (!retried && mxt_wakeup_toggle(client, true, true)) {
+ retried = true;
+ goto retry;
} else {
if (ret >= 0)
ret = -EIO;
@@ -673,6 +712,7 @@ static int __mxt_read_reg(struct i2c_client *client,
static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
const void *val)
{
+ bool retried = false;
u8 *buf;
size_t count;
int ret;
@@ -686,9 +726,13 @@ static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
buf[1] = (reg >> 8) & 0xff;
memcpy(&buf[2], val, len);
+retry:
ret = i2c_master_send(client, buf, count);
if (ret == count) {
ret = 0;
+ } else if (!retried && mxt_wakeup_toggle(client, true, true)) {
+ retried = true;
+ goto retry;
} else {
if (ret >= 0)
ret = -EIO;
@@ -837,8 +881,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
* have happened.
*/
if (status & MXT_T9_RELEASE) {
- input_mt_report_slot_state(input_dev,
- MT_TOOL_FINGER, 0);
+ input_mt_report_slot_inactive(input_dev);
mxt_input_sync(data);
}
@@ -848,18 +891,35 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
/* Touch active */
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
- input_report_abs(input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ touchscreen_report_pos(input_dev, &data->prop, x, y, true);
input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
} else {
/* Touch no longer active, close out slot */
- input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+ input_mt_report_slot_inactive(input_dev);
}
data->update_input = true;
}
+static void mxt_proc_t15_messages(struct mxt_data *data, u8 *message)
+{
+ struct input_dev *input_dev = data->input_dev;
+ unsigned long keystates = get_unaligned_le32(&message[2]);
+ int key;
+
+ for (key = 0; key < data->t15_num_keys; key++)
+ input_report_key(input_dev, data->t15_keymap[key],
+ keystates & BIT(key));
+
+ data->update_input = true;
+}
+
+static void mxt_proc_t97_messages(struct mxt_data *data, u8 *message)
+{
+ mxt_proc_t15_messages(data, message);
+}
+
static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
{
struct device *dev = &data->client->dev;
@@ -952,8 +1012,7 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
id, type, x, y, major, pressure, orientation);
input_mt_report_slot_state(input_dev, tool, 1);
- input_report_abs(input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ touchscreen_report_pos(input_dev, &data->prop, x, y, true);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major);
input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
input_report_abs(input_dev, ABS_MT_DISTANCE, distance);
@@ -962,7 +1021,7 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
dev_dbg(dev, "[%u] release\n", id);
/* close out slot */
- input_mt_report_slot_state(input_dev, 0, 0);
+ input_mt_report_slot_inactive(input_dev);
}
data->update_input = true;
@@ -986,6 +1045,12 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
} else if (report_id >= data->T9_reportid_min &&
report_id <= data->T9_reportid_max) {
mxt_proc_t9_message(data, message);
+ } else if (report_id >= data->T15_reportid_min &&
+ report_id <= data->T15_reportid_max) {
+ mxt_proc_t15_messages(data, message);
+ } else if (report_id >= data->T97_reportid_min &&
+ report_id <= data->T97_reportid_max) {
+ mxt_proc_t97_messages(data, message);
} else if (report_id >= data->T100_reportid_min &&
report_id <= data->T100_reportid_max) {
mxt_proc_t100_message(data, message);
@@ -1206,9 +1271,11 @@ static int mxt_acquire_irq(struct mxt_data *data)
enable_irq(data->irq);
- error = mxt_process_messages_until_invalid(data);
- if (error)
- return error;
+ if (data->use_retrigen_workaround) {
+ error = mxt_process_messages_until_invalid(data);
+ if (error)
+ return error;
+ }
return 0;
}
@@ -1298,6 +1365,38 @@ static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
return crc;
}
+static int mxt_check_retrigen(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ int error;
+ int val;
+ struct irq_data *irqd;
+
+ data->use_retrigen_workaround = false;
+
+ irqd = irq_get_irq_data(data->irq);
+ if (!irqd)
+ return -EINVAL;
+
+ if (irqd_is_level_type(irqd))
+ return 0;
+
+ if (data->T18_address) {
+ error = __mxt_read_reg(client,
+ data->T18_address + MXT_COMMS_CTRL,
+ 1, &val);
+ if (error)
+ return error;
+
+ if (val & MXT_COMMS_RETRIGEN)
+ return 0;
+ }
+
+ dev_warn(&client->dev, "Enabling RETRIGEN workaround\n");
+ data->use_retrigen_workaround = true;
+ return 0;
+}
+
static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg)
{
struct device *dev = &data->client->dev;
@@ -1526,7 +1625,8 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
} else if (config_crc == data->config_crc) {
dev_dbg(dev, "Config CRC 0x%06X: OK\n",
data->config_crc);
- return 0;
+ 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);
@@ -1576,6 +1676,10 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
+ ret = mxt_check_retrigen(data);
+ if (ret)
+ goto release_mem;
+
ret = mxt_soft_reset(data);
if (ret)
goto release_mem;
@@ -1619,8 +1723,13 @@ static void mxt_free_object_table(struct mxt_data *data)
data->T71_address = 0;
data->T9_reportid_min = 0;
data->T9_reportid_max = 0;
+ data->T15_reportid_min = 0;
+ data->T15_reportid_max = 0;
+ data->T18_address = 0;
data->T19_reportid = 0;
data->T44_address = 0;
+ data->T97_reportid_min = 0;
+ data->T97_reportid_max = 0;
data->T100_reportid_min = 0;
data->T100_reportid_max = 0;
data->max_reportid = 0;
@@ -1693,12 +1802,23 @@ static int mxt_parse_object_table(struct mxt_data *data,
object->num_report_ids - 1;
data->num_touchids = object->num_report_ids;
break;
+ case MXT_TOUCH_KEYARRAY_T15:
+ data->T15_reportid_min = min_id;
+ data->T15_reportid_max = max_id;
+ break;
+ case MXT_SPT_COMMSCONFIG_T18:
+ data->T18_address = object->start_address;
+ break;
case MXT_SPT_MESSAGECOUNT_T44:
data->T44_address = object->start_address;
break;
case MXT_SPT_GPIOPWM_T19:
data->T19_reportid = min_id;
break;
+ case MXT_TOUCH_PTC_KEYS_T97:
+ data->T97_reportid_min = min_id;
+ data->T97_reportid_max = max_id;
+ break;
case MXT_TOUCH_MULTITOUCHSCREEN_T100:
data->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100;
data->T100_reportid_min = min_id;
@@ -1808,7 +1928,7 @@ static int mxt_read_info_block(struct mxt_data *data)
if (error) {
dev_err(&client->dev, "Error %d parsing object table\n", error);
mxt_free_object_table(data);
- goto err_free_mem;
+ return error;
}
data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START);
@@ -1976,6 +2096,7 @@ static int mxt_initialize_input_device(struct mxt_data *data)
int error;
unsigned int num_mt_slots;
unsigned int mt_flags = 0;
+ int i;
switch (data->multitouch) {
case MXT_TOUCH_MULTI_T9:
@@ -2021,6 +2142,10 @@ static int mxt_initialize_input_device(struct mxt_data *data)
input_dev->open = mxt_input_open;
input_dev->close = mxt_input_close;
+ input_dev->keycode = data->t15_keymap;
+ input_dev->keycodemax = data->t15_num_keys;
+ input_dev->keycodesize = sizeof(data->t15_keymap[0]);
+
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
/* For single touch */
@@ -2088,6 +2213,15 @@ static int mxt_initialize_input_device(struct mxt_data *data)
0, 255, 0, 0);
}
+ touchscreen_parse_properties(input_dev, true, &data->prop);
+
+ /* For T15 and T97 Key Array */
+ if (data->T15_reportid_min || data->T97_reportid_min) {
+ for (i = 0; i < data->t15_num_keys; i++)
+ input_set_capability(input_dev,
+ EV_KEY, data->t15_keymap[i]);
+ }
+
input_set_drvdata(input_dev, data);
error = input_register_device(input_dev);
@@ -2152,6 +2286,10 @@ static int mxt_initialize(struct mxt_data *data)
msleep(MXT_FW_RESET_TIME);
}
+ error = mxt_check_retrigen(data);
+ if (error)
+ return error;
+
error = mxt_acquire_irq(data);
if (error)
return error;
@@ -2223,6 +2361,16 @@ recheck:
}
#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT_T37
+static const struct v4l2_file_operations mxt_video_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
+};
+
static u16 mxt_get_debug_value(struct mxt_data *data, unsigned int x,
unsigned int y)
{
@@ -2390,8 +2538,6 @@ fault:
static const struct vb2_ops mxt_queue_ops = {
.queue_setup = mxt_queue_setup,
.buf_queue = mxt_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct vb2_queue mxt_queue = {
@@ -2401,7 +2547,7 @@ static const struct vb2_queue mxt_queue = {
.ops = &mxt_queue_ops,
.mem_ops = &vb2_vmalloc_memops,
.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
- .min_buffers_needed = 1,
+ .min_queued_buffers = 1,
};
static int mxt_vidioc_querycap(struct file *file, void *priv,
@@ -2409,8 +2555,8 @@ static int mxt_vidioc_querycap(struct file *file, void *priv,
{
struct mxt_data *data = video_drvdata(file);
- strlcpy(cap->driver, "atmel_mxt_ts", sizeof(cap->driver));
- strlcpy(cap->card, "atmel_mxt_ts touch", sizeof(cap->card));
+ strscpy(cap->driver, "atmel_mxt_ts", sizeof(cap->driver));
+ strscpy(cap->card, "atmel_mxt_ts touch", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"I2C:%s", dev_name(&data->client->dev));
return 0;
@@ -2426,11 +2572,11 @@ static int mxt_vidioc_enum_input(struct file *file, void *priv,
switch (i->index) {
case MXT_V4L_INPUT_REFS:
- strlcpy(i->name, "Mutual Capacitance References",
+ strscpy(i->name, "Mutual Capacitance References",
sizeof(i->name));
break;
case MXT_V4L_INPUT_DELTAS:
- strlcpy(i->name, "Mutual Capacitance Deltas", sizeof(i->name));
+ strscpy(i->name, "Mutual Capacitance Deltas", sizeof(i->name));
break;
}
@@ -2673,8 +2819,8 @@ static ssize_t mxt_fw_version_show(struct device *dev,
{
struct mxt_data *data = dev_get_drvdata(dev);
struct mxt_info *info = data->info;
- return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n",
- info->version >> 4, info->version & 0xf, info->build);
+ return sysfs_emit(buf, "%u.%u.%02X\n",
+ info->version >> 4, info->version & 0xf, info->build);
}
/* Hardware Version is returned as FamilyID.VariantID */
@@ -2683,8 +2829,7 @@ static ssize_t mxt_hw_version_show(struct device *dev,
{
struct mxt_data *data = dev_get_drvdata(dev);
struct mxt_info *info = data->info;
- return scnprintf(buf, PAGE_SIZE, "%u.%u\n",
- info->family_id, info->variant_id);
+ return sysfs_emit(buf, "%u.%u\n", info->family_id, info->variant_id);
}
static ssize_t mxt_show_instance(char *buf, int count,
@@ -2694,19 +2839,18 @@ static ssize_t mxt_show_instance(char *buf, int count,
int i;
if (mxt_obj_instances(object) > 1)
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Instance %u\n", instance);
+ count += sysfs_emit_at(buf, count, "Instance %u\n", instance);
for (i = 0; i < mxt_obj_size(object); i++)
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "\t[%2u]: %02x (%d)\n", i, val[i], val[i]);
- count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
+ count += sysfs_emit_at(buf, count, "\t[%2u]: %02x (%d)\n",
+ i, val[i], val[i]);
+ count += sysfs_emit_at(buf, count, "\n");
return count;
}
static ssize_t mxt_object_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
struct mxt_data *data = dev_get_drvdata(dev);
struct mxt_object *object;
@@ -2727,8 +2871,7 @@ static ssize_t mxt_object_show(struct device *dev,
if (!mxt_object_readable(object->type))
continue;
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "T%u:\n", object->type);
+ count += sysfs_emit_at(buf, count, "T%u:\n", object->type);
for (j = 0; j < mxt_obj_instances(object); j++) {
u16 size = mxt_obj_size(object);
@@ -2927,12 +3070,12 @@ static struct attribute *mxt_attrs[] = {
NULL
};
-static const struct attribute_group mxt_attr_group = {
- .attrs = mxt_attrs,
-};
+ATTRIBUTE_GROUPS(mxt);
static void mxt_start(struct mxt_data *data)
{
+ mxt_wakeup_toggle(data->client, true, false);
+
switch (data->suspend_mode) {
case MXT_SUSPEND_T9_CTRL:
mxt_soft_reset(data);
@@ -2967,6 +3110,8 @@ static void mxt_stop(struct mxt_data *data)
mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
break;
}
+
+ mxt_wakeup_toggle(data->client, false, false);
}
static int mxt_input_open(struct input_dev *dev)
@@ -2988,14 +3133,15 @@ static void mxt_input_close(struct input_dev *dev)
static int mxt_parse_device_properties(struct mxt_data *data)
{
static const char keymap_property[] = "linux,gpio-keymap";
+ static const char buttons_property[] = "linux,keycodes";
struct device *dev = &data->client->dev;
u32 *keymap;
+ u32 *buttonmap;
int n_keys;
int error;
if (device_property_present(dev, keymap_property)) {
- n_keys = device_property_read_u32_array(dev, keymap_property,
- NULL, 0);
+ n_keys = device_property_count_u32(dev, keymap_property);
if (n_keys <= 0) {
error = n_keys < 0 ? n_keys : -EINVAL;
dev_err(dev, "invalid/malformed '%s' property: %d\n",
@@ -3020,6 +3166,32 @@ 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_count_u32(dev, buttons_property);
+ 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;
+ }
+
return 0;
}
@@ -3038,7 +3210,7 @@ static const struct dmi_system_id chromebook_T9_suspend_dmi[] = {
{ }
};
-static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int mxt_probe(struct i2c_client *client)
{
struct mxt_data *data;
int error;
@@ -3090,62 +3262,111 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (error)
return error;
+ /*
+ * VDDA is the analog voltage supply 2.57..3.47 V
+ * VDD is the digital voltage supply 1.71..3.47 V
+ */
+ data->regulators[0].supply = "vdda";
+ data->regulators[1].supply = "vdd";
+ error = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (error) {
+ if (error != -EPROBE_DEFER)
+ dev_err(&client->dev, "Failed to get regulators %d\n",
+ error);
+ return error;
+ }
+
+ /* Request the RESET line as asserted so we go into reset */
data->reset_gpio = devm_gpiod_get_optional(&client->dev,
- "reset", GPIOD_OUT_LOW);
+ "reset", GPIOD_OUT_HIGH);
if (IS_ERR(data->reset_gpio)) {
error = PTR_ERR(data->reset_gpio);
dev_err(&client->dev, "Failed to get reset gpio: %d\n", error);
return error;
}
+ /* Request the WAKE line as asserted so we go out of sleep */
+ data->wake_gpio = devm_gpiod_get_optional(&client->dev,
+ "wake", GPIOD_OUT_HIGH);
+ if (IS_ERR(data->wake_gpio)) {
+ error = PTR_ERR(data->wake_gpio);
+ dev_err(&client->dev, "Failed to get wake gpio: %d\n", error);
+ return error;
+ }
+
error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, mxt_interrupt, IRQF_ONESHOT,
+ NULL, mxt_interrupt,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
client->name, data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
return error;
}
- disable_irq(client->irq);
+ error = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
+ data->regulators);
+ if (error) {
+ dev_err(&client->dev, "failed to enable regulators: %d\n",
+ error);
+ return error;
+ }
+ /*
+ * The device takes 40ms to come up after power-on according
+ * to the mXT224 datasheet, page 13.
+ */
+ msleep(MXT_BACKUP_TIME);
if (data->reset_gpio) {
+ /* Wait a while and then de-assert the RESET GPIO line */
msleep(MXT_RESET_GPIO_TIME);
- gpiod_set_value(data->reset_gpio, 1);
+ gpiod_set_value_cansleep(data->reset_gpio, 0);
msleep(MXT_RESET_INVALID_CHG);
}
+ /*
+ * Controllers like mXT1386 have a dedicated WAKE line that could be
+ * connected to a GPIO or to I2C SCL pin, or permanently asserted low.
+ *
+ * This WAKE line is used for waking controller from a deep-sleep and
+ * it needs to be asserted low for 25 milliseconds before I2C transfers
+ * could be accepted by controller if it was in a deep-sleep mode.
+ * Controller will go into sleep automatically after 2 seconds of
+ * inactivity if WAKE line is deasserted and deep sleep is activated.
+ *
+ * If WAKE line is connected to I2C SCL pin, then the first I2C transfer
+ * will get an instant NAK and transfer needs to be retried after 25ms.
+ *
+ * If WAKE line is connected to a GPIO line, the line must be asserted
+ * 25ms before the host attempts to communicate with the controller.
+ */
+ device_property_read_u32(&client->dev, "atmel,wakeup-method",
+ &data->wakeup_method);
+
error = mxt_initialize(data);
if (error)
- return error;
-
- error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
- if (error) {
- dev_err(&client->dev, "Failure %d creating sysfs group\n",
- error);
- goto err_free_object;
- }
+ goto err_disable_regulators;
return 0;
-err_free_object:
- mxt_free_input_device(data);
- mxt_free_object_table(data);
+err_disable_regulators:
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators),
+ data->regulators);
return error;
}
-static int mxt_remove(struct i2c_client *client)
+static void mxt_remove(struct i2c_client *client)
{
struct mxt_data *data = i2c_get_clientdata(client);
disable_irq(data->irq);
- sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
mxt_free_input_device(data);
mxt_free_object_table(data);
-
- return 0;
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators),
+ data->regulators);
}
-static int __maybe_unused mxt_suspend(struct device *dev)
+static int mxt_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
@@ -3156,15 +3377,17 @@ static int __maybe_unused mxt_suspend(struct device *dev)
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
mxt_stop(data);
mutex_unlock(&input_dev->mutex);
+ disable_irq(data->irq);
+
return 0;
}
-static int __maybe_unused mxt_resume(struct device *dev)
+static int mxt_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
@@ -3173,9 +3396,11 @@ static int __maybe_unused mxt_resume(struct device *dev)
if (!input_dev)
return 0;
+ enable_irq(data->irq);
+
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ if (input_device_enabled(input_dev))
mxt_start(data);
mutex_unlock(&input_dev->mutex);
@@ -3183,7 +3408,7 @@ static int __maybe_unused mxt_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
static const struct of_device_id mxt_of_match[] = {
{ .compatible = "atmel,maxtouch", },
@@ -3206,11 +3431,11 @@ MODULE_DEVICE_TABLE(acpi, mxt_acpi_id);
#endif
static const struct i2c_device_id mxt_id[] = {
- { "qt602240_ts", 0 },
- { "atmel_mxt_ts", 0 },
- { "atmel_mxt_tp", 0 },
- { "maxtouch", 0 },
- { "mXT224", 0 },
+ { "qt602240_ts" },
+ { "atmel_mxt_ts" },
+ { "atmel_mxt_tp" },
+ { "maxtouch" },
+ { "mXT224" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mxt_id);
@@ -3218,9 +3443,10 @@ MODULE_DEVICE_TABLE(i2c, mxt_id);
static struct i2c_driver mxt_driver = {
.driver = {
.name = "atmel_mxt_ts",
+ .dev_groups = mxt_groups,
.of_match_table = mxt_of_match,
.acpi_match_table = ACPI_PTR(mxt_acpi_id),
- .pm = &mxt_pm_ops,
+ .pm = pm_sleep_ptr(&mxt_pm_ops),
},
.probe = mxt_probe,
.remove = mxt_remove,