-
Notifications
You must be signed in to change notification settings - Fork 63
/
0033-CHROMIUM-Input-atmel_mxt_ts-Add-IDLE-DEEP-SLEEP-mode.patch
230 lines (208 loc) · 6.61 KB
/
0033-CHROMIUM-Input-atmel_mxt_ts-Add-IDLE-DEEP-SLEEP-mode.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
From b161fde6730e5d631ce404dde7ef11571fa3e3e6 Mon Sep 17 00:00:00 2001
From: Yufeng Shen <miletus@chromium.org>
Date: Fri, 4 May 2012 20:47:32 -0400
Subject: [PATCH 33/57] CHROMIUM: Input: atmel_mxt_ts - Add IDLE/DEEP-SLEEP
modes when suspend
Currently when system enters/leaves sleep mode, the driver dis/enables
T9 object. It has the limitation that 1) it does not allow the device
to wakeup the system 2) the device is not in it's best power saving mode
when the system is sleeping.
This patch adds the support to put the device into 1) Idle mode, when the
need of wakeup from sleep is needed 2) Deepsleep mode when wakeup from
sleep is not needed.
To achieve this, when the system enters sleep mode, the current T7 Power
Config value is first saved and then it is re-configured to be Idle mode
(with largest Idle Acquisition Interval and largest Active Acquisition
Interval) or Deepsleep mode. Also if wakeup from sleep is needed, the
current T9 Ctrl field is saved and a resonable value 0x03 is used to
enable T9 so that we can be sure touch contact will generate IRQ to wake
the system up.
When resume, before-suspend T7 and T9 values are restored accordingly.
BUG=chrome-os-partner:9413
TEST=On system with atmel trackpad
cd /sys/bus/i2c/drivers/atmel_mxt_ts/2-004b/power
echo "enabled" > wakeup
powerd_suspend
touch trackpad should wakeup the system
echo "disabled" > wakeup
powerd_suspend
touch trackpad should not wakeup the system
Change-Id: I85896691ddd69d854a923f548edf8b7d6caa9f8e
Signed-off-by: Yufeng Shen <miletus@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/21919
Reviewed-by: Benson Leung <bleung@chromium.org>
v3.7 rebase:
Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
---
drivers/input/touchscreen/atmel_mxt_ts.c | 134 +++++++++++++++++++++++++++++--
1 file changed, 127 insertions(+), 7 deletions(-)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1882e14..0804795 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -305,6 +305,20 @@ struct mxt_data {
struct mutex T37_buf_mutex;
u8 *T37_buf;
size_t T37_buf_size;
+
+ /* Saved T7 configuration
+ * [0] = IDLEACQINT
+ * [1] = ACTVACQINT
+ * [2] = ACTV2IDLETO
+ */
+ u8 T7_config[3];
+ bool T7_config_valid;
+
+ /* Saved T9 Ctrl field */
+ u8 T9_ctrl;
+ bool T9_ctrl_valid;
+
+ bool irq_wake; /* irq wake is enabled */
};
/* global root node of the atmel_mxt_ts debugfs directory. */
@@ -1824,6 +1838,44 @@ static int mxt_debugfs_init(struct mxt_data *mxt)
return 0;
}
+static int mxt_save_regs(struct mxt_data *data, u8 type, u8 instance,
+ u8 offset, u8 *val, u16 size)
+{
+ struct mxt_object *object;
+ u16 addr;
+ int ret;
+
+ object = mxt_get_object(data, type);
+ if (!object)
+ return -EINVAL;
+
+ addr = object->start_address + instance * mxt_obj_size(object) + offset;
+ ret = __mxt_read_reg(data->client, addr, size, val);
+ if (ret)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int mxt_set_regs(struct mxt_data *data, u8 type, u8 instance,
+ u8 offset, const u8 *val, u16 size)
+{
+ struct mxt_object *object;
+ u16 addr;
+ int ret;
+
+ object = mxt_get_object(data, type);
+ if (!object)
+ return -EINVAL;
+
+ addr = object->start_address + instance * mxt_obj_size(object) + offset;
+ ret = __mxt_write_reg(data->client, addr, size, val);
+ if (ret)
+ return -EINVAL;
+
+ return 0;
+}
+
static void mxt_start(struct mxt_data *data)
{
/* Touch enable */
@@ -2036,14 +2088,62 @@ static int mxt_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
+ static const u8 T7_config_idle[3] = { 0xfe, 0xfe, 0x00 };
+ static const u8 T7_config_deepsleep[3] = { 0x00, 0x00, 0x00 };
+ const u8 *power_config;
+ u8 T9_ctrl = 0x03;
+ int ret;
if (mxt_in_bootloader(data))
return 0;
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ /* Save 3 bytes T7 Power config */
+ ret = mxt_save_regs(data, MXT_GEN_POWER_T7, 0, 0,
+ data->T7_config, 3);
+ if (ret)
+ dev_err(dev, "Save T7 Power config failed, %d\n", ret);
+ data->T7_config_valid = (ret == 0);
+
+ /*
+ * Set T7 to idle mode if we allow wakeup from touch, otherwise
+ * put it into deepsleep mode.
+ */
+ power_config = device_may_wakeup(dev) ? T7_config_idle
+ : T7_config_deepsleep;
+
+ ret = mxt_set_regs(data, MXT_GEN_POWER_T7, 0, 0,
+ power_config, 3);
+ if (ret)
+ dev_err(dev, "Set T7 Power config failed, %d\n", ret);
+
+ if (device_may_wakeup(dev)) {
+ /*
+ * If we allow wakeup from touch, we have to enable T9 so
+ * that IRQ can be generated from touch
+ */
+
+ /* Save 1 byte T9 Ctrl config */
+ ret = mxt_save_regs(data, MXT_TOUCH_MULTI_T9, 0, 0,
+ &data->T9_ctrl, 1);
+ if (ret)
+ dev_err(dev, "Save T9 ctrl config failed, %d\n", ret);
+ data->T9_ctrl_valid = (ret == 0);
+
+ /* Enable T9 object */
+ ret = mxt_set_regs(data, MXT_TOUCH_MULTI_T9, 0, 0,
+ &T9_ctrl, 1);
+ if (ret)
+ dev_err(dev, "Set T9 ctrl config failed, %d\n", ret);
+
+ /* Enable wake from IRQ */
+ data->irq_wake = (enable_irq_wake(data->irq) == 0);
+ } else if (input_dev->users) {
mxt_stop(data);
+ }
+
+ disable_irq(data->irq);
mutex_unlock(&input_dev->mutex);
@@ -2055,20 +2155,40 @@ static int mxt_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
struct input_dev *input_dev = data->input_dev;
+ int ret;
if (mxt_in_bootloader(data))
return 0;
- /* Soft reset */
- mxt_write_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_RESET, 1);
-
- msleep(MXT_RESET_TIME);
+ /* Process any pending message so that CHG line can be de-asserted */
+ ret = mxt_handle_messages(data);
+ if (ret)
+ dev_err(dev, "Handling message fails upon resume, %d\n", ret);
mutex_lock(&input_dev->mutex);
- if (input_dev->users)
+ enable_irq(data->irq);
+
+ if (device_may_wakeup(dev) && data->irq_wake)
+ disable_irq_wake(data->irq);
+
+ /* Restore the T9 Ctrl config to before-suspend value */
+ if (device_may_wakeup(dev) && data->T9_ctrl_valid) {
+ ret = mxt_set_regs(data, MXT_TOUCH_MULTI_T9, 0, 0,
+ &data->T9_ctrl, 1);
+ if (ret)
+ dev_err(dev, "Set T9 ctrl config failed, %d\n", ret);
+ } else if (input_dev->users) {
mxt_start(data);
+ }
+
+ /* Restore the T7 Power config to before-suspend value */
+ if (data->T7_config_valid) {
+ ret = mxt_set_regs(data, MXT_GEN_POWER_T7, 0, 0,
+ data->T7_config, 3);
+ if (ret)
+ dev_err(dev, "Set T7 power config failed, %d\n", ret);
+ }
mutex_unlock(&input_dev->mutex);
--
1.8.2.1