Commit 875c69b2c37ba94f9e38d2c9211bd66f604ad7cc
1 parent
92e014a929
Exists in
smarc-ti-linux-3.14.y
and in
1 other branch
input: edt-ft5x06: Enable max axes values to be set in DT.
* The edt-ft5x06 driver sets max axes values to quantities much larger than what is actually obtainable. * Use the device tree to get the actual max values. Signed-off-by: Jacob Stiffler <j-stiffler@ti.com>
Showing 1 changed file with 20 additions and 6 deletions Inline Diff
drivers/input/touchscreen/edt-ft5x06.c
1 | /* | 1 | /* |
2 | * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de> | 2 | * Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de> |
3 | * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support) | 3 | * Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support) |
4 | * Lothar Waßmann <LW@KARO-electronics.de> (DT support) | 4 | * Lothar Waßmann <LW@KARO-electronics.de> (DT support) |
5 | * | 5 | * |
6 | * This software is licensed under the terms of the GNU General Public | 6 | * This software is licensed under the terms of the GNU General Public |
7 | * License version 2, as published by the Free Software Foundation, and | 7 | * License version 2, as published by the Free Software Foundation, and |
8 | * may be copied, distributed, and modified under those terms. | 8 | * may be copied, distributed, and modified under those terms. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public | 15 | * You should have received a copy of the GNU General Public |
16 | * License along with this library; if not, write to the Free Software | 16 | * License along with this library; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * This is a driver for the EDT "Polytouch" family of touch controllers | 21 | * This is a driver for the EDT "Polytouch" family of touch controllers |
22 | * based on the FocalTech FT5x06 line of chips. | 22 | * based on the FocalTech FT5x06 line of chips. |
23 | * | 23 | * |
24 | * Development of this driver has been sponsored by Glyn: | 24 | * Development of this driver has been sponsored by Glyn: |
25 | * http://www.glyn.com/Products/Displays | 25 | * http://www.glyn.com/Products/Displays |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/ratelimit.h> | 29 | #include <linux/ratelimit.h> |
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/input.h> | 31 | #include <linux/input.h> |
32 | #include <linux/i2c.h> | 32 | #include <linux/i2c.h> |
33 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
34 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
35 | #include <linux/debugfs.h> | 35 | #include <linux/debugfs.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/gpio.h> | 37 | #include <linux/gpio.h> |
38 | #include <linux/of_gpio.h> | 38 | #include <linux/of_gpio.h> |
39 | #include <linux/input/mt.h> | 39 | #include <linux/input/mt.h> |
40 | #include <linux/input/edt-ft5x06.h> | 40 | #include <linux/input/edt-ft5x06.h> |
41 | 41 | ||
42 | #define MAX_SUPPORT_POINTS 5 | 42 | #define MAX_SUPPORT_POINTS 5 |
43 | 43 | ||
44 | #define WORK_REGISTER_THRESHOLD 0x00 | 44 | #define WORK_REGISTER_THRESHOLD 0x00 |
45 | #define WORK_REGISTER_REPORT_RATE 0x08 | 45 | #define WORK_REGISTER_REPORT_RATE 0x08 |
46 | #define WORK_REGISTER_GAIN 0x30 | 46 | #define WORK_REGISTER_GAIN 0x30 |
47 | #define WORK_REGISTER_OFFSET 0x31 | 47 | #define WORK_REGISTER_OFFSET 0x31 |
48 | #define WORK_REGISTER_NUM_X 0x33 | 48 | #define WORK_REGISTER_NUM_X 0x33 |
49 | #define WORK_REGISTER_NUM_Y 0x34 | 49 | #define WORK_REGISTER_NUM_Y 0x34 |
50 | 50 | ||
51 | #define M09_REGISTER_THRESHOLD 0x80 | 51 | #define M09_REGISTER_THRESHOLD 0x80 |
52 | #define M09_REGISTER_GAIN 0x92 | 52 | #define M09_REGISTER_GAIN 0x92 |
53 | #define M09_REGISTER_OFFSET 0x93 | 53 | #define M09_REGISTER_OFFSET 0x93 |
54 | #define M09_REGISTER_NUM_X 0x94 | 54 | #define M09_REGISTER_NUM_X 0x94 |
55 | #define M09_REGISTER_NUM_Y 0x95 | 55 | #define M09_REGISTER_NUM_Y 0x95 |
56 | 56 | ||
57 | #define NO_REGISTER 0xff | 57 | #define NO_REGISTER 0xff |
58 | 58 | ||
59 | #define WORK_REGISTER_OPMODE 0x3c | 59 | #define WORK_REGISTER_OPMODE 0x3c |
60 | #define FACTORY_REGISTER_OPMODE 0x01 | 60 | #define FACTORY_REGISTER_OPMODE 0x01 |
61 | 61 | ||
62 | #define TOUCH_EVENT_DOWN 0x00 | 62 | #define TOUCH_EVENT_DOWN 0x00 |
63 | #define TOUCH_EVENT_UP 0x01 | 63 | #define TOUCH_EVENT_UP 0x01 |
64 | #define TOUCH_EVENT_ON 0x02 | 64 | #define TOUCH_EVENT_ON 0x02 |
65 | #define TOUCH_EVENT_RESERVED 0x03 | 65 | #define TOUCH_EVENT_RESERVED 0x03 |
66 | 66 | ||
67 | #define EDT_NAME_LEN 23 | 67 | #define EDT_NAME_LEN 23 |
68 | #define EDT_SWITCH_MODE_RETRIES 10 | 68 | #define EDT_SWITCH_MODE_RETRIES 10 |
69 | #define EDT_SWITCH_MODE_DELAY 5 /* msec */ | 69 | #define EDT_SWITCH_MODE_DELAY 5 /* msec */ |
70 | #define EDT_RAW_DATA_RETRIES 100 | 70 | #define EDT_RAW_DATA_RETRIES 100 |
71 | #define EDT_RAW_DATA_DELAY 1 /* msec */ | 71 | #define EDT_RAW_DATA_DELAY 1 /* msec */ |
72 | 72 | ||
73 | enum edt_ver { | 73 | enum edt_ver { |
74 | M06, | 74 | M06, |
75 | M09, | 75 | M09, |
76 | }; | 76 | }; |
77 | 77 | ||
78 | struct edt_reg_addr { | 78 | struct edt_reg_addr { |
79 | int reg_threshold; | 79 | int reg_threshold; |
80 | int reg_report_rate; | 80 | int reg_report_rate; |
81 | int reg_gain; | 81 | int reg_gain; |
82 | int reg_offset; | 82 | int reg_offset; |
83 | int reg_num_x; | 83 | int reg_num_x; |
84 | int reg_num_y; | 84 | int reg_num_y; |
85 | }; | 85 | }; |
86 | 86 | ||
87 | struct edt_ft5x06_ts_data { | 87 | struct edt_ft5x06_ts_data { |
88 | struct i2c_client *client; | 88 | struct i2c_client *client; |
89 | struct input_dev *input; | 89 | struct input_dev *input; |
90 | u16 num_x; | 90 | u16 num_x; |
91 | u16 num_y; | 91 | u16 num_y; |
92 | 92 | ||
93 | int reset_pin; | 93 | int reset_pin; |
94 | int irq_pin; | 94 | int irq_pin; |
95 | int wake_pin; | 95 | int wake_pin; |
96 | 96 | ||
97 | #if defined(CONFIG_DEBUG_FS) | 97 | #if defined(CONFIG_DEBUG_FS) |
98 | struct dentry *debug_dir; | 98 | struct dentry *debug_dir; |
99 | u8 *raw_buffer; | 99 | u8 *raw_buffer; |
100 | size_t raw_bufsize; | 100 | size_t raw_bufsize; |
101 | #endif | 101 | #endif |
102 | 102 | ||
103 | struct mutex mutex; | 103 | struct mutex mutex; |
104 | bool factory_mode; | 104 | bool factory_mode; |
105 | int threshold; | 105 | int threshold; |
106 | int gain; | 106 | int gain; |
107 | int offset; | 107 | int offset; |
108 | int report_rate; | 108 | int report_rate; |
109 | 109 | ||
110 | char name[EDT_NAME_LEN]; | 110 | char name[EDT_NAME_LEN]; |
111 | 111 | ||
112 | struct edt_reg_addr reg_addr; | 112 | struct edt_reg_addr reg_addr; |
113 | enum edt_ver version; | 113 | enum edt_ver version; |
114 | }; | 114 | }; |
115 | 115 | ||
116 | static int edt_ft5x06_ts_readwrite(struct i2c_client *client, | 116 | static int edt_ft5x06_ts_readwrite(struct i2c_client *client, |
117 | u16 wr_len, u8 *wr_buf, | 117 | u16 wr_len, u8 *wr_buf, |
118 | u16 rd_len, u8 *rd_buf) | 118 | u16 rd_len, u8 *rd_buf) |
119 | { | 119 | { |
120 | struct i2c_msg wrmsg[2]; | 120 | struct i2c_msg wrmsg[2]; |
121 | int i = 0; | 121 | int i = 0; |
122 | int ret; | 122 | int ret; |
123 | 123 | ||
124 | if (wr_len) { | 124 | if (wr_len) { |
125 | wrmsg[i].addr = client->addr; | 125 | wrmsg[i].addr = client->addr; |
126 | wrmsg[i].flags = 0; | 126 | wrmsg[i].flags = 0; |
127 | wrmsg[i].len = wr_len; | 127 | wrmsg[i].len = wr_len; |
128 | wrmsg[i].buf = wr_buf; | 128 | wrmsg[i].buf = wr_buf; |
129 | i++; | 129 | i++; |
130 | } | 130 | } |
131 | if (rd_len) { | 131 | if (rd_len) { |
132 | wrmsg[i].addr = client->addr; | 132 | wrmsg[i].addr = client->addr; |
133 | wrmsg[i].flags = I2C_M_RD; | 133 | wrmsg[i].flags = I2C_M_RD; |
134 | wrmsg[i].len = rd_len; | 134 | wrmsg[i].len = rd_len; |
135 | wrmsg[i].buf = rd_buf; | 135 | wrmsg[i].buf = rd_buf; |
136 | i++; | 136 | i++; |
137 | } | 137 | } |
138 | 138 | ||
139 | ret = i2c_transfer(client->adapter, wrmsg, i); | 139 | ret = i2c_transfer(client->adapter, wrmsg, i); |
140 | if (ret < 0) | 140 | if (ret < 0) |
141 | return ret; | 141 | return ret; |
142 | if (ret != i) | 142 | if (ret != i) |
143 | return -EIO; | 143 | return -EIO; |
144 | 144 | ||
145 | return 0; | 145 | return 0; |
146 | } | 146 | } |
147 | 147 | ||
148 | static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, | 148 | static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, |
149 | u8 *buf, int buflen) | 149 | u8 *buf, int buflen) |
150 | { | 150 | { |
151 | int i; | 151 | int i; |
152 | u8 crc = 0; | 152 | u8 crc = 0; |
153 | 153 | ||
154 | for (i = 0; i < buflen - 1; i++) | 154 | for (i = 0; i < buflen - 1; i++) |
155 | crc ^= buf[i]; | 155 | crc ^= buf[i]; |
156 | 156 | ||
157 | if (crc != buf[buflen-1]) { | 157 | if (crc != buf[buflen-1]) { |
158 | dev_err_ratelimited(&tsdata->client->dev, | 158 | dev_err_ratelimited(&tsdata->client->dev, |
159 | "crc error: 0x%02x expected, got 0x%02x\n", | 159 | "crc error: 0x%02x expected, got 0x%02x\n", |
160 | crc, buf[buflen-1]); | 160 | crc, buf[buflen-1]); |
161 | return false; | 161 | return false; |
162 | } | 162 | } |
163 | 163 | ||
164 | return true; | 164 | return true; |
165 | } | 165 | } |
166 | 166 | ||
167 | static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) | 167 | static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) |
168 | { | 168 | { |
169 | struct edt_ft5x06_ts_data *tsdata = dev_id; | 169 | struct edt_ft5x06_ts_data *tsdata = dev_id; |
170 | struct device *dev = &tsdata->client->dev; | 170 | struct device *dev = &tsdata->client->dev; |
171 | u8 cmd; | 171 | u8 cmd; |
172 | u8 rdbuf[29]; | 172 | u8 rdbuf[29]; |
173 | int i, type, x, y, id; | 173 | int i, type, x, y, id; |
174 | int offset, tplen, datalen; | 174 | int offset, tplen, datalen; |
175 | int error; | 175 | int error; |
176 | 176 | ||
177 | switch (tsdata->version) { | 177 | switch (tsdata->version) { |
178 | case M06: | 178 | case M06: |
179 | cmd = 0xf9; /* tell the controller to send touch data */ | 179 | cmd = 0xf9; /* tell the controller to send touch data */ |
180 | offset = 5; /* where the actual touch data starts */ | 180 | offset = 5; /* where the actual touch data starts */ |
181 | tplen = 4; /* data comes in so called frames */ | 181 | tplen = 4; /* data comes in so called frames */ |
182 | datalen = 26; /* how much bytes to listen for */ | 182 | datalen = 26; /* how much bytes to listen for */ |
183 | break; | 183 | break; |
184 | 184 | ||
185 | case M09: | 185 | case M09: |
186 | cmd = 0x02; | 186 | cmd = 0x02; |
187 | offset = 1; | 187 | offset = 1; |
188 | tplen = 6; | 188 | tplen = 6; |
189 | datalen = 29; | 189 | datalen = 29; |
190 | break; | 190 | break; |
191 | 191 | ||
192 | default: | 192 | default: |
193 | goto out; | 193 | goto out; |
194 | } | 194 | } |
195 | 195 | ||
196 | memset(rdbuf, 0, sizeof(rdbuf)); | 196 | memset(rdbuf, 0, sizeof(rdbuf)); |
197 | 197 | ||
198 | error = edt_ft5x06_ts_readwrite(tsdata->client, | 198 | error = edt_ft5x06_ts_readwrite(tsdata->client, |
199 | sizeof(cmd), &cmd, | 199 | sizeof(cmd), &cmd, |
200 | datalen, rdbuf); | 200 | datalen, rdbuf); |
201 | if (error) { | 201 | if (error) { |
202 | dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", | 202 | dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", |
203 | error); | 203 | error); |
204 | goto out; | 204 | goto out; |
205 | } | 205 | } |
206 | 206 | ||
207 | /* M09 does not send header or CRC */ | 207 | /* M09 does not send header or CRC */ |
208 | if (tsdata->version == M06) { | 208 | if (tsdata->version == M06) { |
209 | if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || | 209 | if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || |
210 | rdbuf[2] != datalen) { | 210 | rdbuf[2] != datalen) { |
211 | dev_err_ratelimited(dev, | 211 | dev_err_ratelimited(dev, |
212 | "Unexpected header: %02x%02x%02x!\n", | 212 | "Unexpected header: %02x%02x%02x!\n", |
213 | rdbuf[0], rdbuf[1], rdbuf[2]); | 213 | rdbuf[0], rdbuf[1], rdbuf[2]); |
214 | goto out; | 214 | goto out; |
215 | } | 215 | } |
216 | 216 | ||
217 | if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) | 217 | if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) |
218 | goto out; | 218 | goto out; |
219 | } | 219 | } |
220 | 220 | ||
221 | for (i = 0; i < MAX_SUPPORT_POINTS; i++) { | 221 | for (i = 0; i < MAX_SUPPORT_POINTS; i++) { |
222 | u8 *buf = &rdbuf[i * tplen + offset]; | 222 | u8 *buf = &rdbuf[i * tplen + offset]; |
223 | bool down; | 223 | bool down; |
224 | 224 | ||
225 | type = buf[0] >> 6; | 225 | type = buf[0] >> 6; |
226 | /* ignore Reserved events */ | 226 | /* ignore Reserved events */ |
227 | if (type == TOUCH_EVENT_RESERVED) | 227 | if (type == TOUCH_EVENT_RESERVED) |
228 | continue; | 228 | continue; |
229 | 229 | ||
230 | /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ | 230 | /* M06 sometimes sends bogus coordinates in TOUCH_DOWN */ |
231 | if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN) | 231 | if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN) |
232 | continue; | 232 | continue; |
233 | 233 | ||
234 | x = ((buf[0] << 8) | buf[1]) & 0x0fff; | 234 | x = ((buf[0] << 8) | buf[1]) & 0x0fff; |
235 | y = ((buf[2] << 8) | buf[3]) & 0x0fff; | 235 | y = ((buf[2] << 8) | buf[3]) & 0x0fff; |
236 | id = (buf[2] >> 4) & 0x0f; | 236 | id = (buf[2] >> 4) & 0x0f; |
237 | down = type != TOUCH_EVENT_UP; | 237 | down = type != TOUCH_EVENT_UP; |
238 | 238 | ||
239 | input_mt_slot(tsdata->input, id); | 239 | input_mt_slot(tsdata->input, id); |
240 | input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down); | 240 | input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down); |
241 | 241 | ||
242 | if (!down) | 242 | if (!down) |
243 | continue; | 243 | continue; |
244 | 244 | ||
245 | input_report_abs(tsdata->input, ABS_MT_POSITION_X, x); | 245 | input_report_abs(tsdata->input, ABS_MT_POSITION_X, x); |
246 | input_report_abs(tsdata->input, ABS_MT_POSITION_Y, y); | 246 | input_report_abs(tsdata->input, ABS_MT_POSITION_Y, y); |
247 | } | 247 | } |
248 | 248 | ||
249 | input_mt_report_pointer_emulation(tsdata->input, true); | 249 | input_mt_report_pointer_emulation(tsdata->input, true); |
250 | input_sync(tsdata->input); | 250 | input_sync(tsdata->input); |
251 | 251 | ||
252 | out: | 252 | out: |
253 | return IRQ_HANDLED; | 253 | return IRQ_HANDLED; |
254 | } | 254 | } |
255 | 255 | ||
256 | static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, | 256 | static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, |
257 | u8 addr, u8 value) | 257 | u8 addr, u8 value) |
258 | { | 258 | { |
259 | u8 wrbuf[4]; | 259 | u8 wrbuf[4]; |
260 | 260 | ||
261 | switch (tsdata->version) { | 261 | switch (tsdata->version) { |
262 | case M06: | 262 | case M06: |
263 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; | 263 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; |
264 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; | 264 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; |
265 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; | 265 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; |
266 | wrbuf[2] = value; | 266 | wrbuf[2] = value; |
267 | wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; | 267 | wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; |
268 | return edt_ft5x06_ts_readwrite(tsdata->client, 4, | 268 | return edt_ft5x06_ts_readwrite(tsdata->client, 4, |
269 | wrbuf, 0, NULL); | 269 | wrbuf, 0, NULL); |
270 | case M09: | 270 | case M09: |
271 | wrbuf[0] = addr; | 271 | wrbuf[0] = addr; |
272 | wrbuf[1] = value; | 272 | wrbuf[1] = value; |
273 | 273 | ||
274 | return edt_ft5x06_ts_readwrite(tsdata->client, 2, | 274 | return edt_ft5x06_ts_readwrite(tsdata->client, 2, |
275 | wrbuf, 0, NULL); | 275 | wrbuf, 0, NULL); |
276 | 276 | ||
277 | default: | 277 | default: |
278 | return -EINVAL; | 278 | return -EINVAL; |
279 | } | 279 | } |
280 | } | 280 | } |
281 | 281 | ||
282 | static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, | 282 | static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, |
283 | u8 addr) | 283 | u8 addr) |
284 | { | 284 | { |
285 | u8 wrbuf[2], rdbuf[2]; | 285 | u8 wrbuf[2], rdbuf[2]; |
286 | int error; | 286 | int error; |
287 | 287 | ||
288 | switch (tsdata->version) { | 288 | switch (tsdata->version) { |
289 | case M06: | 289 | case M06: |
290 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; | 290 | wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; |
291 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; | 291 | wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; |
292 | wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; | 292 | wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; |
293 | 293 | ||
294 | error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, | 294 | error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, |
295 | rdbuf); | 295 | rdbuf); |
296 | if (error) | 296 | if (error) |
297 | return error; | 297 | return error; |
298 | 298 | ||
299 | if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { | 299 | if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { |
300 | dev_err(&tsdata->client->dev, | 300 | dev_err(&tsdata->client->dev, |
301 | "crc error: 0x%02x expected, got 0x%02x\n", | 301 | "crc error: 0x%02x expected, got 0x%02x\n", |
302 | wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], | 302 | wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], |
303 | rdbuf[1]); | 303 | rdbuf[1]); |
304 | return -EIO; | 304 | return -EIO; |
305 | } | 305 | } |
306 | break; | 306 | break; |
307 | 307 | ||
308 | case M09: | 308 | case M09: |
309 | wrbuf[0] = addr; | 309 | wrbuf[0] = addr; |
310 | error = edt_ft5x06_ts_readwrite(tsdata->client, 1, | 310 | error = edt_ft5x06_ts_readwrite(tsdata->client, 1, |
311 | wrbuf, 1, rdbuf); | 311 | wrbuf, 1, rdbuf); |
312 | if (error) | 312 | if (error) |
313 | return error; | 313 | return error; |
314 | break; | 314 | break; |
315 | 315 | ||
316 | default: | 316 | default: |
317 | return -EINVAL; | 317 | return -EINVAL; |
318 | } | 318 | } |
319 | 319 | ||
320 | return rdbuf[0]; | 320 | return rdbuf[0]; |
321 | } | 321 | } |
322 | 322 | ||
323 | struct edt_ft5x06_attribute { | 323 | struct edt_ft5x06_attribute { |
324 | struct device_attribute dattr; | 324 | struct device_attribute dattr; |
325 | size_t field_offset; | 325 | size_t field_offset; |
326 | u8 limit_low; | 326 | u8 limit_low; |
327 | u8 limit_high; | 327 | u8 limit_high; |
328 | u8 addr_m06; | 328 | u8 addr_m06; |
329 | u8 addr_m09; | 329 | u8 addr_m09; |
330 | }; | 330 | }; |
331 | 331 | ||
332 | #define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \ | 332 | #define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \ |
333 | _limit_low, _limit_high) \ | 333 | _limit_low, _limit_high) \ |
334 | struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ | 334 | struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = { \ |
335 | .dattr = __ATTR(_field, _mode, \ | 335 | .dattr = __ATTR(_field, _mode, \ |
336 | edt_ft5x06_setting_show, \ | 336 | edt_ft5x06_setting_show, \ |
337 | edt_ft5x06_setting_store), \ | 337 | edt_ft5x06_setting_store), \ |
338 | .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ | 338 | .field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \ |
339 | .addr_m06 = _addr_m06, \ | 339 | .addr_m06 = _addr_m06, \ |
340 | .addr_m09 = _addr_m09, \ | 340 | .addr_m09 = _addr_m09, \ |
341 | .limit_low = _limit_low, \ | 341 | .limit_low = _limit_low, \ |
342 | .limit_high = _limit_high, \ | 342 | .limit_high = _limit_high, \ |
343 | } | 343 | } |
344 | 344 | ||
345 | static ssize_t edt_ft5x06_setting_show(struct device *dev, | 345 | static ssize_t edt_ft5x06_setting_show(struct device *dev, |
346 | struct device_attribute *dattr, | 346 | struct device_attribute *dattr, |
347 | char *buf) | 347 | char *buf) |
348 | { | 348 | { |
349 | struct i2c_client *client = to_i2c_client(dev); | 349 | struct i2c_client *client = to_i2c_client(dev); |
350 | struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); | 350 | struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); |
351 | struct edt_ft5x06_attribute *attr = | 351 | struct edt_ft5x06_attribute *attr = |
352 | container_of(dattr, struct edt_ft5x06_attribute, dattr); | 352 | container_of(dattr, struct edt_ft5x06_attribute, dattr); |
353 | u8 *field = (u8 *)tsdata + attr->field_offset; | 353 | u8 *field = (u8 *)tsdata + attr->field_offset; |
354 | int val; | 354 | int val; |
355 | size_t count = 0; | 355 | size_t count = 0; |
356 | int error = 0; | 356 | int error = 0; |
357 | u8 addr; | 357 | u8 addr; |
358 | 358 | ||
359 | mutex_lock(&tsdata->mutex); | 359 | mutex_lock(&tsdata->mutex); |
360 | 360 | ||
361 | if (tsdata->factory_mode) { | 361 | if (tsdata->factory_mode) { |
362 | error = -EIO; | 362 | error = -EIO; |
363 | goto out; | 363 | goto out; |
364 | } | 364 | } |
365 | 365 | ||
366 | switch (tsdata->version) { | 366 | switch (tsdata->version) { |
367 | case M06: | 367 | case M06: |
368 | addr = attr->addr_m06; | 368 | addr = attr->addr_m06; |
369 | break; | 369 | break; |
370 | 370 | ||
371 | case M09: | 371 | case M09: |
372 | addr = attr->addr_m09; | 372 | addr = attr->addr_m09; |
373 | break; | 373 | break; |
374 | 374 | ||
375 | default: | 375 | default: |
376 | error = -ENODEV; | 376 | error = -ENODEV; |
377 | goto out; | 377 | goto out; |
378 | } | 378 | } |
379 | 379 | ||
380 | if (addr != NO_REGISTER) { | 380 | if (addr != NO_REGISTER) { |
381 | val = edt_ft5x06_register_read(tsdata, addr); | 381 | val = edt_ft5x06_register_read(tsdata, addr); |
382 | if (val < 0) { | 382 | if (val < 0) { |
383 | error = val; | 383 | error = val; |
384 | dev_err(&tsdata->client->dev, | 384 | dev_err(&tsdata->client->dev, |
385 | "Failed to fetch attribute %s, error %d\n", | 385 | "Failed to fetch attribute %s, error %d\n", |
386 | dattr->attr.name, error); | 386 | dattr->attr.name, error); |
387 | goto out; | 387 | goto out; |
388 | } | 388 | } |
389 | } else { | 389 | } else { |
390 | val = *field; | 390 | val = *field; |
391 | } | 391 | } |
392 | 392 | ||
393 | if (val != *field) { | 393 | if (val != *field) { |
394 | dev_warn(&tsdata->client->dev, | 394 | dev_warn(&tsdata->client->dev, |
395 | "%s: read (%d) and stored value (%d) differ\n", | 395 | "%s: read (%d) and stored value (%d) differ\n", |
396 | dattr->attr.name, val, *field); | 396 | dattr->attr.name, val, *field); |
397 | *field = val; | 397 | *field = val; |
398 | } | 398 | } |
399 | 399 | ||
400 | count = scnprintf(buf, PAGE_SIZE, "%d\n", val); | 400 | count = scnprintf(buf, PAGE_SIZE, "%d\n", val); |
401 | out: | 401 | out: |
402 | mutex_unlock(&tsdata->mutex); | 402 | mutex_unlock(&tsdata->mutex); |
403 | return error ?: count; | 403 | return error ?: count; |
404 | } | 404 | } |
405 | 405 | ||
406 | static ssize_t edt_ft5x06_setting_store(struct device *dev, | 406 | static ssize_t edt_ft5x06_setting_store(struct device *dev, |
407 | struct device_attribute *dattr, | 407 | struct device_attribute *dattr, |
408 | const char *buf, size_t count) | 408 | const char *buf, size_t count) |
409 | { | 409 | { |
410 | struct i2c_client *client = to_i2c_client(dev); | 410 | struct i2c_client *client = to_i2c_client(dev); |
411 | struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); | 411 | struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); |
412 | struct edt_ft5x06_attribute *attr = | 412 | struct edt_ft5x06_attribute *attr = |
413 | container_of(dattr, struct edt_ft5x06_attribute, dattr); | 413 | container_of(dattr, struct edt_ft5x06_attribute, dattr); |
414 | u8 *field = (u8 *)tsdata + attr->field_offset; | 414 | u8 *field = (u8 *)tsdata + attr->field_offset; |
415 | unsigned int val; | 415 | unsigned int val; |
416 | int error; | 416 | int error; |
417 | u8 addr; | 417 | u8 addr; |
418 | 418 | ||
419 | mutex_lock(&tsdata->mutex); | 419 | mutex_lock(&tsdata->mutex); |
420 | 420 | ||
421 | if (tsdata->factory_mode) { | 421 | if (tsdata->factory_mode) { |
422 | error = -EIO; | 422 | error = -EIO; |
423 | goto out; | 423 | goto out; |
424 | } | 424 | } |
425 | 425 | ||
426 | error = kstrtouint(buf, 0, &val); | 426 | error = kstrtouint(buf, 0, &val); |
427 | if (error) | 427 | if (error) |
428 | goto out; | 428 | goto out; |
429 | 429 | ||
430 | if (val < attr->limit_low || val > attr->limit_high) { | 430 | if (val < attr->limit_low || val > attr->limit_high) { |
431 | error = -ERANGE; | 431 | error = -ERANGE; |
432 | goto out; | 432 | goto out; |
433 | } | 433 | } |
434 | 434 | ||
435 | switch (tsdata->version) { | 435 | switch (tsdata->version) { |
436 | case M06: | 436 | case M06: |
437 | addr = attr->addr_m06; | 437 | addr = attr->addr_m06; |
438 | break; | 438 | break; |
439 | 439 | ||
440 | case M09: | 440 | case M09: |
441 | addr = attr->addr_m09; | 441 | addr = attr->addr_m09; |
442 | break; | 442 | break; |
443 | 443 | ||
444 | default: | 444 | default: |
445 | error = -ENODEV; | 445 | error = -ENODEV; |
446 | goto out; | 446 | goto out; |
447 | } | 447 | } |
448 | 448 | ||
449 | if (addr != NO_REGISTER) { | 449 | if (addr != NO_REGISTER) { |
450 | error = edt_ft5x06_register_write(tsdata, addr, val); | 450 | error = edt_ft5x06_register_write(tsdata, addr, val); |
451 | if (error) { | 451 | if (error) { |
452 | dev_err(&tsdata->client->dev, | 452 | dev_err(&tsdata->client->dev, |
453 | "Failed to update attribute %s, error: %d\n", | 453 | "Failed to update attribute %s, error: %d\n", |
454 | dattr->attr.name, error); | 454 | dattr->attr.name, error); |
455 | goto out; | 455 | goto out; |
456 | } | 456 | } |
457 | } | 457 | } |
458 | *field = val; | 458 | *field = val; |
459 | 459 | ||
460 | out: | 460 | out: |
461 | mutex_unlock(&tsdata->mutex); | 461 | mutex_unlock(&tsdata->mutex); |
462 | return error ?: count; | 462 | return error ?: count; |
463 | } | 463 | } |
464 | 464 | ||
465 | static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, | 465 | static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN, |
466 | M09_REGISTER_GAIN, 0, 31); | 466 | M09_REGISTER_GAIN, 0, 31); |
467 | static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, | 467 | static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET, |
468 | M09_REGISTER_OFFSET, 0, 31); | 468 | M09_REGISTER_OFFSET, 0, 31); |
469 | static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, | 469 | static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD, |
470 | M09_REGISTER_THRESHOLD, 20, 80); | 470 | M09_REGISTER_THRESHOLD, 20, 80); |
471 | static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, | 471 | static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, |
472 | NO_REGISTER, 3, 14); | 472 | NO_REGISTER, 3, 14); |
473 | 473 | ||
474 | static struct attribute *edt_ft5x06_attrs[] = { | 474 | static struct attribute *edt_ft5x06_attrs[] = { |
475 | &edt_ft5x06_attr_gain.dattr.attr, | 475 | &edt_ft5x06_attr_gain.dattr.attr, |
476 | &edt_ft5x06_attr_offset.dattr.attr, | 476 | &edt_ft5x06_attr_offset.dattr.attr, |
477 | &edt_ft5x06_attr_threshold.dattr.attr, | 477 | &edt_ft5x06_attr_threshold.dattr.attr, |
478 | &edt_ft5x06_attr_report_rate.dattr.attr, | 478 | &edt_ft5x06_attr_report_rate.dattr.attr, |
479 | NULL | 479 | NULL |
480 | }; | 480 | }; |
481 | 481 | ||
482 | static const struct attribute_group edt_ft5x06_attr_group = { | 482 | static const struct attribute_group edt_ft5x06_attr_group = { |
483 | .attrs = edt_ft5x06_attrs, | 483 | .attrs = edt_ft5x06_attrs, |
484 | }; | 484 | }; |
485 | 485 | ||
486 | #ifdef CONFIG_DEBUG_FS | 486 | #ifdef CONFIG_DEBUG_FS |
487 | static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) | 487 | static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) |
488 | { | 488 | { |
489 | struct i2c_client *client = tsdata->client; | 489 | struct i2c_client *client = tsdata->client; |
490 | int retries = EDT_SWITCH_MODE_RETRIES; | 490 | int retries = EDT_SWITCH_MODE_RETRIES; |
491 | int ret; | 491 | int ret; |
492 | int error; | 492 | int error; |
493 | 493 | ||
494 | disable_irq(client->irq); | 494 | disable_irq(client->irq); |
495 | 495 | ||
496 | if (!tsdata->raw_buffer) { | 496 | if (!tsdata->raw_buffer) { |
497 | tsdata->raw_bufsize = tsdata->num_x * tsdata->num_y * | 497 | tsdata->raw_bufsize = tsdata->num_x * tsdata->num_y * |
498 | sizeof(u16); | 498 | sizeof(u16); |
499 | tsdata->raw_buffer = kzalloc(tsdata->raw_bufsize, GFP_KERNEL); | 499 | tsdata->raw_buffer = kzalloc(tsdata->raw_bufsize, GFP_KERNEL); |
500 | if (!tsdata->raw_buffer) { | 500 | if (!tsdata->raw_buffer) { |
501 | error = -ENOMEM; | 501 | error = -ENOMEM; |
502 | goto err_out; | 502 | goto err_out; |
503 | } | 503 | } |
504 | } | 504 | } |
505 | 505 | ||
506 | /* mode register is 0x3c when in the work mode */ | 506 | /* mode register is 0x3c when in the work mode */ |
507 | if (tsdata->version == M09) | 507 | if (tsdata->version == M09) |
508 | goto m09_out; | 508 | goto m09_out; |
509 | 509 | ||
510 | error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); | 510 | error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); |
511 | if (error) { | 511 | if (error) { |
512 | dev_err(&client->dev, | 512 | dev_err(&client->dev, |
513 | "failed to switch to factory mode, error %d\n", error); | 513 | "failed to switch to factory mode, error %d\n", error); |
514 | goto err_out; | 514 | goto err_out; |
515 | } | 515 | } |
516 | 516 | ||
517 | tsdata->factory_mode = true; | 517 | tsdata->factory_mode = true; |
518 | do { | 518 | do { |
519 | mdelay(EDT_SWITCH_MODE_DELAY); | 519 | mdelay(EDT_SWITCH_MODE_DELAY); |
520 | /* mode register is 0x01 when in factory mode */ | 520 | /* mode register is 0x01 when in factory mode */ |
521 | ret = edt_ft5x06_register_read(tsdata, FACTORY_REGISTER_OPMODE); | 521 | ret = edt_ft5x06_register_read(tsdata, FACTORY_REGISTER_OPMODE); |
522 | if (ret == 0x03) | 522 | if (ret == 0x03) |
523 | break; | 523 | break; |
524 | } while (--retries > 0); | 524 | } while (--retries > 0); |
525 | 525 | ||
526 | if (retries == 0) { | 526 | if (retries == 0) { |
527 | dev_err(&client->dev, "not in factory mode after %dms.\n", | 527 | dev_err(&client->dev, "not in factory mode after %dms.\n", |
528 | EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); | 528 | EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); |
529 | error = -EIO; | 529 | error = -EIO; |
530 | goto err_out; | 530 | goto err_out; |
531 | } | 531 | } |
532 | 532 | ||
533 | return 0; | 533 | return 0; |
534 | 534 | ||
535 | err_out: | 535 | err_out: |
536 | kfree(tsdata->raw_buffer); | 536 | kfree(tsdata->raw_buffer); |
537 | tsdata->raw_buffer = NULL; | 537 | tsdata->raw_buffer = NULL; |
538 | tsdata->factory_mode = false; | 538 | tsdata->factory_mode = false; |
539 | enable_irq(client->irq); | 539 | enable_irq(client->irq); |
540 | 540 | ||
541 | return error; | 541 | return error; |
542 | 542 | ||
543 | m09_out: | 543 | m09_out: |
544 | dev_err(&client->dev, "No factory mode support for M09\n"); | 544 | dev_err(&client->dev, "No factory mode support for M09\n"); |
545 | return -EINVAL; | 545 | return -EINVAL; |
546 | 546 | ||
547 | } | 547 | } |
548 | 548 | ||
549 | static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) | 549 | static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) |
550 | { | 550 | { |
551 | struct i2c_client *client = tsdata->client; | 551 | struct i2c_client *client = tsdata->client; |
552 | int retries = EDT_SWITCH_MODE_RETRIES; | 552 | int retries = EDT_SWITCH_MODE_RETRIES; |
553 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | 553 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; |
554 | int ret; | 554 | int ret; |
555 | int error; | 555 | int error; |
556 | 556 | ||
557 | /* mode register is 0x01 when in the factory mode */ | 557 | /* mode register is 0x01 when in the factory mode */ |
558 | error = edt_ft5x06_register_write(tsdata, FACTORY_REGISTER_OPMODE, 0x1); | 558 | error = edt_ft5x06_register_write(tsdata, FACTORY_REGISTER_OPMODE, 0x1); |
559 | if (error) { | 559 | if (error) { |
560 | dev_err(&client->dev, | 560 | dev_err(&client->dev, |
561 | "failed to switch to work mode, error: %d\n", error); | 561 | "failed to switch to work mode, error: %d\n", error); |
562 | return error; | 562 | return error; |
563 | } | 563 | } |
564 | 564 | ||
565 | tsdata->factory_mode = false; | 565 | tsdata->factory_mode = false; |
566 | 566 | ||
567 | do { | 567 | do { |
568 | mdelay(EDT_SWITCH_MODE_DELAY); | 568 | mdelay(EDT_SWITCH_MODE_DELAY); |
569 | /* mode register is 0x01 when in factory mode */ | 569 | /* mode register is 0x01 when in factory mode */ |
570 | ret = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OPMODE); | 570 | ret = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OPMODE); |
571 | if (ret == 0x01) | 571 | if (ret == 0x01) |
572 | break; | 572 | break; |
573 | } while (--retries > 0); | 573 | } while (--retries > 0); |
574 | 574 | ||
575 | if (retries == 0) { | 575 | if (retries == 0) { |
576 | dev_err(&client->dev, "not in work mode after %dms.\n", | 576 | dev_err(&client->dev, "not in work mode after %dms.\n", |
577 | EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); | 577 | EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); |
578 | tsdata->factory_mode = true; | 578 | tsdata->factory_mode = true; |
579 | return -EIO; | 579 | return -EIO; |
580 | } | 580 | } |
581 | 581 | ||
582 | kfree(tsdata->raw_buffer); | 582 | kfree(tsdata->raw_buffer); |
583 | tsdata->raw_buffer = NULL; | 583 | tsdata->raw_buffer = NULL; |
584 | 584 | ||
585 | /* restore parameters */ | 585 | /* restore parameters */ |
586 | edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, | 586 | edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, |
587 | tsdata->threshold); | 587 | tsdata->threshold); |
588 | edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, | 588 | edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, |
589 | tsdata->gain); | 589 | tsdata->gain); |
590 | edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, | 590 | edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, |
591 | tsdata->offset); | 591 | tsdata->offset); |
592 | if (reg_addr->reg_report_rate) | 592 | if (reg_addr->reg_report_rate) |
593 | edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, | 593 | edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, |
594 | tsdata->report_rate); | 594 | tsdata->report_rate); |
595 | 595 | ||
596 | enable_irq(client->irq); | 596 | enable_irq(client->irq); |
597 | 597 | ||
598 | return 0; | 598 | return 0; |
599 | } | 599 | } |
600 | 600 | ||
601 | static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode) | 601 | static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode) |
602 | { | 602 | { |
603 | struct edt_ft5x06_ts_data *tsdata = data; | 603 | struct edt_ft5x06_ts_data *tsdata = data; |
604 | 604 | ||
605 | *mode = tsdata->factory_mode; | 605 | *mode = tsdata->factory_mode; |
606 | 606 | ||
607 | return 0; | 607 | return 0; |
608 | }; | 608 | }; |
609 | 609 | ||
610 | static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode) | 610 | static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode) |
611 | { | 611 | { |
612 | struct edt_ft5x06_ts_data *tsdata = data; | 612 | struct edt_ft5x06_ts_data *tsdata = data; |
613 | int retval = 0; | 613 | int retval = 0; |
614 | 614 | ||
615 | if (mode > 1) | 615 | if (mode > 1) |
616 | return -ERANGE; | 616 | return -ERANGE; |
617 | 617 | ||
618 | mutex_lock(&tsdata->mutex); | 618 | mutex_lock(&tsdata->mutex); |
619 | 619 | ||
620 | if (mode != tsdata->factory_mode) { | 620 | if (mode != tsdata->factory_mode) { |
621 | retval = mode ? edt_ft5x06_factory_mode(tsdata) : | 621 | retval = mode ? edt_ft5x06_factory_mode(tsdata) : |
622 | edt_ft5x06_work_mode(tsdata); | 622 | edt_ft5x06_work_mode(tsdata); |
623 | } | 623 | } |
624 | 624 | ||
625 | mutex_unlock(&tsdata->mutex); | 625 | mutex_unlock(&tsdata->mutex); |
626 | 626 | ||
627 | return retval; | 627 | return retval; |
628 | }; | 628 | }; |
629 | 629 | ||
630 | DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get, | 630 | DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get, |
631 | edt_ft5x06_debugfs_mode_set, "%llu\n"); | 631 | edt_ft5x06_debugfs_mode_set, "%llu\n"); |
632 | 632 | ||
633 | static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, | 633 | static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, |
634 | char __user *buf, size_t count, loff_t *off) | 634 | char __user *buf, size_t count, loff_t *off) |
635 | { | 635 | { |
636 | struct edt_ft5x06_ts_data *tsdata = file->private_data; | 636 | struct edt_ft5x06_ts_data *tsdata = file->private_data; |
637 | struct i2c_client *client = tsdata->client; | 637 | struct i2c_client *client = tsdata->client; |
638 | int retries = EDT_RAW_DATA_RETRIES; | 638 | int retries = EDT_RAW_DATA_RETRIES; |
639 | int val, i, error; | 639 | int val, i, error; |
640 | size_t read = 0; | 640 | size_t read = 0; |
641 | int colbytes; | 641 | int colbytes; |
642 | char wrbuf[3]; | 642 | char wrbuf[3]; |
643 | u8 *rdbuf; | 643 | u8 *rdbuf; |
644 | 644 | ||
645 | if (*off < 0 || *off >= tsdata->raw_bufsize) | 645 | if (*off < 0 || *off >= tsdata->raw_bufsize) |
646 | return 0; | 646 | return 0; |
647 | 647 | ||
648 | mutex_lock(&tsdata->mutex); | 648 | mutex_lock(&tsdata->mutex); |
649 | 649 | ||
650 | if (!tsdata->factory_mode || !tsdata->raw_buffer) { | 650 | if (!tsdata->factory_mode || !tsdata->raw_buffer) { |
651 | error = -EIO; | 651 | error = -EIO; |
652 | goto out; | 652 | goto out; |
653 | } | 653 | } |
654 | 654 | ||
655 | error = edt_ft5x06_register_write(tsdata, 0x08, 0x01); | 655 | error = edt_ft5x06_register_write(tsdata, 0x08, 0x01); |
656 | if (error) { | 656 | if (error) { |
657 | dev_dbg(&client->dev, | 657 | dev_dbg(&client->dev, |
658 | "failed to write 0x08 register, error %d\n", error); | 658 | "failed to write 0x08 register, error %d\n", error); |
659 | goto out; | 659 | goto out; |
660 | } | 660 | } |
661 | 661 | ||
662 | do { | 662 | do { |
663 | msleep(EDT_RAW_DATA_DELAY); | 663 | msleep(EDT_RAW_DATA_DELAY); |
664 | val = edt_ft5x06_register_read(tsdata, 0x08); | 664 | val = edt_ft5x06_register_read(tsdata, 0x08); |
665 | if (val < 1) | 665 | if (val < 1) |
666 | break; | 666 | break; |
667 | } while (--retries > 0); | 667 | } while (--retries > 0); |
668 | 668 | ||
669 | if (val < 0) { | 669 | if (val < 0) { |
670 | error = val; | 670 | error = val; |
671 | dev_dbg(&client->dev, | 671 | dev_dbg(&client->dev, |
672 | "failed to read 0x08 register, error %d\n", error); | 672 | "failed to read 0x08 register, error %d\n", error); |
673 | goto out; | 673 | goto out; |
674 | } | 674 | } |
675 | 675 | ||
676 | if (retries == 0) { | 676 | if (retries == 0) { |
677 | dev_dbg(&client->dev, | 677 | dev_dbg(&client->dev, |
678 | "timed out waiting for register to settle\n"); | 678 | "timed out waiting for register to settle\n"); |
679 | error = -ETIMEDOUT; | 679 | error = -ETIMEDOUT; |
680 | goto out; | 680 | goto out; |
681 | } | 681 | } |
682 | 682 | ||
683 | rdbuf = tsdata->raw_buffer; | 683 | rdbuf = tsdata->raw_buffer; |
684 | colbytes = tsdata->num_y * sizeof(u16); | 684 | colbytes = tsdata->num_y * sizeof(u16); |
685 | 685 | ||
686 | wrbuf[0] = 0xf5; | 686 | wrbuf[0] = 0xf5; |
687 | wrbuf[1] = 0x0e; | 687 | wrbuf[1] = 0x0e; |
688 | for (i = 0; i < tsdata->num_x; i++) { | 688 | for (i = 0; i < tsdata->num_x; i++) { |
689 | wrbuf[2] = i; /* column index */ | 689 | wrbuf[2] = i; /* column index */ |
690 | error = edt_ft5x06_ts_readwrite(tsdata->client, | 690 | error = edt_ft5x06_ts_readwrite(tsdata->client, |
691 | sizeof(wrbuf), wrbuf, | 691 | sizeof(wrbuf), wrbuf, |
692 | colbytes, rdbuf); | 692 | colbytes, rdbuf); |
693 | if (error) | 693 | if (error) |
694 | goto out; | 694 | goto out; |
695 | 695 | ||
696 | rdbuf += colbytes; | 696 | rdbuf += colbytes; |
697 | } | 697 | } |
698 | 698 | ||
699 | read = min_t(size_t, count, tsdata->raw_bufsize - *off); | 699 | read = min_t(size_t, count, tsdata->raw_bufsize - *off); |
700 | if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) { | 700 | if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) { |
701 | error = -EFAULT; | 701 | error = -EFAULT; |
702 | goto out; | 702 | goto out; |
703 | } | 703 | } |
704 | 704 | ||
705 | *off += read; | 705 | *off += read; |
706 | out: | 706 | out: |
707 | mutex_unlock(&tsdata->mutex); | 707 | mutex_unlock(&tsdata->mutex); |
708 | return error ?: read; | 708 | return error ?: read; |
709 | }; | 709 | }; |
710 | 710 | ||
711 | static const struct file_operations debugfs_raw_data_fops = { | 711 | static const struct file_operations debugfs_raw_data_fops = { |
712 | .open = simple_open, | 712 | .open = simple_open, |
713 | .read = edt_ft5x06_debugfs_raw_data_read, | 713 | .read = edt_ft5x06_debugfs_raw_data_read, |
714 | }; | 714 | }; |
715 | 715 | ||
716 | static void | 716 | static void |
717 | edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, | 717 | edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, |
718 | const char *debugfs_name) | 718 | const char *debugfs_name) |
719 | { | 719 | { |
720 | tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL); | 720 | tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL); |
721 | if (!tsdata->debug_dir) | 721 | if (!tsdata->debug_dir) |
722 | return; | 722 | return; |
723 | 723 | ||
724 | debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x); | 724 | debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x); |
725 | debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y); | 725 | debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y); |
726 | 726 | ||
727 | debugfs_create_file("mode", S_IRUSR | S_IWUSR, | 727 | debugfs_create_file("mode", S_IRUSR | S_IWUSR, |
728 | tsdata->debug_dir, tsdata, &debugfs_mode_fops); | 728 | tsdata->debug_dir, tsdata, &debugfs_mode_fops); |
729 | debugfs_create_file("raw_data", S_IRUSR, | 729 | debugfs_create_file("raw_data", S_IRUSR, |
730 | tsdata->debug_dir, tsdata, &debugfs_raw_data_fops); | 730 | tsdata->debug_dir, tsdata, &debugfs_raw_data_fops); |
731 | } | 731 | } |
732 | 732 | ||
733 | static void | 733 | static void |
734 | edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) | 734 | edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) |
735 | { | 735 | { |
736 | if (tsdata->debug_dir) | 736 | if (tsdata->debug_dir) |
737 | debugfs_remove_recursive(tsdata->debug_dir); | 737 | debugfs_remove_recursive(tsdata->debug_dir); |
738 | kfree(tsdata->raw_buffer); | 738 | kfree(tsdata->raw_buffer); |
739 | } | 739 | } |
740 | 740 | ||
741 | #else | 741 | #else |
742 | 742 | ||
743 | static inline void | 743 | static inline void |
744 | edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, | 744 | edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, |
745 | const char *debugfs_name) | 745 | const char *debugfs_name) |
746 | { | 746 | { |
747 | } | 747 | } |
748 | 748 | ||
749 | static inline void | 749 | static inline void |
750 | edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) | 750 | edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) |
751 | { | 751 | { |
752 | } | 752 | } |
753 | 753 | ||
754 | #endif /* CONFIG_DEBUGFS */ | 754 | #endif /* CONFIG_DEBUGFS */ |
755 | 755 | ||
756 | static int edt_ft5x06_ts_reset(struct i2c_client *client, | 756 | static int edt_ft5x06_ts_reset(struct i2c_client *client, |
757 | struct edt_ft5x06_ts_data *tsdata) | 757 | struct edt_ft5x06_ts_data *tsdata) |
758 | { | 758 | { |
759 | int error; | 759 | int error; |
760 | 760 | ||
761 | if (gpio_is_valid(tsdata->wake_pin)) { | 761 | if (gpio_is_valid(tsdata->wake_pin)) { |
762 | error = devm_gpio_request_one(&client->dev, | 762 | error = devm_gpio_request_one(&client->dev, |
763 | tsdata->wake_pin, GPIOF_OUT_INIT_LOW, | 763 | tsdata->wake_pin, GPIOF_OUT_INIT_LOW, |
764 | "edt-ft5x06 wake"); | 764 | "edt-ft5x06 wake"); |
765 | if (error) { | 765 | if (error) { |
766 | dev_err(&client->dev, | 766 | dev_err(&client->dev, |
767 | "Failed to request GPIO %d as wake pin, error %d\n", | 767 | "Failed to request GPIO %d as wake pin, error %d\n", |
768 | tsdata->wake_pin, error); | 768 | tsdata->wake_pin, error); |
769 | return error; | 769 | return error; |
770 | } | 770 | } |
771 | 771 | ||
772 | msleep(5); | 772 | msleep(5); |
773 | gpio_set_value(tsdata->wake_pin, 1); | 773 | gpio_set_value(tsdata->wake_pin, 1); |
774 | } | 774 | } |
775 | if (gpio_is_valid(tsdata->reset_pin)) { | 775 | if (gpio_is_valid(tsdata->reset_pin)) { |
776 | /* this pulls reset down, enabling the low active reset */ | 776 | /* this pulls reset down, enabling the low active reset */ |
777 | error = devm_gpio_request_one(&client->dev, | 777 | error = devm_gpio_request_one(&client->dev, |
778 | tsdata->reset_pin, GPIOF_OUT_INIT_LOW, | 778 | tsdata->reset_pin, GPIOF_OUT_INIT_LOW, |
779 | "edt-ft5x06 reset"); | 779 | "edt-ft5x06 reset"); |
780 | if (error) { | 780 | if (error) { |
781 | dev_err(&client->dev, | 781 | dev_err(&client->dev, |
782 | "Failed to request GPIO %d as reset pin, error %d\n", | 782 | "Failed to request GPIO %d as reset pin, error %d\n", |
783 | tsdata->reset_pin, error); | 783 | tsdata->reset_pin, error); |
784 | return error; | 784 | return error; |
785 | } | 785 | } |
786 | 786 | ||
787 | msleep(5); | 787 | msleep(5); |
788 | gpio_set_value(tsdata->reset_pin, 1); | 788 | gpio_set_value(tsdata->reset_pin, 1); |
789 | msleep(300); | 789 | msleep(300); |
790 | } | 790 | } |
791 | 791 | ||
792 | return 0; | 792 | return 0; |
793 | } | 793 | } |
794 | 794 | ||
795 | static int edt_ft5x06_ts_identify(struct i2c_client *client, | 795 | static int edt_ft5x06_ts_identify(struct i2c_client *client, |
796 | struct edt_ft5x06_ts_data *tsdata, | 796 | struct edt_ft5x06_ts_data *tsdata, |
797 | char *fw_version) | 797 | char *fw_version) |
798 | { | 798 | { |
799 | u8 rdbuf[EDT_NAME_LEN]; | 799 | u8 rdbuf[EDT_NAME_LEN]; |
800 | char *p; | 800 | char *p; |
801 | int error; | 801 | int error; |
802 | char *model_name = tsdata->name; | 802 | char *model_name = tsdata->name; |
803 | 803 | ||
804 | /* see what we find if we assume it is a M06 * | 804 | /* see what we find if we assume it is a M06 * |
805 | * if we get less than EDT_NAME_LEN, we don't want | 805 | * if we get less than EDT_NAME_LEN, we don't want |
806 | * to have garbage in there | 806 | * to have garbage in there |
807 | */ | 807 | */ |
808 | memset(rdbuf, 0, sizeof(rdbuf)); | 808 | memset(rdbuf, 0, sizeof(rdbuf)); |
809 | error = edt_ft5x06_ts_readwrite(client, 1, "\xbb", | 809 | error = edt_ft5x06_ts_readwrite(client, 1, "\xbb", |
810 | EDT_NAME_LEN - 1, rdbuf); | 810 | EDT_NAME_LEN - 1, rdbuf); |
811 | if (error) | 811 | if (error) |
812 | return error; | 812 | return error; |
813 | 813 | ||
814 | /* if we find something consistent, stay with that assumption | 814 | /* if we find something consistent, stay with that assumption |
815 | * at least M09 won't send 3 bytes here | 815 | * at least M09 won't send 3 bytes here |
816 | */ | 816 | */ |
817 | if (!(strnicmp(rdbuf + 1, "EP0", 3))) { | 817 | if (!(strnicmp(rdbuf + 1, "EP0", 3))) { |
818 | tsdata->version = M06; | 818 | tsdata->version = M06; |
819 | 819 | ||
820 | /* remove last '$' end marker */ | 820 | /* remove last '$' end marker */ |
821 | rdbuf[EDT_NAME_LEN - 1] = '\0'; | 821 | rdbuf[EDT_NAME_LEN - 1] = '\0'; |
822 | if (rdbuf[EDT_NAME_LEN - 2] == '$') | 822 | if (rdbuf[EDT_NAME_LEN - 2] == '$') |
823 | rdbuf[EDT_NAME_LEN - 2] = '\0'; | 823 | rdbuf[EDT_NAME_LEN - 2] = '\0'; |
824 | 824 | ||
825 | /* look for Model/Version separator */ | 825 | /* look for Model/Version separator */ |
826 | p = strchr(rdbuf, '*'); | 826 | p = strchr(rdbuf, '*'); |
827 | if (p) | 827 | if (p) |
828 | *p++ = '\0'; | 828 | *p++ = '\0'; |
829 | strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); | 829 | strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN); |
830 | strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); | 830 | strlcpy(fw_version, p ? p : "", EDT_NAME_LEN); |
831 | } else { | 831 | } else { |
832 | /* since there are only two versions around (M06, M09) */ | 832 | /* since there are only two versions around (M06, M09) */ |
833 | tsdata->version = M09; | 833 | tsdata->version = M09; |
834 | 834 | ||
835 | error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", | 835 | error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", |
836 | 2, rdbuf); | 836 | 2, rdbuf); |
837 | if (error) | 837 | if (error) |
838 | return error; | 838 | return error; |
839 | 839 | ||
840 | strlcpy(fw_version, rdbuf, 2); | 840 | strlcpy(fw_version, rdbuf, 2); |
841 | 841 | ||
842 | error = edt_ft5x06_ts_readwrite(client, 1, "\xA8", | 842 | error = edt_ft5x06_ts_readwrite(client, 1, "\xA8", |
843 | 1, rdbuf); | 843 | 1, rdbuf); |
844 | if (error) | 844 | if (error) |
845 | return error; | 845 | return error; |
846 | 846 | ||
847 | snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", | 847 | snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", |
848 | rdbuf[0] >> 4, rdbuf[0] & 0x0F); | 848 | rdbuf[0] >> 4, rdbuf[0] & 0x0F); |
849 | } | 849 | } |
850 | 850 | ||
851 | return 0; | 851 | return 0; |
852 | } | 852 | } |
853 | 853 | ||
854 | #define EDT_ATTR_CHECKSET(name, reg) \ | 854 | #define EDT_ATTR_CHECKSET(name, reg) \ |
855 | if (pdata->name >= edt_ft5x06_attr_##name.limit_low && \ | 855 | if (pdata->name >= edt_ft5x06_attr_##name.limit_low && \ |
856 | pdata->name <= edt_ft5x06_attr_##name.limit_high) \ | 856 | pdata->name <= edt_ft5x06_attr_##name.limit_high) \ |
857 | edt_ft5x06_register_write(tsdata, reg, pdata->name) | 857 | edt_ft5x06_register_write(tsdata, reg, pdata->name) |
858 | 858 | ||
859 | #define EDT_GET_PROP(name, reg) { \ | 859 | #define EDT_GET_PROP(name, reg) { \ |
860 | u32 val; \ | 860 | u32 val; \ |
861 | if (of_property_read_u32(np, #name, &val) == 0) \ | 861 | if (of_property_read_u32(np, #name, &val) == 0) \ |
862 | edt_ft5x06_register_write(tsdata, reg, val); \ | 862 | edt_ft5x06_register_write(tsdata, reg, val); \ |
863 | } | 863 | } |
864 | 864 | ||
865 | static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np, | 865 | static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np, |
866 | struct edt_ft5x06_ts_data *tsdata) | 866 | struct edt_ft5x06_ts_data *tsdata) |
867 | { | 867 | { |
868 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | 868 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; |
869 | 869 | ||
870 | EDT_GET_PROP(threshold, reg_addr->reg_threshold); | 870 | EDT_GET_PROP(threshold, reg_addr->reg_threshold); |
871 | EDT_GET_PROP(gain, reg_addr->reg_gain); | 871 | EDT_GET_PROP(gain, reg_addr->reg_gain); |
872 | EDT_GET_PROP(offset, reg_addr->reg_offset); | 872 | EDT_GET_PROP(offset, reg_addr->reg_offset); |
873 | } | 873 | } |
874 | 874 | ||
875 | static void | 875 | static void |
876 | edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, | 876 | edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, |
877 | const struct edt_ft5x06_platform_data *pdata) | 877 | const struct edt_ft5x06_platform_data *pdata) |
878 | { | 878 | { |
879 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | 879 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; |
880 | 880 | ||
881 | if (!pdata->use_parameters) | 881 | if (!pdata->use_parameters) |
882 | return; | 882 | return; |
883 | 883 | ||
884 | /* pick up defaults from the platform data */ | 884 | /* pick up defaults from the platform data */ |
885 | EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold); | 885 | EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold); |
886 | EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain); | 886 | EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain); |
887 | EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset); | 887 | EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset); |
888 | if (reg_addr->reg_report_rate != NO_REGISTER) | 888 | if (reg_addr->reg_report_rate != NO_REGISTER) |
889 | EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate); | 889 | EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate); |
890 | } | 890 | } |
891 | 891 | ||
892 | static void | 892 | static void |
893 | edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) | 893 | edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) |
894 | { | 894 | { |
895 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | 895 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; |
896 | 896 | ||
897 | tsdata->threshold = edt_ft5x06_register_read(tsdata, | 897 | tsdata->threshold = edt_ft5x06_register_read(tsdata, |
898 | reg_addr->reg_threshold); | 898 | reg_addr->reg_threshold); |
899 | tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); | 899 | tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); |
900 | tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); | 900 | tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); |
901 | if (reg_addr->reg_report_rate != NO_REGISTER) | 901 | if (reg_addr->reg_report_rate != NO_REGISTER) |
902 | tsdata->report_rate = edt_ft5x06_register_read(tsdata, | 902 | tsdata->report_rate = edt_ft5x06_register_read(tsdata, |
903 | reg_addr->reg_report_rate); | 903 | reg_addr->reg_report_rate); |
904 | tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); | 904 | tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x); |
905 | tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); | 905 | tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y); |
906 | } | 906 | } |
907 | 907 | ||
908 | static void | 908 | static void |
909 | edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) | 909 | edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) |
910 | { | 910 | { |
911 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; | 911 | struct edt_reg_addr *reg_addr = &tsdata->reg_addr; |
912 | 912 | ||
913 | switch (tsdata->version) { | 913 | switch (tsdata->version) { |
914 | case M06: | 914 | case M06: |
915 | reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; | 915 | reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD; |
916 | reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; | 916 | reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE; |
917 | reg_addr->reg_gain = WORK_REGISTER_GAIN; | 917 | reg_addr->reg_gain = WORK_REGISTER_GAIN; |
918 | reg_addr->reg_offset = WORK_REGISTER_OFFSET; | 918 | reg_addr->reg_offset = WORK_REGISTER_OFFSET; |
919 | reg_addr->reg_num_x = WORK_REGISTER_NUM_X; | 919 | reg_addr->reg_num_x = WORK_REGISTER_NUM_X; |
920 | reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; | 920 | reg_addr->reg_num_y = WORK_REGISTER_NUM_Y; |
921 | break; | 921 | break; |
922 | 922 | ||
923 | case M09: | 923 | case M09: |
924 | reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; | 924 | reg_addr->reg_threshold = M09_REGISTER_THRESHOLD; |
925 | reg_addr->reg_gain = M09_REGISTER_GAIN; | 925 | reg_addr->reg_gain = M09_REGISTER_GAIN; |
926 | reg_addr->reg_offset = M09_REGISTER_OFFSET; | 926 | reg_addr->reg_offset = M09_REGISTER_OFFSET; |
927 | reg_addr->reg_num_x = M09_REGISTER_NUM_X; | 927 | reg_addr->reg_num_x = M09_REGISTER_NUM_X; |
928 | reg_addr->reg_num_y = M09_REGISTER_NUM_Y; | 928 | reg_addr->reg_num_y = M09_REGISTER_NUM_Y; |
929 | break; | 929 | break; |
930 | } | 930 | } |
931 | } | 931 | } |
932 | 932 | ||
933 | #ifdef CONFIG_OF | 933 | #ifdef CONFIG_OF |
934 | static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, | 934 | static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, |
935 | struct edt_ft5x06_ts_data *tsdata) | 935 | struct edt_ft5x06_ts_data *tsdata) |
936 | { | 936 | { |
937 | struct device_node *np = dev->of_node; | 937 | struct device_node *np = dev->of_node; |
938 | 938 | ||
939 | /* | 939 | /* |
940 | * irq_pin is not needed for DT setup. | 940 | * irq_pin is not needed for DT setup. |
941 | * irq is associated via 'interrupts' property in DT | 941 | * irq is associated via 'interrupts' property in DT |
942 | */ | 942 | */ |
943 | tsdata->irq_pin = -EINVAL; | 943 | tsdata->irq_pin = -EINVAL; |
944 | tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0); | 944 | tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0); |
945 | tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0); | 945 | tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0); |
946 | 946 | ||
947 | return 0; | 947 | return 0; |
948 | } | 948 | } |
949 | #else | 949 | #else |
950 | static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, | 950 | static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, |
951 | struct edt_ft5x06_ts_data *tsdata) | 951 | struct edt_ft5x06_ts_data *tsdata) |
952 | { | 952 | { |
953 | return -ENODEV; | 953 | return -ENODEV; |
954 | } | 954 | } |
955 | #endif | 955 | #endif |
956 | 956 | ||
957 | static int edt_ft5x06_ts_probe(struct i2c_client *client, | 957 | static int edt_ft5x06_ts_probe(struct i2c_client *client, |
958 | const struct i2c_device_id *id) | 958 | const struct i2c_device_id *id) |
959 | { | 959 | { |
960 | const struct edt_ft5x06_platform_data *pdata = | 960 | const struct edt_ft5x06_platform_data *pdata = |
961 | dev_get_platdata(&client->dev); | 961 | dev_get_platdata(&client->dev); |
962 | struct edt_ft5x06_ts_data *tsdata; | 962 | struct edt_ft5x06_ts_data *tsdata; |
963 | struct input_dev *input; | 963 | struct input_dev *input; |
964 | int error; | 964 | int error; |
965 | char fw_version[EDT_NAME_LEN]; | 965 | char fw_version[EDT_NAME_LEN]; |
966 | unsigned int max_x, max_y; | ||
966 | 967 | ||
967 | dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); | 968 | dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); |
968 | 969 | ||
969 | tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); | 970 | tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); |
970 | if (!tsdata) { | 971 | if (!tsdata) { |
971 | dev_err(&client->dev, "failed to allocate driver data.\n"); | 972 | dev_err(&client->dev, "failed to allocate driver data.\n"); |
972 | return -ENOMEM; | 973 | return -ENOMEM; |
973 | } | 974 | } |
974 | 975 | ||
975 | if (!pdata) { | 976 | if (!pdata) { |
976 | error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata); | 977 | error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata); |
977 | if (error) { | 978 | if (error) { |
978 | dev_err(&client->dev, | 979 | dev_err(&client->dev, |
979 | "DT probe failed and no platform data present\n"); | 980 | "DT probe failed and no platform data present\n"); |
980 | return error; | 981 | return error; |
981 | } | 982 | } |
982 | } else { | 983 | } else { |
983 | tsdata->reset_pin = pdata->reset_pin; | 984 | tsdata->reset_pin = pdata->reset_pin; |
984 | tsdata->irq_pin = pdata->irq_pin; | 985 | tsdata->irq_pin = pdata->irq_pin; |
985 | tsdata->wake_pin = -EINVAL; | 986 | tsdata->wake_pin = -EINVAL; |
986 | } | 987 | } |
987 | 988 | ||
988 | error = edt_ft5x06_ts_reset(client, tsdata); | 989 | error = edt_ft5x06_ts_reset(client, tsdata); |
989 | if (error) | 990 | if (error) |
990 | return error; | 991 | return error; |
991 | 992 | ||
992 | if (gpio_is_valid(tsdata->irq_pin)) { | 993 | if (gpio_is_valid(tsdata->irq_pin)) { |
993 | error = devm_gpio_request_one(&client->dev, tsdata->irq_pin, | 994 | error = devm_gpio_request_one(&client->dev, tsdata->irq_pin, |
994 | GPIOF_IN, "edt-ft5x06 irq"); | 995 | GPIOF_IN, "edt-ft5x06 irq"); |
995 | if (error) { | 996 | if (error) { |
996 | dev_err(&client->dev, | 997 | dev_err(&client->dev, |
997 | "Failed to request GPIO %d, error %d\n", | 998 | "Failed to request GPIO %d, error %d\n", |
998 | tsdata->irq_pin, error); | 999 | tsdata->irq_pin, error); |
999 | return error; | 1000 | return error; |
1000 | } | 1001 | } |
1001 | } | 1002 | } |
1002 | 1003 | ||
1003 | input = devm_input_allocate_device(&client->dev); | 1004 | input = devm_input_allocate_device(&client->dev); |
1004 | if (!input) { | 1005 | if (!input) { |
1005 | dev_err(&client->dev, "failed to allocate input device.\n"); | 1006 | dev_err(&client->dev, "failed to allocate input device.\n"); |
1006 | return -ENOMEM; | 1007 | return -ENOMEM; |
1007 | } | 1008 | } |
1008 | 1009 | ||
1009 | mutex_init(&tsdata->mutex); | 1010 | mutex_init(&tsdata->mutex); |
1010 | tsdata->client = client; | 1011 | tsdata->client = client; |
1011 | tsdata->input = input; | 1012 | tsdata->input = input; |
1012 | tsdata->factory_mode = false; | 1013 | tsdata->factory_mode = false; |
1013 | 1014 | ||
1014 | error = edt_ft5x06_ts_identify(client, tsdata, fw_version); | 1015 | error = edt_ft5x06_ts_identify(client, tsdata, fw_version); |
1015 | if (error) { | 1016 | if (error) { |
1016 | dev_err(&client->dev, "touchscreen probe failed\n"); | 1017 | dev_err(&client->dev, "touchscreen probe failed\n"); |
1017 | return error; | 1018 | return error; |
1018 | } | 1019 | } |
1019 | 1020 | ||
1020 | edt_ft5x06_ts_set_regs(tsdata); | 1021 | edt_ft5x06_ts_set_regs(tsdata); |
1021 | 1022 | ||
1022 | if (!pdata) | 1023 | if (!pdata) |
1023 | edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata); | 1024 | edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata); |
1024 | else | 1025 | else |
1025 | edt_ft5x06_ts_get_defaults(tsdata, pdata); | 1026 | edt_ft5x06_ts_get_defaults(tsdata, pdata); |
1026 | 1027 | ||
1027 | edt_ft5x06_ts_get_parameters(tsdata); | 1028 | edt_ft5x06_ts_get_parameters(tsdata); |
1028 | 1029 | ||
1029 | dev_dbg(&client->dev, | 1030 | dev_dbg(&client->dev, |
1030 | "Model \"%s\", Rev. \"%s\", %dx%d sensors\n", | 1031 | "Model \"%s\", Rev. \"%s\", %dx%d sensors\n", |
1031 | tsdata->name, fw_version, tsdata->num_x, tsdata->num_y); | 1032 | tsdata->name, fw_version, tsdata->num_x, tsdata->num_y); |
1032 | 1033 | ||
1033 | input->name = tsdata->name; | 1034 | input->name = tsdata->name; |
1034 | input->id.bustype = BUS_I2C; | 1035 | input->id.bustype = BUS_I2C; |
1035 | input->dev.parent = &client->dev; | 1036 | input->dev.parent = &client->dev; |
1036 | 1037 | ||
1037 | __set_bit(EV_SYN, input->evbit); | 1038 | __set_bit(EV_SYN, input->evbit); |
1038 | __set_bit(EV_KEY, input->evbit); | 1039 | __set_bit(EV_KEY, input->evbit); |
1039 | __set_bit(EV_ABS, input->evbit); | 1040 | __set_bit(EV_ABS, input->evbit); |
1040 | __set_bit(BTN_TOUCH, input->keybit); | 1041 | __set_bit(BTN_TOUCH, input->keybit); |
1041 | input_set_abs_params(input, ABS_X, 0, tsdata->num_x * 64 - 1, 0, 0); | 1042 | |
1042 | input_set_abs_params(input, ABS_Y, 0, tsdata->num_y * 64 - 1, 0, 0); | 1043 | if ( of_property_read_u32(client->dev.of_node, "touchscreen-size-x", &max_x) == 0 ) { |
1043 | input_set_abs_params(input, ABS_MT_POSITION_X, | 1044 | input_set_abs_params(input, ABS_X, 0, max_x - 1, 0, 0); |
1044 | 0, tsdata->num_x * 64 - 1, 0, 0); | 1045 | input_set_abs_params(input, ABS_MT_POSITION_X, |
1045 | input_set_abs_params(input, ABS_MT_POSITION_Y, | 1046 | 0, max_x - 1, 0, 0); |
1046 | 0, tsdata->num_y * 64 - 1, 0, 0); | 1047 | } else { |
1048 | input_set_abs_params(input, ABS_X, 0, tsdata->num_x * 64 - 1, 0, 0); | ||
1049 | input_set_abs_params(input, ABS_MT_POSITION_X, | ||
1050 | 0, tsdata->num_x * 64 - 1, 0, 0); | ||
1051 | } | ||
1052 | if ( of_property_read_u32(client->dev.of_node, "touchscreen-size-y", &max_y) == 0 ) { | ||
1053 | input_set_abs_params(input, ABS_Y, 0, max_y - 1, 0, 0); | ||
1054 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
1055 | 0, max_y - 1, 0, 0); | ||
1056 | } else { | ||
1057 | input_set_abs_params(input, ABS_Y, 0, tsdata->num_y * 64 - 1, 0, 0); | ||
1058 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
1059 | 0, tsdata->num_y * 64 - 1, 0, 0); | ||
1060 | } | ||
1047 | error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0); | 1061 | error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0); |
1048 | if (error) { | 1062 | if (error) { |
1049 | dev_err(&client->dev, "Unable to init MT slots.\n"); | 1063 | dev_err(&client->dev, "Unable to init MT slots.\n"); |
1050 | return error; | 1064 | return error; |
1051 | } | 1065 | } |
1052 | 1066 | ||
1053 | input_set_drvdata(input, tsdata); | 1067 | input_set_drvdata(input, tsdata); |
1054 | i2c_set_clientdata(client, tsdata); | 1068 | i2c_set_clientdata(client, tsdata); |
1055 | 1069 | ||
1056 | error = devm_request_threaded_irq(&client->dev, client->irq, NULL, | 1070 | error = devm_request_threaded_irq(&client->dev, client->irq, NULL, |
1057 | edt_ft5x06_ts_isr, | 1071 | edt_ft5x06_ts_isr, |
1058 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 1072 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
1059 | client->name, tsdata); | 1073 | client->name, tsdata); |
1060 | if (error) { | 1074 | if (error) { |
1061 | dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); | 1075 | dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); |
1062 | return error; | 1076 | return error; |
1063 | } | 1077 | } |
1064 | 1078 | ||
1065 | error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group); | 1079 | error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group); |
1066 | if (error) | 1080 | if (error) |
1067 | return error; | 1081 | return error; |
1068 | 1082 | ||
1069 | error = input_register_device(input); | 1083 | error = input_register_device(input); |
1070 | if (error) | 1084 | if (error) |
1071 | goto err_remove_attrs; | 1085 | goto err_remove_attrs; |
1072 | 1086 | ||
1073 | edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); | 1087 | edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); |
1074 | device_init_wakeup(&client->dev, 1); | 1088 | device_init_wakeup(&client->dev, 1); |
1075 | 1089 | ||
1076 | dev_dbg(&client->dev, | 1090 | dev_dbg(&client->dev, |
1077 | "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", | 1091 | "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", |
1078 | client->irq, tsdata->wake_pin, tsdata->reset_pin); | 1092 | client->irq, tsdata->wake_pin, tsdata->reset_pin); |
1079 | 1093 | ||
1080 | return 0; | 1094 | return 0; |
1081 | 1095 | ||
1082 | err_remove_attrs: | 1096 | err_remove_attrs: |
1083 | sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); | 1097 | sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); |
1084 | return error; | 1098 | return error; |
1085 | } | 1099 | } |
1086 | 1100 | ||
1087 | static int edt_ft5x06_ts_remove(struct i2c_client *client) | 1101 | static int edt_ft5x06_ts_remove(struct i2c_client *client) |
1088 | { | 1102 | { |
1089 | struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); | 1103 | struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); |
1090 | 1104 | ||
1091 | edt_ft5x06_ts_teardown_debugfs(tsdata); | 1105 | edt_ft5x06_ts_teardown_debugfs(tsdata); |
1092 | sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); | 1106 | sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group); |
1093 | 1107 | ||
1094 | return 0; | 1108 | return 0; |
1095 | } | 1109 | } |
1096 | 1110 | ||
1097 | #ifdef CONFIG_PM_SLEEP | 1111 | #ifdef CONFIG_PM_SLEEP |
1098 | static int edt_ft5x06_ts_suspend(struct device *dev) | 1112 | static int edt_ft5x06_ts_suspend(struct device *dev) |
1099 | { | 1113 | { |
1100 | struct i2c_client *client = to_i2c_client(dev); | 1114 | struct i2c_client *client = to_i2c_client(dev); |
1101 | 1115 | ||
1102 | if (device_may_wakeup(dev)) | 1116 | if (device_may_wakeup(dev)) |
1103 | enable_irq_wake(client->irq); | 1117 | enable_irq_wake(client->irq); |
1104 | 1118 | ||
1105 | return 0; | 1119 | return 0; |
1106 | } | 1120 | } |
1107 | 1121 | ||
1108 | static int edt_ft5x06_ts_resume(struct device *dev) | 1122 | static int edt_ft5x06_ts_resume(struct device *dev) |
1109 | { | 1123 | { |
1110 | struct i2c_client *client = to_i2c_client(dev); | 1124 | struct i2c_client *client = to_i2c_client(dev); |
1111 | 1125 | ||
1112 | if (device_may_wakeup(dev)) | 1126 | if (device_may_wakeup(dev)) |
1113 | disable_irq_wake(client->irq); | 1127 | disable_irq_wake(client->irq); |
1114 | 1128 | ||
1115 | return 0; | 1129 | return 0; |
1116 | } | 1130 | } |
1117 | #endif | 1131 | #endif |
1118 | 1132 | ||
1119 | static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, | 1133 | static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, |
1120 | edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); | 1134 | edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); |
1121 | 1135 | ||
1122 | static const struct i2c_device_id edt_ft5x06_ts_id[] = { | 1136 | static const struct i2c_device_id edt_ft5x06_ts_id[] = { |
1123 | { "edt-ft5x06", 0, }, | 1137 | { "edt-ft5x06", 0, }, |
1124 | { /* sentinel */ } | 1138 | { /* sentinel */ } |
1125 | }; | 1139 | }; |
1126 | MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); | 1140 | MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); |
1127 | 1141 | ||
1128 | #ifdef CONFIG_OF | 1142 | #ifdef CONFIG_OF |
1129 | static const struct of_device_id edt_ft5x06_of_match[] = { | 1143 | static const struct of_device_id edt_ft5x06_of_match[] = { |
1130 | { .compatible = "edt,edt-ft5206", }, | 1144 | { .compatible = "edt,edt-ft5206", }, |
1131 | { .compatible = "edt,edt-ft5306", }, | 1145 | { .compatible = "edt,edt-ft5306", }, |
1132 | { .compatible = "edt,edt-ft5406", }, | 1146 | { .compatible = "edt,edt-ft5406", }, |
1133 | { /* sentinel */ } | 1147 | { /* sentinel */ } |
1134 | }; | 1148 | }; |
1135 | MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); | 1149 | MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); |
1136 | #endif | 1150 | #endif |
1137 | 1151 | ||
1138 | static struct i2c_driver edt_ft5x06_ts_driver = { | 1152 | static struct i2c_driver edt_ft5x06_ts_driver = { |
1139 | .driver = { | 1153 | .driver = { |
1140 | .owner = THIS_MODULE, | 1154 | .owner = THIS_MODULE, |
1141 | .name = "edt_ft5x06", | 1155 | .name = "edt_ft5x06", |
1142 | .of_match_table = of_match_ptr(edt_ft5x06_of_match), | 1156 | .of_match_table = of_match_ptr(edt_ft5x06_of_match), |
1143 | .pm = &edt_ft5x06_ts_pm_ops, | 1157 | .pm = &edt_ft5x06_ts_pm_ops, |
1144 | }, | 1158 | }, |
1145 | .id_table = edt_ft5x06_ts_id, | 1159 | .id_table = edt_ft5x06_ts_id, |
1146 | .probe = edt_ft5x06_ts_probe, | 1160 | .probe = edt_ft5x06_ts_probe, |
1147 | .remove = edt_ft5x06_ts_remove, | 1161 | .remove = edt_ft5x06_ts_remove, |
1148 | }; | 1162 | }; |
1149 | 1163 | ||
1150 | module_i2c_driver(edt_ft5x06_ts_driver); | 1164 | module_i2c_driver(edt_ft5x06_ts_driver); |
1151 | 1165 | ||
1152 | MODULE_ALIAS("i2c:edt-ft5206"); | 1166 | MODULE_ALIAS("i2c:edt-ft5206"); |
1153 | MODULE_ALIAS("i2c:edt-ft5306"); | 1167 | MODULE_ALIAS("i2c:edt-ft5306"); |
1154 | MODULE_ALIAS("i2c:edt-ft5406"); | 1168 | MODULE_ALIAS("i2c:edt-ft5406"); |
1155 | MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>"); | 1169 | MODULE_AUTHOR("Simon Budig <simon.budig@kernelconcepts.de>"); |
1156 | MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver"); | 1170 | MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver"); |
1157 | MODULE_LICENSE("GPL"); | 1171 | MODULE_LICENSE("GPL"); |
1158 | 1172 |