Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Nick Dyer and committed by
Dmitry Torokhov
7f3884f7 7d6548ab

+120 -15
+108 -11
drivers/input/touchscreen/atmel_mxt_ts.c
··· 22 22 #include <linux/delay.h> 23 23 #include <linux/firmware.h> 24 24 #include <linux/i2c.h> 25 - #include <linux/i2c/atmel_mxt_ts.h> 25 + #include <linux/platform_data/atmel_mxt_ts.h> 26 26 #include <linux/input/mt.h> 27 27 #include <linux/interrupt.h> 28 28 #include <linux/of.h> ··· 103 103 #define MXT_T6_STATUS_COMSERR (1 << 2) 104 104 105 105 /* MXT_GEN_POWER_T7 field */ 106 - #define MXT_POWER_IDLEACQINT 0 107 - #define MXT_POWER_ACTVACQINT 1 108 - #define MXT_POWER_ACTV2IDLETO 2 106 + struct t7_config { 107 + u8 idle; 108 + u8 active; 109 + } __packed; 110 + 111 + #define MXT_POWER_CFG_RUN 0 112 + #define MXT_POWER_CFG_DEEPSLEEP 1 109 113 110 114 /* MXT_GEN_ACQUIRE_T8 field */ 111 115 #define MXT_ACQUIRE_CHRGTIME 0 ··· 121 117 #define MXT_ACQUIRE_ATCHCALSTHR 7 122 118 123 119 /* MXT_TOUCH_MULTI_T9 field */ 124 - #define MXT_TOUCH_CTRL 0 120 + #define MXT_T9_CTRL 0 125 121 #define MXT_T9_ORIENT 9 126 122 #define MXT_T9_RANGE 18 127 123 ··· 295 291 u8 last_message_count; 296 292 u8 num_touchids; 297 293 u8 multitouch; 294 + struct t7_config t7_cfg; 298 295 299 296 /* Cached parameters from object table */ 300 297 u16 T5_address; ··· 1366 1361 return 0; 1367 1362 } 1368 1363 1364 + static int mxt_init_t7_power_cfg(struct mxt_data *data); 1365 + 1369 1366 /* 1370 1367 * mxt_update_cfg - download configuration to chip 1371 1368 * ··· 1514 1507 goto release_mem; 1515 1508 1516 1509 dev_info(dev, "Config successfully updated\n"); 1510 + 1511 + /* T7 config may have changed */ 1512 + mxt_init_t7_power_cfg(data); 1517 1513 1518 1514 release_mem: 1519 1515 kfree(config_mem); ··· 2061 2051 return error; 2062 2052 } 2063 2053 2054 + static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep) 2055 + { 2056 + struct device *dev = &data->client->dev; 2057 + int error; 2058 + struct t7_config *new_config; 2059 + struct t7_config deepsleep = { .active = 0, .idle = 0 }; 2060 + 2061 + if (sleep == MXT_POWER_CFG_DEEPSLEEP) 2062 + new_config = &deepsleep; 2063 + else 2064 + new_config = &data->t7_cfg; 2065 + 2066 + error = __mxt_write_reg(data->client, data->T7_address, 2067 + sizeof(data->t7_cfg), new_config); 2068 + if (error) 2069 + return error; 2070 + 2071 + dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n", 2072 + new_config->active, new_config->idle); 2073 + 2074 + return 0; 2075 + } 2076 + 2077 + static int mxt_init_t7_power_cfg(struct mxt_data *data) 2078 + { 2079 + struct device *dev = &data->client->dev; 2080 + int error; 2081 + bool retry = false; 2082 + 2083 + recheck: 2084 + error = __mxt_read_reg(data->client, data->T7_address, 2085 + sizeof(data->t7_cfg), &data->t7_cfg); 2086 + if (error) 2087 + return error; 2088 + 2089 + if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) { 2090 + if (!retry) { 2091 + dev_dbg(dev, "T7 cfg zero, resetting\n"); 2092 + mxt_soft_reset(data); 2093 + retry = true; 2094 + goto recheck; 2095 + } else { 2096 + dev_dbg(dev, "T7 cfg zero after reset, overriding\n"); 2097 + data->t7_cfg.active = 20; 2098 + data->t7_cfg.idle = 100; 2099 + return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); 2100 + } 2101 + } 2102 + 2103 + dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n", 2104 + data->t7_cfg.active, data->t7_cfg.idle); 2105 + return 0; 2106 + } 2107 + 2064 2108 static int mxt_configure_objects(struct mxt_data *data, 2065 2109 const struct firmware *cfg) 2066 2110 { 2067 2111 struct device *dev = &data->client->dev; 2068 2112 struct mxt_info *info = &data->info; 2069 2113 int error; 2114 + 2115 + error = mxt_init_t7_power_cfg(data); 2116 + if (error) { 2117 + dev_err(dev, "Failed to initialize power cfg\n"); 2118 + return error; 2119 + } 2070 2120 2071 2121 if (cfg) { 2072 2122 error = mxt_update_cfg(data, cfg); ··· 2416 2346 2417 2347 static void mxt_start(struct mxt_data *data) 2418 2348 { 2419 - /* Touch enable */ 2420 - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0x83); 2349 + switch (data->pdata->suspend_mode) { 2350 + case MXT_SUSPEND_T9_CTRL: 2351 + mxt_soft_reset(data); 2352 + 2353 + /* Touch enable */ 2354 + /* 0x83 = SCANEN | RPTEN | ENABLE */ 2355 + mxt_write_object(data, 2356 + MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83); 2357 + break; 2358 + 2359 + case MXT_SUSPEND_DEEP_SLEEP: 2360 + default: 2361 + mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); 2362 + 2363 + /* Recalibrate since chip has been in deep sleep */ 2364 + mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); 2365 + break; 2366 + } 2367 + 2421 2368 } 2422 2369 2423 2370 static void mxt_stop(struct mxt_data *data) 2424 2371 { 2425 - /* Touch disable */ 2426 - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0); 2372 + switch (data->pdata->suspend_mode) { 2373 + case MXT_SUSPEND_T9_CTRL: 2374 + /* Touch disable */ 2375 + mxt_write_object(data, 2376 + MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0); 2377 + break; 2378 + 2379 + case MXT_SUSPEND_DEEP_SLEEP: 2380 + default: 2381 + mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP); 2382 + break; 2383 + } 2427 2384 } 2428 2385 2429 2386 static int mxt_input_open(struct input_dev *dev) ··· 2505 2408 2506 2409 pdata->t19_keymap = keymap; 2507 2410 } 2411 + 2412 + pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP; 2508 2413 2509 2414 return pdata; 2510 2415 } ··· 2723 2624 struct i2c_client *client = to_i2c_client(dev); 2724 2625 struct mxt_data *data = i2c_get_clientdata(client); 2725 2626 struct input_dev *input_dev = data->input_dev; 2726 - 2727 - mxt_soft_reset(data); 2728 2627 2729 2628 mutex_lock(&input_dev->mutex); 2730 2629
+3 -1
drivers/platform/chrome/chromeos_laptop.c
··· 23 23 24 24 #include <linux/dmi.h> 25 25 #include <linux/i2c.h> 26 - #include <linux/i2c/atmel_mxt_ts.h> 26 + #include <linux/platform_data/atmel_mxt_ts.h> 27 27 #include <linux/input.h> 28 28 #include <linux/interrupt.h> 29 29 #include <linux/module.h> ··· 111 111 .irqflags = IRQF_TRIGGER_FALLING, 112 112 .t19_num_keys = ARRAY_SIZE(mxt_t19_keys), 113 113 .t19_keymap = mxt_t19_keys, 114 + .suspend_mode = MXT_SUSPEND_T9_CTRL, 114 115 }; 115 116 116 117 static struct i2c_board_info atmel_224s_tp_device = { ··· 122 121 123 122 static struct mxt_platform_data atmel_1664s_platform_data = { 124 123 .irqflags = IRQF_TRIGGER_FALLING, 124 + .suspend_mode = MXT_SUSPEND_T9_CTRL, 125 125 }; 126 126 127 127 static struct i2c_board_info atmel_1664s_device = {
+9 -3
include/linux/i2c/atmel_mxt_ts.h include/linux/platform_data/atmel_mxt_ts.h
··· 10 10 * option) any later version. 11 11 */ 12 12 13 - #ifndef __LINUX_ATMEL_MXT_TS_H 14 - #define __LINUX_ATMEL_MXT_TS_H 13 + #ifndef __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H 14 + #define __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H 15 15 16 16 #include <linux/types.h> 17 + 18 + enum mxt_suspend_mode { 19 + MXT_SUSPEND_DEEP_SLEEP = 0, 20 + MXT_SUSPEND_T9_CTRL = 1, 21 + }; 17 22 18 23 /* The platform data for the Atmel maXTouch touchscreen driver */ 19 24 struct mxt_platform_data { 20 25 unsigned long irqflags; 21 26 u8 t19_num_keys; 22 27 const unsigned int *t19_keymap; 28 + enum mxt_suspend_mode suspend_mode; 23 29 }; 24 30 25 - #endif /* __LINUX_ATMEL_MXT_TS_H */ 31 + #endif /* __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H */