Input: atmel_mxt_ts - use deep sleep mode when stopped
The hardcoded 0x83 CTRL setting overrides other settings in that byte, enabling extra reporting that may not be useful on a particular platform. Implement improved suspend mechanism via deep sleep. By writing zero to both the active and idle cycle times the maXTouch device can be put into a deep sleep mode, using minimal power. It is necessary to issue a calibrate command after the chip has spent any time in deep sleep, however a soft reset is unnecessary. Use the old method on Chromebook Pixel via platform data option. This patch also deals with the situation where the power configuration is zero on probe, which would mean that the device never wakes up to execute commands. After a config download, the T7 power configuration may have changed so it is necessary to re-read it. Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk> Acked-by: Benson Leung <bleung@chromium.org> Acked-by: Yufeng Shen <miletus@chromium.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
7d6548abcf
commit
7f3884f7de
|
@ -22,7 +22,7 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include <linux/i2c.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/input/mt.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
@ -103,9 +103,13 @@
|
||||||
#define MXT_T6_STATUS_COMSERR (1 << 2)
|
#define MXT_T6_STATUS_COMSERR (1 << 2)
|
||||||
|
|
||||||
/* MXT_GEN_POWER_T7 field */
|
/* MXT_GEN_POWER_T7 field */
|
||||||
#define MXT_POWER_IDLEACQINT 0
|
struct t7_config {
|
||||||
#define MXT_POWER_ACTVACQINT 1
|
u8 idle;
|
||||||
#define MXT_POWER_ACTV2IDLETO 2
|
u8 active;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define MXT_POWER_CFG_RUN 0
|
||||||
|
#define MXT_POWER_CFG_DEEPSLEEP 1
|
||||||
|
|
||||||
/* MXT_GEN_ACQUIRE_T8 field */
|
/* MXT_GEN_ACQUIRE_T8 field */
|
||||||
#define MXT_ACQUIRE_CHRGTIME 0
|
#define MXT_ACQUIRE_CHRGTIME 0
|
||||||
|
@ -117,7 +121,7 @@
|
||||||
#define MXT_ACQUIRE_ATCHCALSTHR 7
|
#define MXT_ACQUIRE_ATCHCALSTHR 7
|
||||||
|
|
||||||
/* MXT_TOUCH_MULTI_T9 field */
|
/* MXT_TOUCH_MULTI_T9 field */
|
||||||
#define MXT_TOUCH_CTRL 0
|
#define MXT_T9_CTRL 0
|
||||||
#define MXT_T9_ORIENT 9
|
#define MXT_T9_ORIENT 9
|
||||||
#define MXT_T9_RANGE 18
|
#define MXT_T9_RANGE 18
|
||||||
|
|
||||||
|
@ -291,6 +295,7 @@ struct mxt_data {
|
||||||
u8 last_message_count;
|
u8 last_message_count;
|
||||||
u8 num_touchids;
|
u8 num_touchids;
|
||||||
u8 multitouch;
|
u8 multitouch;
|
||||||
|
struct t7_config t7_cfg;
|
||||||
|
|
||||||
/* Cached parameters from object table */
|
/* Cached parameters from object table */
|
||||||
u16 T5_address;
|
u16 T5_address;
|
||||||
|
@ -1361,6 +1366,8 @@ static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mxt_init_t7_power_cfg(struct mxt_data *data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mxt_update_cfg - download configuration to chip
|
* mxt_update_cfg - download configuration to chip
|
||||||
*
|
*
|
||||||
|
@ -1508,6 +1515,9 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
|
||||||
|
|
||||||
dev_info(dev, "Config successfully updated\n");
|
dev_info(dev, "Config successfully updated\n");
|
||||||
|
|
||||||
|
/* T7 config may have changed */
|
||||||
|
mxt_init_t7_power_cfg(data);
|
||||||
|
|
||||||
release_mem:
|
release_mem:
|
||||||
kfree(config_mem);
|
kfree(config_mem);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -2051,6 +2061,60 @@ err_free_object_table:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep)
|
||||||
|
{
|
||||||
|
struct device *dev = &data->client->dev;
|
||||||
|
int error;
|
||||||
|
struct t7_config *new_config;
|
||||||
|
struct t7_config deepsleep = { .active = 0, .idle = 0 };
|
||||||
|
|
||||||
|
if (sleep == MXT_POWER_CFG_DEEPSLEEP)
|
||||||
|
new_config = &deepsleep;
|
||||||
|
else
|
||||||
|
new_config = &data->t7_cfg;
|
||||||
|
|
||||||
|
error = __mxt_write_reg(data->client, data->T7_address,
|
||||||
|
sizeof(data->t7_cfg), new_config);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n",
|
||||||
|
new_config->active, new_config->idle);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxt_init_t7_power_cfg(struct mxt_data *data)
|
||||||
|
{
|
||||||
|
struct device *dev = &data->client->dev;
|
||||||
|
int error;
|
||||||
|
bool retry = false;
|
||||||
|
|
||||||
|
recheck:
|
||||||
|
error = __mxt_read_reg(data->client, data->T7_address,
|
||||||
|
sizeof(data->t7_cfg), &data->t7_cfg);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) {
|
||||||
|
if (!retry) {
|
||||||
|
dev_dbg(dev, "T7 cfg zero, resetting\n");
|
||||||
|
mxt_soft_reset(data);
|
||||||
|
retry = true;
|
||||||
|
goto recheck;
|
||||||
|
} else {
|
||||||
|
dev_dbg(dev, "T7 cfg zero after reset, overriding\n");
|
||||||
|
data->t7_cfg.active = 20;
|
||||||
|
data->t7_cfg.idle = 100;
|
||||||
|
return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n",
|
||||||
|
data->t7_cfg.active, data->t7_cfg.idle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int mxt_configure_objects(struct mxt_data *data,
|
static int mxt_configure_objects(struct mxt_data *data,
|
||||||
const struct firmware *cfg)
|
const struct firmware *cfg)
|
||||||
{
|
{
|
||||||
|
@ -2058,6 +2122,12 @@ static int mxt_configure_objects(struct mxt_data *data,
|
||||||
struct mxt_info *info = &data->info;
|
struct mxt_info *info = &data->info;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
error = mxt_init_t7_power_cfg(data);
|
||||||
|
if (error) {
|
||||||
|
dev_err(dev, "Failed to initialize power cfg\n");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
if (cfg) {
|
if (cfg) {
|
||||||
error = mxt_update_cfg(data, cfg);
|
error = mxt_update_cfg(data, cfg);
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -2346,14 +2416,41 @@ static const struct attribute_group mxt_attr_group = {
|
||||||
|
|
||||||
static void mxt_start(struct mxt_data *data)
|
static void mxt_start(struct mxt_data *data)
|
||||||
{
|
{
|
||||||
/* Touch enable */
|
switch (data->pdata->suspend_mode) {
|
||||||
mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0x83);
|
case MXT_SUSPEND_T9_CTRL:
|
||||||
|
mxt_soft_reset(data);
|
||||||
|
|
||||||
|
/* Touch enable */
|
||||||
|
/* 0x83 = SCANEN | RPTEN | ENABLE */
|
||||||
|
mxt_write_object(data,
|
||||||
|
MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MXT_SUSPEND_DEEP_SLEEP:
|
||||||
|
default:
|
||||||
|
mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
|
||||||
|
|
||||||
|
/* Recalibrate since chip has been in deep sleep */
|
||||||
|
mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mxt_stop(struct mxt_data *data)
|
static void mxt_stop(struct mxt_data *data)
|
||||||
{
|
{
|
||||||
/* Touch disable */
|
switch (data->pdata->suspend_mode) {
|
||||||
mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0);
|
case MXT_SUSPEND_T9_CTRL:
|
||||||
|
/* Touch disable */
|
||||||
|
mxt_write_object(data,
|
||||||
|
MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MXT_SUSPEND_DEEP_SLEEP:
|
||||||
|
default:
|
||||||
|
mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mxt_input_open(struct input_dev *dev)
|
static int mxt_input_open(struct input_dev *dev)
|
||||||
|
@ -2409,6 +2506,8 @@ static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client)
|
||||||
pdata->t19_keymap = keymap;
|
pdata->t19_keymap = keymap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP;
|
||||||
|
|
||||||
return pdata;
|
return pdata;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -2625,8 +2724,6 @@ static int __maybe_unused mxt_resume(struct device *dev)
|
||||||
struct mxt_data *data = i2c_get_clientdata(client);
|
struct mxt_data *data = i2c_get_clientdata(client);
|
||||||
struct input_dev *input_dev = data->input_dev;
|
struct input_dev *input_dev = data->input_dev;
|
||||||
|
|
||||||
mxt_soft_reset(data);
|
|
||||||
|
|
||||||
mutex_lock(&input_dev->mutex);
|
mutex_lock(&input_dev->mutex);
|
||||||
|
|
||||||
if (input_dev->users)
|
if (input_dev->users)
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/i2c/atmel_mxt_ts.h>
|
#include <linux/platform_data/atmel_mxt_ts.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -111,6 +111,7 @@ static struct mxt_platform_data atmel_224s_tp_platform_data = {
|
||||||
.irqflags = IRQF_TRIGGER_FALLING,
|
.irqflags = IRQF_TRIGGER_FALLING,
|
||||||
.t19_num_keys = ARRAY_SIZE(mxt_t19_keys),
|
.t19_num_keys = ARRAY_SIZE(mxt_t19_keys),
|
||||||
.t19_keymap = mxt_t19_keys,
|
.t19_keymap = mxt_t19_keys,
|
||||||
|
.suspend_mode = MXT_SUSPEND_T9_CTRL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct i2c_board_info atmel_224s_tp_device = {
|
static struct i2c_board_info atmel_224s_tp_device = {
|
||||||
|
@ -121,6 +122,7 @@ static struct i2c_board_info atmel_224s_tp_device = {
|
||||||
|
|
||||||
static struct mxt_platform_data atmel_1664s_platform_data = {
|
static struct mxt_platform_data atmel_1664s_platform_data = {
|
||||||
.irqflags = IRQF_TRIGGER_FALLING,
|
.irqflags = IRQF_TRIGGER_FALLING,
|
||||||
|
.suspend_mode = MXT_SUSPEND_T9_CTRL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct i2c_board_info atmel_1664s_device = {
|
static struct i2c_board_info atmel_1664s_device = {
|
||||||
|
|
|
@ -10,16 +10,22 @@
|
||||||
* option) any later version.
|
* option) any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __LINUX_ATMEL_MXT_TS_H
|
#ifndef __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H
|
||||||
#define __LINUX_ATMEL_MXT_TS_H
|
#define __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
enum mxt_suspend_mode {
|
||||||
|
MXT_SUSPEND_DEEP_SLEEP = 0,
|
||||||
|
MXT_SUSPEND_T9_CTRL = 1,
|
||||||
|
};
|
||||||
|
|
||||||
/* The platform data for the Atmel maXTouch touchscreen driver */
|
/* The platform data for the Atmel maXTouch touchscreen driver */
|
||||||
struct mxt_platform_data {
|
struct mxt_platform_data {
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
u8 t19_num_keys;
|
u8 t19_num_keys;
|
||||||
const unsigned int *t19_keymap;
|
const unsigned int *t19_keymap;
|
||||||
|
enum mxt_suspend_mode suspend_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __LINUX_ATMEL_MXT_TS_H */
|
#endif /* __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H */
|
Loading…
Reference in a new issue