summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvan Wilson <evan@oliodevices.com>2015-07-25 14:25:11 -0700
committerEvan Wilson <evan@oliodevices.com>2015-07-25 14:25:11 -0700
commitbb39f055aa4ca296019f355633060974c85928d9 (patch)
treec77f8be215f4affb95aadb27d3f6b2721f7c2e49
parenta6eec3c603b23f28e62e0a12adb61b7b290731d4 (diff)
parentc497cf80cda116bc2c2f478b96f21a917e5ca464 (diff)
downloadolio-linux-3.10-bb39f055aa4ca296019f355633060974c85928d9.tar.xz
olio-linux-3.10-bb39f055aa4ca296019f355633060974c85928d9.zip
Merge tag 'maxtouch-v3.10-20150501' into android-3.10-bringup
atmel_mxt_ts driver for Linux kernel v3.10
-rw-r--r--Documentation/devicetree/bindings/input/atmel,maxtouch.txt27
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c770
-rw-r--r--include/dt-bindings/input/atmel_mxt_ts.h22
-rw-r--r--include/linux/platform_data/atmel_mxt_ts.h (renamed from include/linux/i2c/atmel_mxt_ts.h)8
4 files changed, 543 insertions, 284 deletions
diff --git a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt
index 6319f07bfbc..e879f6d1d2c 100644
--- a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt
+++ b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt
@@ -6,15 +6,34 @@ Required properties:
- reg: The I2C address of the device
-- interrupts: The sink for the touch controller CHG/IRQ output
+- interrupts: The sink for the touchpad's IRQ output
See ../interrupt-controller/interrupts.txt
-Optional properties for maXTouch device:
+Optional properties for main touchpad device:
-- linux,gpio-keymap: An array of up to 4 entries indicating the Linux
- keycode generated by each GPIO. Linux keycodes are defined in
+- linux,gpio-keymap: When enabled, the SPT_GPIOPWN_T19 object sends messages
+ on GPIO bit changes. An array of up to 8 entries can be provided
+ indicating the Linux keycode mapped to each bit of the status byte,
+ starting at the LSB. Linux keycodes are defined in
<dt-bindings/input/input.h>.
+ Note: the numbering of the GPIOs and the bit they start at varies between
+ maXTouch devices. You must either refer to the documentation, or
+ experiment to determine which bit corresponds to which input. Use
+ KEY_RESERVED for unused padding values.
+
+- atmel,suspend-mode: Select method used to suspend:
+ MXT_SUSPEND_DEEP_SLEEP - use T7 to suspend the device into deep sleep
+ MXT_SUSPEND_TOUCH_CTRL - use T9.CTRL to turn off touch processing
+ Definitions are in <dt-bindings/input/atmel_mxt_ts.h>.
+
+- atmel,reset-gpio: Configure RESET GPIO. Required for regulator support.
+
+- atmel,cfg_name: Provide name of configuration file in OBP_RAW format. This
+ will be downloaded from the firmware loader on probe to the device.
+
+- atmel,input_name: Override name of input device from the default.
+
Example:
touch@4b {
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c4249f8b5ba..7298926a75c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -20,7 +20,7 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
-#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/platform_data/atmel_mxt_ts.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
+#include <linux/workqueue.h>
#ifdef CONFIG_OF
#include <linux/of_gpio.h>
@@ -71,7 +72,9 @@
#define MXT_SPT_MESSAGECOUNT_T44 44
#define MXT_SPT_CTECONFIG_T46 46
#define MXT_PROCI_ACTIVE_STYLUS_T63 63
+#define MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71 71
#define MXT_TOUCH_MULTITOUCHSCREEN_T100 100
+#define MXT_PROCI_ACTIVESTYLUS_T107 107
/* MXT_GEN_MESSAGE_T5 object */
#define MXT_RPTID_NOMSG 0xff
@@ -101,6 +104,7 @@ struct t7_config {
#define MXT_POWER_CFG_DEEPSLEEP 1
/* MXT_TOUCH_MULTI_T9 field */
+#define MXT_TOUCH_CTRL 0
#define MXT_T9_ORIENT 9
#define MXT_T9_RANGE 18
@@ -135,9 +139,6 @@ struct t9_range {
/* Define for MXT_PROCI_TOUCHSUPPRESSION_T42 */
#define MXT_T42_MSG_TCHSUP (1 << 0)
-/* T47 Stylus */
-#define MXT_TOUCH_MAJOR_T47_STYLUS 1
-
/* T63 Stylus */
#define MXT_T63_STYLUS_PRESS (1 << 0)
#define MXT_T63_STYLUS_RELEASE (1 << 1)
@@ -166,7 +167,28 @@ struct t9_range {
#define MXT_T100_DETECT (1 << 7)
#define MXT_T100_TYPE_MASK 0x70
-#define MXT_T100_TYPE_STYLUS 0x20
+
+enum t100_type {
+ MXT_T100_TYPE_FINGER = 1,
+ MXT_T100_TYPE_PASSIVE_STYLUS = 2,
+ MXT_T100_TYPE_ACTIVE_STYLUS = 3,
+ MXT_T100_TYPE_HOVERING_FINGER = 4,
+ MXT_T100_TYPE_GLOVE = 5,
+ MXT_T100_TYPE_LARGE_TOUCH = 6,
+};
+
+/* Gen2 Active Stylus */
+#define MXT_T107_STYLUS_STYAUX 42
+#define MXT_T107_STYLUS_STYAUX_PRESSURE (1 << 0)
+#define MXT_T107_STYLUS_STYAUX_PEAK (1 << 4)
+
+#define MXT_T107_STYLUS_HOVER (1 << 0)
+#define MXT_T107_STYLUS_TIPSWITCH (1 << 1)
+#define MXT_T107_STYLUS_BUTTON0 (1 << 2)
+#define MXT_T107_STYLUS_BUTTON1 (1 << 3)
+
+#define MXT_TOUCH_MAJOR_DEFAULT 1
+#define MXT_PRESSURE_DEFAULT 1
/* Delay times */
#define MXT_BACKUP_TIME 50 /* msec */
@@ -179,6 +201,7 @@ struct t9_range {
#define MXT_REGULATOR_DELAY 150 /* msec */
#define MXT_CHG_DELAY 100 /* msec */
#define MXT_POWERON_DELAY 150 /* msec */
+#define MXT_BOOTLOADER_WAIT 36E5 /* 1 minute */
/* Command to unlock bootloader */
#define MXT_UNLOCK_CMD_MSB 0xaa
@@ -220,6 +243,26 @@ struct mxt_object {
u8 num_report_ids;
} __packed;
+/* Firmware frame structure */
+struct mxt_fw_frame {
+ __be16 size;
+ u8 data[];
+};
+
+/* Firmware update context */
+struct mxt_flash {
+ struct mxt_data *data;
+ const struct firmware *fw;
+ struct mxt_fw_frame *frame;
+ loff_t pos;
+ size_t frame_size;
+ unsigned int count;
+ unsigned int retry;
+ u8 previous;
+ struct completion flash_completion;
+ struct delayed_work work;
+};
+
/* Each client has this additional data */
struct mxt_data {
struct i2c_client *client;
@@ -256,12 +299,14 @@ struct mxt_data {
struct t7_config t7_cfg;
u8 num_stylusids;
unsigned long t15_keystatus;
+ u8 stylus_aux_pressure;
+ u8 stylus_aux_peak;
bool use_retrigen_workaround;
- bool use_regulator;
struct regulator *reg_vdd;
struct regulator *reg_avdd;
char *fw_name;
char *cfg_name;
+ struct mxt_flash *flash;
/* Cached parameters from object table */
u16 T5_address;
@@ -269,6 +314,7 @@ struct mxt_data {
u8 T6_reportid;
u16 T6_address;
u16 T7_address;
+ u16 T71_address;
u8 T9_reportid_min;
u8 T9_reportid_max;
u8 T15_reportid_min;
@@ -283,9 +329,7 @@ struct mxt_data {
u8 T63_reportid_max;
u8 T100_reportid_min;
u8 T100_reportid_max;
-
- /* for fw update in bootloader */
- struct completion bl_completion;
+ u16 T107_address;
/* for reset handling */
struct completion reset_completion;
@@ -293,6 +337,9 @@ struct mxt_data {
/* for config update handling */
struct completion crc_completion;
+ /* for power up handling */
+ struct completion chg_completion;
+
/* Indicates whether device is in suspend */
bool suspended;
@@ -337,6 +384,7 @@ static bool mxt_object_readable(unsigned int type)
case MXT_SPT_USERDATA_T38:
case MXT_SPT_DIGITIZER_T43:
case MXT_SPT_CTECONFIG_T46:
+ case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71:
return true;
default:
return false;
@@ -582,111 +630,142 @@ static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address)
{
struct device *dev = &data->client->dev;
int error;
- u8 val;
- bool crc_failure;
+ u8 buf[3];
+ bool crc_failure, extended_id;
error = mxt_lookup_bootloader_address(data, alt_address);
if (error)
return error;
- error = mxt_bootloader_read(data, &val, 1);
+ /* Check bootloader status and version information */
+ error = mxt_bootloader_read(data, buf, sizeof(buf));
if (error)
return error;
- /* Check app crc fail mode */
- crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL;
+ crc_failure = (buf[0] & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL;
+ extended_id = buf[0] & MXT_BOOT_EXTENDED_ID;
- dev_err(dev, "Detected bootloader, status:%02X%s\n",
- val, crc_failure ? ", APP_CRC_FAIL" : "");
+ dev_info(dev, "Found bootloader addr:%02x ID:%u%s%u%s\n",
+ data->bootloader_addr,
+ extended_id ? (buf[1] & MXT_BOOT_ID_MASK) : buf[0],
+ extended_id ? " version:" : "",
+ extended_id ? buf[2] : 0,
+ crc_failure ? ", APP_CRC_FAIL" : "");
return 0;
}
-static u8 mxt_get_bootloader_version(struct mxt_data *data, u8 val)
-{
- struct device *dev = &data->client->dev;
- u8 buf[3];
+static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock);
- if (val & MXT_BOOT_EXTENDED_ID) {
- if (mxt_bootloader_read(data, &buf[0], 3) != 0) {
- dev_err(dev, "%s: i2c failure\n", __func__);
- return val;
- }
-
- dev_dbg(dev, "Bootloader ID:%d Version:%d\n", buf[1], buf[2]);
+static int mxt_write_firmware_frame(struct mxt_data *data, struct mxt_flash *f)
+{
+ f->frame = (struct mxt_fw_frame*)(f->fw->data + f->pos);
- return buf[0];
- } else {
- dev_dbg(dev, "Bootloader ID:%d\n", val & MXT_BOOT_ID_MASK);
+ /* Take account of CRC bytes */
+ f->frame_size = __be16_to_cpu(f->frame->size) + 2U;
- return val;
- }
+ /* Write one frame to device */
+ return mxt_bootloader_write(data, f->fw->data + f->pos,
+ f->frame_size);
}
-static int mxt_check_bootloader(struct mxt_data *data, unsigned int state,
- bool wait)
+static int mxt_check_bootloader(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
- u8 val;
+ struct mxt_flash *f = data->flash;
+ u8 state;
int ret;
-recheck:
- if (wait) {
- /*
- * In application update mode, the interrupt
- * line signals state transitions. We must wait for the
- * CHG assertion before reading the status byte.
- * Once the status byte has been read, the line is deasserted.
- */
- ret = mxt_wait_for_completion(data, &data->bl_completion,
- MXT_FW_CHG_TIMEOUT);
- if (ret) {
- /*
- * TODO: handle -ERESTARTSYS better by terminating
- * fw update process before returning to userspace
- * by writing length 0x000 to device (iff we are in
- * WAITING_FRAME_DATA state).
- */
- dev_err(dev, "Update wait error %d\n", ret);
- return ret;
- }
+ /* Handle interrupt after download/flash process */
+ if (f->pos >= f->fw->size) {
+ complete(&f->flash_completion);
+ return 0;
}
- ret = mxt_bootloader_read(data, &val, 1);
+ ret = mxt_bootloader_read(data, &state, 1);
if (ret)
return ret;
- if (state == MXT_WAITING_BOOTLOAD_CMD)
- val = mxt_get_bootloader_version(data, val);
+ /* Remove don't care bits */
+ if (state & ~MXT_BOOT_STATUS_MASK)
+ state &= ~MXT_BOOT_STATUS_MASK;
switch (state) {
case MXT_WAITING_BOOTLOAD_CMD:
+ dev_info(dev, "Unlocking bootloader\n");
+ ret = mxt_send_bootloader_cmd(data, true);
+ if (ret)
+ return ret;
+
+ break;
+
case MXT_WAITING_FRAME_DATA:
- case MXT_APP_CRC_FAIL:
- val &= ~MXT_BOOT_STATUS_MASK;
+ if ((f->previous != MXT_WAITING_BOOTLOAD_CMD)
+ && (f->previous != MXT_FRAME_CRC_PASS)
+ && (f->previous != MXT_FRAME_CRC_FAIL))
+ goto unexpected;
+
+ ret = mxt_write_firmware_frame(data, f);
+ if (ret)
+ return ret;
+
break;
+
+ case MXT_FRAME_CRC_CHECK:
+ if (f->previous != MXT_WAITING_FRAME_DATA)
+ goto unexpected;
+ break;
+
case MXT_FRAME_CRC_PASS:
- if (val == MXT_FRAME_CRC_CHECK) {
- goto recheck;
- } else if (val == MXT_FRAME_CRC_FAIL) {
- dev_err(dev, "Bootloader CRC fail\n");
- return -EINVAL;
+ if (f->previous != MXT_FRAME_CRC_CHECK)
+ goto unexpected;
+
+ /* Next frame */
+ f->retry = 0;
+ f->pos += f->frame_size;
+ f->count++;
+
+ if (f->pos >= f->fw->size)
+ dev_info(dev, "Sent %u frames, %zu bytes\n",
+ f->count, f->fw->size);
+ else if (f->count % 50 == 0)
+ dev_dbg(dev, "Sent %u frames, %lld/%zu bytes\n",
+ f->count, f->pos, f->fw->size);
+
+ break;
+
+ case MXT_FRAME_CRC_FAIL:
+ f->retry++;
+
+ if (f->retry > 20) {
+ dev_err(dev, "Retry count exceeded\n");
+ return -EIO;
+ } else {
+ dev_dbg(dev, "Bootloader frame CRC failure\n");
}
+
+ /* Back off by 20ms per retry */
+ msleep(f->retry * 20);
+
break;
+
default:
return -EINVAL;
}
- if (val != state) {
- dev_err(dev, "Invalid bootloader state %02X != %02X\n",
- val, state);
- return -EINVAL;
- }
+ f->previous = state;
+
+ /* Poll after 0.1s if no interrupt received */
+ schedule_delayed_work(&f->work, HZ / 10);
return 0;
+
+unexpected:
+ dev_err(dev, "Unexpected state transition\n");
+ return -EINVAL;
}
-static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
+int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)
{
int ret;
u8 buf[2];
@@ -839,6 +918,20 @@ static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
data->t6_status = status;
}
+static int mxt_write_object(struct mxt_data *data,
+ u8 type, u8 offset, u8 val)
+{
+ struct mxt_object *object;
+ u16 reg;
+
+ object = mxt_get_object(data, type);
+ if (!object || offset >= mxt_obj_size(object))
+ return -EINVAL;
+
+ reg = object->start_address;
+ return mxt_write_reg(data->client, reg + offset, val);
+}
+
static void mxt_input_button(struct mxt_data *data, u8 *message)
{
struct input_dev *input = data->input_dev;
@@ -922,7 +1015,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
/* A size of zero indicates touch is from a linked T47 Stylus */
if (area == 0) {
- area = MXT_TOUCH_MAJOR_T47_STYLUS;
+ area = MXT_TOUCH_MAJOR_DEFAULT;
tool = MT_TOOL_PEN;
} else {
tool = MT_TOOL_FINGER;
@@ -949,9 +1042,17 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
struct input_dev *input_dev = data->input_dev;
int id;
u8 status;
+ u8 type;
int x;
int y;
int tool;
+ u8 major = 0;
+ u8 pressure = 0;
+ u8 orientation = 0;
+ bool active = false;
+ bool hover = false;
+ bool eraser = false;
+ bool barrel = false;
id = message[0] - data->T100_reportid_min - 2;
@@ -963,53 +1064,108 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
x = (message[3] << 8) | message[2];
y = (message[5] << 8) | message[4];
- dev_dbg(dev,
- "[%u] status:%02X x:%u y:%u area:%02X amp:%02X vec:%02X\n",
- id,
- status,
- x, y,
- data->t100_aux_area ? message[data->t100_aux_area] : 0,
- data->t100_aux_ampl ? message[data->t100_aux_ampl] : 0,
- data->t100_aux_vect ? message[data->t100_aux_vect] : 0);
+ if (status & MXT_T100_DETECT) {
+ type = (status & MXT_T100_TYPE_MASK) >> 4;
- input_mt_slot(input_dev, id);
+ switch (type) {
+ case MXT_T100_TYPE_HOVERING_FINGER:
+ hover = true;
+ /* fall through */
+ case MXT_T100_TYPE_FINGER:
+ case MXT_T100_TYPE_GLOVE:
+ active = true;
+ tool = MT_TOOL_FINGER;
- if (status & MXT_T100_DETECT) {
- if ((status & MXT_T100_TYPE_MASK) == MXT_T100_TYPE_STYLUS)
+ if (data->t100_aux_area)
+ major = message[data->t100_aux_area];
+ if (data->t100_aux_ampl)
+ pressure = message[data->t100_aux_ampl];
+ if (data->t100_aux_vect)
+ orientation = message[data->t100_aux_vect];
+
+ break;
+
+ case MXT_T100_TYPE_PASSIVE_STYLUS:
+ active = true;
tool = MT_TOOL_PEN;
- else
- tool = MT_TOOL_FINGER;
- /* Touch active */
- 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);
+ /* Passive stylus is reported with size zero so
+ * hardcode */
+ major = MXT_TOUCH_MAJOR_DEFAULT;
- if (data->t100_aux_ampl)
- input_report_abs(input_dev, ABS_MT_PRESSURE,
- message[data->t100_aux_ampl]);
+ if (data->t100_aux_ampl)
+ pressure = message[data->t100_aux_ampl];
- if (data->t100_aux_area) {
- if (tool == MT_TOOL_PEN)
- input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
- MXT_TOUCH_MAJOR_T47_STYLUS);
- else
- input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
- message[data->t100_aux_area]);
+ break;
+
+ case MXT_T100_TYPE_ACTIVE_STYLUS:
+ /* stylus in range, but position unavailable */
+ if (!(message[6] & MXT_T107_STYLUS_HOVER))
+ break;
+
+ active = true;
+ tool = MT_TOOL_PEN;
+ major = MXT_TOUCH_MAJOR_DEFAULT;
+ eraser = message[6] & MXT_T107_STYLUS_BUTTON0;
+ barrel = message[6] & MXT_T107_STYLUS_BUTTON1;
+
+ if (!(message[6] & MXT_T107_STYLUS_TIPSWITCH))
+ hover = true;
+ else if (data->stylus_aux_pressure)
+ pressure = message[data->stylus_aux_pressure];
+
+ break;
+
+ case MXT_T100_TYPE_LARGE_TOUCH:
+ /* Ignore suppressed touch */
+ break;
+
+ default:
+ dev_dbg(dev, "Unexpected T100 type\n");
+ return;
}
+ }
+
+ if (hover) {
+ pressure = 0;
+ major = 0;
+ } else if (active) {
+ /*
+ * Values reported should be non-zero if tool is touching the
+ * device
+ */
+ if (pressure == 0)
+ pressure = MXT_PRESSURE_DEFAULT;
+
+ if (major == 0)
+ major = MXT_TOUCH_MAJOR_DEFAULT;
+ }
+
+ input_mt_slot(input_dev, id);
- if (data->t100_aux_vect)
- input_report_abs(input_dev, ABS_MT_ORIENTATION,
- message[data->t100_aux_vect]);
+ if (active) {
+ dev_dbg(dev, "[%u] type:%u x:%u y:%u a:%02X p:%02X v:%02X\n",
+ 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);
+ 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_ORIENTATION, orientation);
+
+ input_report_key(input_dev, BTN_STYLUS, eraser);
+ input_report_key(input_dev, BTN_STYLUS2, barrel);
} else {
- /* Touch no longer active, close out slot */
- input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
+ dev_dbg(dev, "[%u] release\n", id);
+
+ /* close out slot */
+ input_mt_report_slot_state(input_dev, 0, 0);
}
data->update_input = true;
}
-
static void mxt_proc_t15_messages(struct mxt_data *data, u8 *msg)
{
struct input_dev *input_dev = data->input_dev;
@@ -1327,10 +1483,13 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;
+ complete(&data->chg_completion);
+
if (data->in_bootloader) {
- /* bootloader state transition completion */
- complete(&data->bl_completion);
- return IRQ_HANDLED;
+ if (data->flash && &data->flash->work)
+ cancel_delayed_work_sync(&data->flash->work);
+
+ return IRQ_RETVAL(mxt_check_bootloader(data));
}
if (!data->object_table)
@@ -1380,7 +1539,9 @@ static int mxt_soft_reset(struct mxt_data *data)
struct device *dev = &data->client->dev;
int ret = 0;
- dev_info(dev, "Resetting chip\n");
+ dev_info(dev, "Resetting device\n");
+
+ disable_irq(data->irq);
INIT_COMPLETION(data->reset_completion);
@@ -1388,6 +1549,11 @@ static int mxt_soft_reset(struct mxt_data *data)
if (ret)
return ret;
+ /* Ignore CHG line for 100ms after reset */
+ msleep(100);
+
+ enable_irq(data->irq);
+
ret = mxt_wait_for_completion(data, &data->reset_completion,
MXT_RESET_TIMEOUT);
if (ret)
@@ -1644,6 +1810,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
u32 info_crc, config_crc, calculated_crc;
u8 *config_mem;
size_t config_mem_size;
+ u16 crc_start = 0;
mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1);
@@ -1721,10 +1888,8 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
MXT_INFO_CHECKSUM_SIZE;
config_mem_size = data->mem_size - cfg_start_ofs;
config_mem = kzalloc(config_mem_size, GFP_KERNEL);
- if (!config_mem) {
- dev_err(dev, "Failed to allocate memory\n");
+ if (!config_mem)
return -ENOMEM;
- }
ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs,
config_mem, config_mem_size);
@@ -1732,20 +1897,22 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
goto release_mem;
/* Calculate crc of the received configs (not the raw config file) */
- if (data->T7_address < cfg_start_ofs) {
- dev_err(dev, "Bad T7 address, T7addr = %x, config offset %x\n",
- data->T7_address, cfg_start_ofs);
- ret = 0;
- goto release_mem;
- }
+ if (data->T71_address)
+ crc_start = data->T71_address;
+ else if (data->T7_address)
+ crc_start = data->T7_address;
+ else
+ dev_warn(dev, "Could not find CRC start\n");
- calculated_crc = mxt_calculate_crc(config_mem,
- data->T7_address - cfg_start_ofs,
- config_mem_size);
+ if (crc_start > cfg_start_ofs) {
+ calculated_crc = mxt_calculate_crc(config_mem,
+ crc_start - cfg_start_ofs,
+ config_mem_size);
- if (config_crc > 0 && config_crc != calculated_crc)
- dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n",
- calculated_crc, config_crc);
+ 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);
+ }
ret = mxt_upload_cfg_mem(data, cfg_start_ofs,
config_mem, config_mem_size);
@@ -1776,9 +1943,23 @@ static int mxt_acquire_irq(struct mxt_data *data)
{
int error;
- enable_irq(data->irq);
+ if (!data->irq) {
+ error = request_threaded_irq(data->client->irq, NULL,
+ mxt_interrupt,
+ data->pdata->irqflags | IRQF_ONESHOT,
+ data->client->name, data);
+ if (error) {
+ dev_err(&data->client->dev, "Error requesting irq\n");
+ return error;
+ }
+
+ /* Presence of data->irq means IRQ initialised */
+ data->irq = data->client->irq;
+ } else {
+ enable_irq(data->irq);
+ }
- if (data->use_retrigen_workaround) {
+ if (data->object_table && data->use_retrigen_workaround) {
error = mxt_process_messages_until_invalid(data);
if (error)
return error;
@@ -1805,11 +1986,11 @@ static void mxt_free_object_table(struct mxt_data *data)
data->raw_info_block = NULL;
kfree(data->msg_buf);
data->msg_buf = NULL;
-
data->T5_address = 0;
data->T5_msg_size = 0;
data->T6_reportid = 0;
data->T7_address = 0;
+ data->T71_address = 0;
data->T9_reportid_min = 0;
data->T9_reportid_max = 0;
data->T15_reportid_min = 0;
@@ -1883,6 +2064,9 @@ static int mxt_parse_object_table(struct mxt_data *data,
case MXT_GEN_POWER_T7:
data->T7_address = object->start_address;
break;
+ case MXT_SPT_DYNAMICCONFIGURATIONCONTAINER_T71:
+ data->T71_address = object->start_address;
+ break;
case MXT_TOUCH_MULTI_T9:
/* Only handle messages from first T9 instance */
data->T9_reportid_min = min_id;
@@ -1922,6 +2106,9 @@ static int mxt_parse_object_table(struct mxt_data *data,
/* first two report IDs reserved */
data->num_touchids = object->num_report_ids - 2;
break;
+ case MXT_PROCI_ACTIVESTYLUS_T107:
+ data->T107_address = object->start_address;
+ break;
}
end_address = object->start_address
@@ -1942,10 +2129,8 @@ static int mxt_parse_object_table(struct mxt_data *data,
data->msg_buf = kcalloc(data->max_reportid,
data->T5_msg_size, GFP_KERNEL);
- if (!data->msg_buf) {
- dev_err(&client->dev, "Failed to allocate message buffer\n");
+ if (!data->msg_buf)
return -ENOMEM;
- }
return 0;
}
@@ -1967,10 +2152,8 @@ static int mxt_read_info_block(struct mxt_data *data)
/* Read 7-byte ID information block starting at address 0 */
size = sizeof(struct mxt_info);
id_buf = kzalloc(size, GFP_KERNEL);
- if (!id_buf) {
- dev_err(&client->dev, "Failed to allocate memory\n");
+ if (!id_buf)
return -ENOMEM;
- }
error = __mxt_read_reg(client, 0, size, id_buf);
if (error) {
@@ -1985,7 +2168,6 @@ static int mxt_read_info_block(struct mxt_data *data)
buf = krealloc(id_buf, size, GFP_KERNEL);
if (!buf) {
- dev_err(&client->dev, "Failed to allocate memory\n");
error = -ENOMEM;
goto err_free_mem;
}
@@ -2056,14 +2238,19 @@ static void mxt_regulator_enable(struct mxt_data *data)
if (error)
return;
+ /*
+ * According to maXTouch power sequencing specification, RESET line
+ * must be kept low until some time after regulators come up to
+ * voltage
+ */
msleep(MXT_REGULATOR_DELAY);
gpio_set_value(data->pdata->gpio_reset, 1);
msleep(MXT_CHG_DELAY);
retry_wait:
- INIT_COMPLETION(data->bl_completion);
+ INIT_COMPLETION(data->chg_completion);
data->in_bootloader = true;
- error = mxt_wait_for_completion(data, &data->bl_completion,
+ error = mxt_wait_for_completion(data, &data->chg_completion,
MXT_POWERON_DELAY);
if (error == -EINTR)
goto retry_wait;
@@ -2077,18 +2264,14 @@ static void mxt_regulator_disable(struct mxt_data *data)
regulator_disable(data->reg_avdd);
}
-static void mxt_probe_regulators(struct mxt_data *data)
+static int mxt_probe_regulators(struct mxt_data *data)
{
struct device *dev = &data->client->dev;
int error;
- /*
- * According to maXTouch power sequencing specification, RESET line
- * must be kept low until some time after regulators come up to
- * voltage
- */
if (!gpio_is_valid(data->pdata->gpio_reset)) {
dev_dbg(dev, "Must have reset GPIO to use regulator support\n");
+ error = -EINVAL;
goto fail;
}
@@ -2106,18 +2289,17 @@ static void mxt_probe_regulators(struct mxt_data *data)
goto fail_release;
}
- data->use_regulator = true;
mxt_regulator_enable(data);
dev_dbg(dev, "Initialised regulators\n");
- return;
+ return 0;
fail_release:
regulator_put(data->reg_vdd);
fail:
data->reg_vdd = NULL;
data->reg_avdd = NULL;
- data->use_regulator = false;
+ return error;
}
static int mxt_read_t9_resolution(struct mxt_data *data)
@@ -2168,8 +2350,6 @@ static int mxt_read_t9_resolution(struct mxt_data *data)
return 0;
}
-static void mxt_start(struct mxt_data *data);
-static void mxt_stop(struct mxt_data *data);
static int mxt_input_open(struct input_dev *dev);
static void mxt_input_close(struct input_dev *dev);
@@ -2188,10 +2368,8 @@ static int mxt_initialize_t9_input_device(struct mxt_data *data)
dev_warn(dev, "Failed to initialize T9 resolution\n");
input_dev = input_allocate_device();
- if (!input_dev) {
- dev_err(dev, "Failed to allocate memory\n");
+ if (!input_dev)
return -ENOMEM;
- }
input_dev->name = "Atmel maXTouch Touchscreen";
input_dev->phys = data->phys;
@@ -2287,6 +2465,40 @@ err_free_mem:
return error;
}
+static int mxt_read_t107_stylus_config(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ int error;
+ struct mxt_object *object;
+ u8 styaux;
+ int aux;
+
+ object = mxt_get_object(data, MXT_PROCI_ACTIVESTYLUS_T107);
+ if (!object)
+ return 0;
+
+ error = __mxt_read_reg(client,
+ object->start_address + MXT_T107_STYLUS_STYAUX,
+ 1, &styaux);
+ if (error)
+ return error;
+
+ /* map aux bits */
+ aux = 7;
+
+ if (styaux & MXT_T107_STYLUS_STYAUX_PRESSURE)
+ data->stylus_aux_pressure = aux++;
+
+ if (styaux & MXT_T107_STYLUS_STYAUX_PEAK)
+ data->stylus_aux_peak = aux++;
+
+ dev_dbg(&client->dev,
+ "Enabling T107 active stylus, aux map pressure:%u peak:%u\n",
+ data->stylus_aux_pressure, data->stylus_aux_peak);
+
+ return 0;
+}
+
static int mxt_read_t100_config(struct mxt_data *data)
{
struct i2c_client *client = data->client;
@@ -2332,10 +2544,6 @@ static int mxt_read_t100_config(struct mxt_data *data)
if (range_x == 0)
range_x = 1023;
- /* Handle default values */
- if (range_x == 0)
- range_x = 1023;
-
if (range_y == 0)
range_y = 1023;
@@ -2359,6 +2567,10 @@ static int mxt_read_t100_config(struct mxt_data *data)
if (tchaux & MXT_T100_TCHAUX_AREA)
data->t100_aux_area = aux++;
+ dev_dbg(&client->dev,
+ "T100 aux mappings vect:%u ampl:%u area:%u\n",
+ data->t100_aux_vect, data->t100_aux_ampl, data->t100_aux_area);
+
dev_info(&client->dev,
"T100 Touchscreen size X%uY%u\n", data->max_x, data->max_y);
@@ -2372,14 +2584,16 @@ static int mxt_initialize_t100_input_device(struct mxt_data *data)
int error;
error = mxt_read_t100_config(data);
- if (error)
- dev_warn(dev, "Failed to initialize T9 resolution\n");
+ if (error) {
+ dev_err(dev, "Failed to read T100 config\n");
+ return error;
+ }
+
+ mxt_read_t107_stylus_config(data);
input_dev = input_allocate_device();
- if (!data || !input_dev) {
- dev_err(dev, "Failed to allocate memory\n");
+ if (!data || !input_dev)
return -ENOMEM;
- }
if (data->pdata->input_name)
input_dev->name = data->pdata->input_name;
@@ -2419,11 +2633,16 @@ static int mxt_initialize_t100_input_device(struct mxt_data *data)
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, data->max_y, 0, 0);
+ if (data->T107_address) {
+ input_set_capability(input_dev, EV_KEY, BTN_STYLUS);
+ input_set_capability(input_dev, EV_KEY, BTN_STYLUS2);
+ }
+
if (data->t100_aux_area)
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, MXT_MAX_AREA, 0, 0);
- if (data->t100_aux_ampl)
+ if (data->t100_aux_ampl | data->stylus_aux_pressure)
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
0, 255, 0, 0);
@@ -2743,132 +2962,98 @@ static int mxt_check_firmware_format(struct device *dev,
return -EINVAL;
}
-static int mxt_load_fw(struct device *dev)
+static int mxt_enter_bootloader(struct mxt_data *data)
{
- struct mxt_data *data = dev_get_drvdata(dev);
- const struct firmware *fw = NULL;
- unsigned int frame_size;
- unsigned int pos = 0;
- unsigned int retry = 0;
- unsigned int frame = 0;
int ret;
- ret = request_firmware(&fw, data->fw_name, dev);
- if (ret) {
- dev_err(dev, "Unable to open firmware %s\n", data->fw_name);
- return ret;
- }
-
- /* Check for incorrect enc file */
- ret = mxt_check_firmware_format(dev, fw);
- if (ret)
- goto release_firmware;
-
if (data->suspended) {
- if (data->use_regulator)
+ if (data->pdata->suspend_mode == MXT_SUSPEND_REGULATOR)
mxt_regulator_enable(data);
- enable_irq(data->irq);
data->suspended = false;
}
if (!data->in_bootloader) {
/* Change to the bootloader mode */
- data->in_bootloader = true;
-
ret = mxt_t6_command(data, MXT_COMMAND_RESET,
MXT_BOOT_VALUE, false);
if (ret)
- goto release_firmware;
+ return ret;
msleep(MXT_RESET_TIME);
/* Do not need to scan since we know family ID */
- ret = mxt_lookup_bootloader_address(data, 0);
+ ret = mxt_probe_bootloader(data, 0);
if (ret)
- goto release_firmware;
+ return ret;
+ data->in_bootloader = true;
mxt_free_input_device(data);
mxt_free_object_table(data);
- } else {
- enable_irq(data->irq);
}
- INIT_COMPLETION(data->bl_completion);
+ dev_dbg(&data->client->dev, "Entered bootloader\n");
- ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false);
- if (ret) {
- /* Bootloader may still be unlocked from previous attempt */
- ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false);
- if (ret)
- goto disable_irq;
- } else {
- dev_info(dev, "Unlocking bootloader\n");
+ return 0;
+}
- /* Unlock bootloader */
- ret = mxt_send_bootloader_cmd(data, true);
- if (ret)
- goto disable_irq;
- }
+static void mxt_fw_work(struct work_struct *work)
+{
+ struct mxt_flash *f =
+ container_of(work, struct mxt_flash, work.work);
- while (pos < fw->size) {
- ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true);
- if (ret)
- goto disable_irq;
+ mxt_check_bootloader(f->data);
+}
- frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
+static int mxt_load_fw(struct device *dev)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ int ret;
- /* Take account of CRC bytes */
- frame_size += 2;
+ data->flash = devm_kzalloc(dev, sizeof(struct mxt_flash), GFP_KERNEL);
+ if (!data->flash)
+ return -ENOMEM;
- /* Write one frame to device */
- ret = mxt_bootloader_write(data, fw->data + pos, frame_size);
- if (ret)
- goto disable_irq;
+ data->flash->data = data;
- ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true);
- if (ret) {
- retry++;
+ ret = request_firmware(&data->flash->fw, data->fw_name, dev);
+ if (ret) {
+ dev_err(dev, "Unable to open firmware %s\n", data->fw_name);
+ goto free;
+ }
- /* Back off by 20ms per retry */
- msleep(retry * 20);
+ /* Check for incorrect enc file */
+ ret = mxt_check_firmware_format(dev, data->flash->fw);
+ if (ret)
+ goto release_firmware;
- if (retry > 20) {
- dev_err(dev, "Retry count exceeded\n");
- goto disable_irq;
- }
- } else {
- retry = 0;
- pos += frame_size;
- frame++;
- }
+ init_completion(&data->flash->flash_completion);
+ INIT_DELAYED_WORK(&data->flash->work, mxt_fw_work);
- if (frame % 50 == 0)
- dev_dbg(dev, "Sent %d frames, %d/%zd bytes\n",
- frame, pos, fw->size);
+ if (!data->in_bootloader) {
+ ret = mxt_enter_bootloader(data);
+ if (ret)
+ goto release_firmware;
}
- /* Wait for flash. */
- ret = mxt_wait_for_completion(data, &data->bl_completion,
- MXT_FW_RESET_TIME);
+ ret = mxt_acquire_irq(data);
if (ret)
- goto disable_irq;
+ goto release_firmware;
- dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos);
+ /* Poll after 0.1s if no interrupt received */
+ schedule_delayed_work(&data->flash->work, HZ / 10);
- /*
- * Wait for device to reset. Some bootloader versions do not assert
- * the CHG line after bootloading has finished, so ignore potential
- * errors.
- */
- mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME);
-
- data->in_bootloader = false;
+ /* Wait for flash. */
+ ret = mxt_wait_for_completion(data, &data->flash->flash_completion,
+ MXT_BOOTLOADER_WAIT);
-disable_irq:
disable_irq(data->irq);
+ cancel_delayed_work_sync(&data->flash->work);
+ data->in_bootloader = false;
release_firmware:
- release_firmware(fw);
+ release_firmware(data->flash->fw);
+free:
+ devm_kfree(dev, data->flash);
return ret;
}
@@ -2884,10 +3069,8 @@ static int mxt_update_file_name(struct device *dev, char **file_name,
}
file_name_tmp = krealloc(*file_name, count + 1, GFP_KERNEL);
- if (!file_name_tmp) {
- dev_warn(dev, "no memory\n");
+ if (!file_name_tmp)
return -ENOMEM;
- }
*file_name = file_name_tmp;
memcpy(*file_name, buf, count);
@@ -2934,6 +3117,7 @@ static ssize_t mxt_update_cfg_store(struct device *dev,
const char *buf, size_t count)
{
struct mxt_data *data = dev_get_drvdata(dev);
+ const struct mxt_platform_data *pdata = data->pdata;
const struct firmware *cfg;
int ret;
@@ -2959,10 +3143,10 @@ static ssize_t mxt_update_cfg_store(struct device *dev,
mxt_free_input_device(data);
if (data->suspended) {
- if (data->use_regulator) {
+ if (pdata->suspend_mode == MXT_SUSPEND_REGULATOR) {
enable_irq(data->irq);
mxt_regulator_enable(data);
- } else {
+ } else if (pdata->suspend_mode == MXT_SUSPEND_DEEP_SLEEP) {
mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
mxt_acquire_irq(data);
}
@@ -3044,6 +3228,9 @@ static ssize_t mxt_debug_enable_store(struct device *dev,
static int mxt_check_mem_access_params(struct mxt_data *data, loff_t off,
size_t *count)
{
+ if (data->in_bootloader)
+ return -EINVAL;
+
if (off >= data->mem_size)
return -EIO;
@@ -3144,13 +3331,24 @@ static void mxt_start(struct mxt_data *data)
if (!data->suspended || data->in_bootloader)
return;
- if (data->use_regulator) {
- enable_irq(data->irq);
+ switch (data->pdata->suspend_mode) {
+ case MXT_SUSPEND_TOUCH_CTRL:
+ mxt_soft_reset(data);
+
+ /* Touch enable */
+ mxt_write_object(data,
+ MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83);
+ break;
+ case MXT_SUSPEND_REGULATOR:
+ enable_irq(data->irq);
mxt_regulator_enable(data);
- } else {
+ break;
+
+ case MXT_SUSPEND_DEEP_SLEEP:
+ default:
/*
- * Discard any messages still in message buffer
+ * Discard any touch messages still in message buffer
* from before chip went to sleep
*/
mxt_process_messages_until_invalid(data);
@@ -3161,6 +3359,7 @@ static void mxt_start(struct mxt_data *data)
mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
mxt_acquire_irq(data);
+ break;
}
data->suspended = false;
@@ -3171,14 +3370,29 @@ static void mxt_stop(struct mxt_data *data)
if (data->suspended || data->in_bootloader || data->updating_config)
return;
- disable_irq(data->irq);
+ switch (data->pdata->suspend_mode) {
+ case MXT_SUSPEND_TOUCH_CTRL:
+ /* Touch disable */
+ mxt_write_object(data,
+ MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
+ break;
- if (data->use_regulator)
+ case MXT_SUSPEND_REGULATOR:
+ disable_irq(data->irq);
mxt_regulator_disable(data);
- else
+ mxt_reset_slots(data);
+ break;
+
+ case MXT_SUSPEND_DEEP_SLEEP:
+ default:
+ disable_irq(data->irq);
+
mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
- mxt_reset_slots(data);
+ mxt_reset_slots(data);
+ break;
+ }
+
data->suspended = true;
}
@@ -3244,6 +3458,9 @@ static struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client)
pdata->t19_keymap = keymap;
}
+ of_property_read_u32(client->dev.of_node, "atmel,suspend-mode",
+ &pdata->suspend_mode);
+
return pdata;
}
#else
@@ -3276,17 +3493,14 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL);
- if (!data) {
- dev_err(&client->dev, "Failed to allocate memory\n");
+ if (!data)
return -ENOMEM;
- }
snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
client->adapter->nr, client->addr);
data->client = client;
data->pdata = pdata;
- data->irq = client->irq;
i2c_set_clientdata(client, data);
if (data->pdata->cfg_name)
@@ -3295,22 +3509,22 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
data->pdata->cfg_name,
strlen(data->pdata->cfg_name));
- init_completion(&data->bl_completion);
init_completion(&data->reset_completion);
init_completion(&data->crc_completion);
+ init_completion(&data->chg_completion);
mutex_init(&data->debug_msg_lock);
- error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
- pdata->irqflags | IRQF_ONESHOT,
- client->name, data);
- if (error) {
- dev_err(&client->dev, "Failed to register interrupt\n");
- goto err_free_mem;
- }
+ if (pdata->suspend_mode == MXT_SUSPEND_REGULATOR) {
+ error = mxt_acquire_irq(data);
+ if (error)
+ goto err_free_mem;
- mxt_probe_regulators(data);
+ error = mxt_probe_regulators(data);
+ if (error)
+ goto err_free_irq;
- disable_irq(data->irq);
+ disable_irq(data->irq);
+ }
error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
if (error) {
@@ -3345,7 +3559,8 @@ err_remove_mem_access:
err_remove_sysfs_group:
sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
err_free_irq:
- free_irq(client->irq, data);
+ if (data->irq)
+ free_irq(data->irq, data);
err_free_mem:
kfree(data);
return error;
@@ -3360,7 +3575,10 @@ static int mxt_remove(struct i2c_client *client)
&data->mem_access_attr);
sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
- free_irq(data->irq, data);
+
+ if (data->irq)
+ free_irq(data->irq, data);
+
regulator_put(data->reg_avdd);
regulator_put(data->reg_vdd);
mxt_free_input_device(data);
@@ -3370,8 +3588,7 @@ static int mxt_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int mxt_suspend(struct device *dev)
+static int __maybe_unused mxt_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
@@ -3387,7 +3604,7 @@ static int mxt_suspend(struct device *dev)
return 0;
}
-static int mxt_resume(struct device *dev)
+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);
@@ -3402,7 +3619,6 @@ static int mxt_resume(struct device *dev)
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
diff --git a/include/dt-bindings/input/atmel_mxt_ts.h b/include/dt-bindings/input/atmel_mxt_ts.h
new file mode 100644
index 00000000000..c7637925da5
--- /dev/null
+++ b/include/dt-bindings/input/atmel_mxt_ts.h
@@ -0,0 +1,22 @@
+/*
+ * Atmel maXTouch Touchscreen driver
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ * Author: Nick Dyer <nick.dyer@itdev.co.uk>
+ *
+ * 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.
+ */
+
+#ifndef __DT_BINDINGS_ATMEL_MXT_TS_H
+#define __DT_BINDINGS_ATMEL_MXT_TS_H
+
+enum mxt_suspend_mode {
+ MXT_SUSPEND_DEEP_SLEEP = 0,
+ MXT_SUSPEND_TOUCH_CTRL = 1,
+ MXT_SUSPEND_REGULATOR = 2,
+};
+
+#endif /* __DT_BINDINGS_ATMEL_MXT_TS_H */
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/platform_data/atmel_mxt_ts.h
index bc74c3f4c86..be6fa95a661 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/platform_data/atmel_mxt_ts.h
@@ -10,16 +10,18 @@
* option) any later version.
*/
-#ifndef __LINUX_ATMEL_MXT_TS_H
-#define __LINUX_ATMEL_MXT_TS_H
+#ifndef __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H
+#define __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H
#include <linux/types.h>
+#include <dt-bindings/input/atmel_mxt_ts.h>
/* The platform data for the Atmel maXTouch touchscreen driver */
struct mxt_platform_data {
unsigned long irqflags;
u8 t19_num_keys;
const unsigned int *t19_keymap;
+ enum mxt_suspend_mode suspend_mode;
int t15_num_keys;
const unsigned int *t15_keymap;
unsigned long gpio_reset;
@@ -27,4 +29,4 @@ struct mxt_platform_data {
const char *input_name;
};
-#endif /* __LINUX_ATMEL_MXT_TS_H */
+#endif /* __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H */