diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 8efe7a002f1e..0e743b3a691b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -103,9 +103,13 @@ #define MXT_T6_STATUS_COMSERR (1 << 2) /* MXT_GEN_POWER_T7 field */ -#define MXT_POWER_IDLEACQINT 0 -#define MXT_POWER_ACTVACQINT 1 -#define MXT_POWER_ACTV2IDLETO 2 +struct t7_config { + u8 idle; + u8 active; +} __packed; + +#define MXT_POWER_CFG_RUN 0 +#define MXT_POWER_CFG_DEEPSLEEP 1 /* MXT_GEN_ACQUIRE_T8 field */ #define MXT_ACQUIRE_CHRGTIME 0 @@ -117,7 +121,7 @@ #define MXT_ACQUIRE_ATCHCALSTHR 7 /* MXT_TOUCH_MULTI_T9 field */ -#define MXT_TOUCH_CTRL 0 +#define MXT_T9_CTRL 0 #define MXT_T9_ORIENT 9 #define MXT_T9_RANGE 18 @@ -291,6 +295,7 @@ struct mxt_data { u8 last_message_count; u8 num_touchids; u8 multitouch; + struct t7_config t7_cfg; /* Cached parameters from object table */ u16 T5_address; @@ -1361,6 +1366,8 @@ static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start, return 0; } +static int mxt_init_t7_power_cfg(struct mxt_data *data); + /* * 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"); + /* T7 config may have changed */ + mxt_init_t7_power_cfg(data); + release_mem: kfree(config_mem); return ret; @@ -2051,6 +2061,60 @@ err_free_object_table: 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, const struct firmware *cfg) { @@ -2058,6 +2122,12 @@ static int mxt_configure_objects(struct mxt_data *data, struct mxt_info *info = &data->info; int error; + error = mxt_init_t7_power_cfg(data); + if (error) { + dev_err(dev, "Failed to initialize power cfg\n"); + return error; + } + if (cfg) { error = mxt_update_cfg(data, cfg); if (error) @@ -2346,14 +2416,41 @@ static const struct attribute_group mxt_attr_group = { static void mxt_start(struct mxt_data *data) { - /* Touch enable */ - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0x83); + switch (data->pdata->suspend_mode) { + 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) { - /* Touch disable */ - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0); + switch (data->pdata->suspend_mode) { + 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) @@ -2409,6 +2506,8 @@ static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) pdata->t19_keymap = keymap; } + pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP; + return pdata; } #else @@ -2625,8 +2724,6 @@ static int __maybe_unused mxt_resume(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; - mxt_soft_reset(data); - mutex_lock(&input_dev->mutex); if (input_dev->users) diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index a04019ab9feb..02072749fff3 100644 --- a/drivers/platform/chrome/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -111,6 +111,7 @@ static struct mxt_platform_data atmel_224s_tp_platform_data = { .irqflags = IRQF_TRIGGER_FALLING, .t19_num_keys = ARRAY_SIZE(mxt_t19_keys), .t19_keymap = mxt_t19_keys, + .suspend_mode = MXT_SUSPEND_T9_CTRL, }; 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 = { .irqflags = IRQF_TRIGGER_FALLING, + .suspend_mode = MXT_SUSPEND_T9_CTRL, }; static struct i2c_board_info atmel_1664s_device = { diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/platform_data/atmel_mxt_ts.h similarity index 70% rename from include/linux/i2c/atmel_mxt_ts.h rename to include/linux/platform_data/atmel_mxt_ts.h index 02bf6ea31701..695035a8d7fb 100644 --- a/include/linux/i2c/atmel_mxt_ts.h +++ b/include/linux/platform_data/atmel_mxt_ts.h @@ -10,16 +10,22 @@ * 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 +enum mxt_suspend_mode { + MXT_SUSPEND_DEEP_SLEEP = 0, + MXT_SUSPEND_T9_CTRL = 1, +}; + /* 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; }; -#endif /* __LINUX_ATMEL_MXT_TS_H */ +#endif /* __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H */