diff options
author | Sundar Raman | 2013-08-07 13:57:48 -0500 |
---|---|---|
committer | Praneeth Bajjuri | 2013-08-09 16:11:21 -0500 |
commit | 70af0c5ff9ea2b0aa1deb8674398c4714eaf2869 (patch) | |
tree | 029dcf62b8e26f1e94e4b7317823448457550aea | |
parent | c5444cc3fe1dd3a812d4ec9e2c1890da5040eac6 (diff) | |
download | kernel-audio-70af0c5ff9ea2b0aa1deb8674398c4714eaf2869.tar.gz kernel-audio-70af0c5ff9ea2b0aa1deb8674398c4714eaf2869.tar.xz kernel-audio-70af0c5ff9ea2b0aa1deb8674398c4714eaf2869.zip |
Input: atmel_mxt_ts: Add device tree support
Add device tree support for Atmel touch driver. All platform
specific data is now read from dts files and parsed inside the
driver.
NOTE: Provision for supplying config data for controller is
given from board specific dts file since the driver no longer
configures these values for different firmware revisions,
after this commit: 71749f5c66e797a39600dae9de58aab3858dc488
Change-Id: Ic88bc62246e2465d527410e6fef78b301d681628
Signed-off-by: Sundar Raman <sunds@ti.com>
Acked-by: Nishanth Menon <nm@ti.com>
-rw-r--r-- | Documentation/devicetree/bindings/input/touchscreen/atmel_mxt_ts.txt | 108 | ||||
-rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 135 |
2 files changed, 238 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/atmel_mxt_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/atmel_mxt_ts.txt new file mode 100644 index 000000000000..effc1abe5dcb --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/atmel_mxt_ts.txt | |||
@@ -0,0 +1,108 @@ | |||
1 | Atmel MaxTouch Touchscreen | ||
2 | -------------------------- | ||
3 | Required properties: | ||
4 | - compatible: "atmel,mXT244" or "atmel,qt602240_ts" | ||
5 | or "atmel,atmel_mxt_ts" | ||
6 | - reg: I2C address of the chip | ||
7 | - interrupts: interrupt signal to which the chip is connected | ||
8 | - atmel,x-line: Number of x lines the touch object occupies in pixels | ||
9 | - atmel,y-line: Number of y lines the touch object occupies in pixels | ||
10 | - atmel,x-size: Horizontal resolution of touchscreen in pixels | ||
11 | - atmel,y-size: Vertical resolution of touchscreen in pixels | ||
12 | - atmel,blen: Sets the gain of the analog circuit in front of ADC | ||
13 | Gain setting depends on package type. Range: 0-3 | ||
14 | - atmel,threshold: Channel detection threshold value. Range: 0-255 | ||
15 | Typical: 30-80. Lower the threshold, higher the | ||
16 | sensitivity | ||
17 | - atmel,voltage: Nominal AVdd in uV for analog circuitry, greater than | ||
18 | or less than base voltage of 2.7V, used for optimizing | ||
19 | capacitive sensing. For example, if you want to | ||
20 | program an optimum voltage of 2.8V in your design, | ||
21 | specify 2800000 for this parameter | ||
22 | - atmel,orientation: touchscreen orientation, must be one of following, | ||
23 | as defined inside include/linux/i2c/atmel_mxt_ts.h | ||
24 | - 0: MXT_NORMAL - normal | ||
25 | - 1: MXT_DIAGONAL - diagonal | ||
26 | - 2: MXT_HORIZONTAL_FLIP - horizonally flipped | ||
27 | - 3: MXT_ROTATED_90_COUNTER - rotated by 90 degrees | ||
28 | counter-clockwise | ||
29 | - 4: MXT_VERTICAL_FLIP - vertically flipped | ||
30 | - 5: MXT_ROTATED_90 - rotated by 90 degress clockwise | ||
31 | - 6: MXT_ROTATED_180 - rotated by 180 degrees | ||
32 | - 7: MXT_DIAGONAL_COUNTER - diagonal counter | ||
33 | |||
34 | Optional properties: | ||
35 | - atmel,config: list of 8-bit register values for controller objects | ||
36 | in the following order. Number of objects and values depends on the | ||
37 | particular model of Atmel touch screen you are using. Please check | ||
38 | with your Atmel representative for helping you tune these values | ||
39 | GEN_COMMAND, GEN_POWER, GEN_ACQUIRE, TOUCH_MULTI | ||
40 | TOUCH_KEYARRAY, MXT244_COMMSCONFIG_T18, SPT_GPIOPWM, PROCI_GRIPFACE, | ||
41 | PROCG_NOISE, TOUCH_PROXIMITY, PROCI_ONETOUCH, SPT_SELFTEST, | ||
42 | PROCI_TWOTOUCH, SPT_CTECONFIG | ||
43 | Note: These register values can be specified here according to | ||
44 | the specific controller and platform configuration desired. The | ||
45 | driver does not configure these registers by default and leaves it | ||
46 | to the platform dts file to supply them | ||
47 | |||
48 | Example: | ||
49 | |||
50 | &i2c1 { | ||
51 | mXT244:mXT244@4a { | ||
52 | reg = <0x4a>; | ||
53 | }; | ||
54 | }; | ||
55 | |||
56 | &mXT244 { | ||
57 | compatible = "atmel,mXT244"; | ||
58 | interrupts = <0 119 0x4>; | ||
59 | |||
60 | atmel,config = < | ||
61 | /* MXT244_GEN_COMMAND(6) */ | ||
62 | 0x00 0x00 0x00 0x00 0x00 0x00 | ||
63 | /* MXT244_GEN_POWER(7) */ | ||
64 | 0x20 0xff 0x32 | ||
65 | /* MXT244_GEN_ACQUIRE(8) */ | ||
66 | 0x0a 0x00 0x05 0x00 0x00 0x00 0x09 0x23 | ||
67 | /* MXT244_TOUCH_MULTI(9) */ | ||
68 | 0x00 0x00 0x00 0x13 0x0b 0x00 0x00 0x00 0x02 0x00 | ||
69 | 0x00 0x01 0x01 0x0e 0x0a 0x0a 0x0a 0x0a 0x00 0x00 | ||
70 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 | ||
71 | 0x00 | ||
72 | /* MXT244_TOUCH_KEYARRAY(15) */ | ||
73 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 | ||
74 | 0x00 | ||
75 | /* MXT244_COMMSCONFIG_T18(2) */ | ||
76 | 0x00 0x00 | ||
77 | /* MXT244_SPT_GPIOPWM(19) */ | ||
78 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 | ||
79 | 0x00 0x00 0x00 0x00 0x00 0x00 | ||
80 | /* MXT244_PROCI_GRIPFACE(20) */ | ||
81 | 0x07 0x00 0x00 0x00 0x00 0x00 0x00 0x50 0x28 0x04 | ||
82 | 0x0f 0x0a | ||
83 | /* MXT244_PROCG_NOISE(22) */ | ||
84 | 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x03 0x23 0x00 | ||
85 | 0x00 0x05 0x0f 0x19 0x23 0x2d 0x03 | ||
86 | /* MXT244_TOUCH_PROXIMITY(23) */ | ||
87 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 | ||
88 | 0x00 0x00 0x00 0x00 0x00 | ||
89 | /* MXT244_PROCI_ONETOUCH(24) */ | ||
90 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 | ||
91 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 | ||
92 | /* MXT244_SPT_SELFTEST(25) */ | ||
93 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 | ||
94 | 0x00 0x00 0x00 0x00 | ||
95 | /* MXT244_PROCI_TWOTOUCH(27) */ | ||
96 | 0x00 0x00 0x00 0x00 0x00 0x00 0x00 | ||
97 | /* MXT244_SPT_CTECONFIG(28) */ | ||
98 | 0x00 0x00 0x02 0x08 0x10 0x00 >; | ||
99 | |||
100 | atmel,x_line = <18>; | ||
101 | atmel,y_line = <12>; | ||
102 | atmel,x_size = <800>; | ||
103 | atmel,y_size = <480>; | ||
104 | atmel,blen = <0x01>; | ||
105 | atmel,threshold = <30>; | ||
106 | atmel,voltage = <2800000>; | ||
107 | atmel,orient = <0x4>; | ||
108 | }; | ||
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 7dc24a3b31a5..69da9b335078 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/input/mt.h> | 20 | #include <linux/input/mt.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/of.h> | ||
24 | #include <linux/of_device.h> | ||
23 | 25 | ||
24 | /* Version */ | 26 | /* Version */ |
25 | #define MXT_VER_20 20 | 27 | #define MXT_VER_20 20 |
@@ -324,6 +326,105 @@ static void mxt_dump_message(struct device *dev, | |||
324 | message->reportid, 7, message->message); | 326 | message->reportid, 7, message->message); |
325 | } | 327 | } |
326 | 328 | ||
329 | static int mxt_of_get_platform_info(struct i2c_client *client, | ||
330 | struct mxt_platform_data *pdata) | ||
331 | |||
332 | { | ||
333 | int size, index = 0; | ||
334 | u32 val; | ||
335 | const __be32 *config_be; | ||
336 | u8 *config; | ||
337 | const char *pname; | ||
338 | struct device_node *node = client->dev.of_node; | ||
339 | |||
340 | config_be = of_get_property(node, "atmel,config", &size); | ||
341 | if (config_be && size) { | ||
342 | size /= sizeof(*config_be); | ||
343 | config = devm_kzalloc(&client->dev, size, GFP_KERNEL); | ||
344 | if (!config) { | ||
345 | dev_err(&client->dev, "Failed to allocate memory\n"); | ||
346 | return -ENOMEM; | ||
347 | } | ||
348 | |||
349 | pdata->config = config; | ||
350 | pdata->config_length = size; | ||
351 | |||
352 | while (index < size) { | ||
353 | config[index] = be32_to_cpup(config_be + index) & 0xFF; | ||
354 | index++; | ||
355 | } | ||
356 | } else { | ||
357 | dev_dbg(&client->dev, "%s:no config data specified\n", | ||
358 | __func__); | ||
359 | } | ||
360 | |||
361 | pname = "atmel,x_line"; | ||
362 | if (of_property_read_u32(node, pname, &pdata->x_line)) { | ||
363 | dev_err(&client->dev, "%s: Failed to read %s property\n", | ||
364 | __func__, pname); | ||
365 | return -EINVAL; | ||
366 | } | ||
367 | |||
368 | pname = "atmel,y_line"; | ||
369 | if (of_property_read_u32(node, pname, &pdata->y_line)) { | ||
370 | dev_err(&client->dev, "%s: Failed to read %s property\n", | ||
371 | __func__, pname); | ||
372 | return -EINVAL; | ||
373 | } | ||
374 | |||
375 | pname = "atmel,x_size"; | ||
376 | if (of_property_read_u32(node, pname, &pdata->x_size)) { | ||
377 | dev_err(&client->dev, "%s: Failed to read %s property\n", | ||
378 | __func__, pname); | ||
379 | return -EINVAL; | ||
380 | } | ||
381 | |||
382 | pname = "atmel,y_size"; | ||
383 | if (of_property_read_u32(node, pname, &pdata->y_size)) { | ||
384 | dev_err(&client->dev, "%s: Failed to read %s property\n", | ||
385 | __func__, pname); | ||
386 | return -EINVAL; | ||
387 | } | ||
388 | |||
389 | pname = "atmel,blen"; | ||
390 | if (of_property_read_u32(node, pname, &pdata->blen)) { | ||
391 | dev_err(&client->dev, "%s: Failed to read %s property\n", | ||
392 | __func__, pname); | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | |||
396 | pname = "atmel,threshold"; | ||
397 | if (of_property_read_u32(node, pname, &pdata->threshold)) { | ||
398 | dev_err(&client->dev, "%s: Failed to read %s property\n", | ||
399 | __func__, pname); | ||
400 | return -EINVAL; | ||
401 | } | ||
402 | |||
403 | pname = "atmel,voltage"; | ||
404 | if (of_property_read_u32(node, pname, &pdata->voltage)) { | ||
405 | dev_err(&client->dev, | ||
406 | "%s: Failed to read %s property\n", | ||
407 | __func__, pname); | ||
408 | return -EINVAL; | ||
409 | } | ||
410 | |||
411 | pname = "atmel,orient"; | ||
412 | if (of_property_read_u32(node, pname, &val)) { | ||
413 | dev_err(&client->dev, "%s: Failed to read %s property\n", | ||
414 | __func__, pname); | ||
415 | return -EINVAL; | ||
416 | } | ||
417 | |||
418 | if (val > 0xFF) { | ||
419 | dev_err(&client->dev, "%s: Bad %s property value %d\n", | ||
420 | __func__, pname, val); | ||
421 | return -EINVAL; | ||
422 | } | ||
423 | pdata->orient = val & 0xFF; | ||
424 | |||
425 | return 0; | ||
426 | } | ||
427 | |||
327 | static int mxt_check_bootloader(struct i2c_client *client, | 428 | static int mxt_check_bootloader(struct i2c_client *client, |
328 | unsigned int state) | 429 | unsigned int state) |
329 | { | 430 | { |
@@ -1095,17 +1196,40 @@ static void mxt_input_close(struct input_dev *dev) | |||
1095 | mxt_stop(data); | 1196 | mxt_stop(data); |
1096 | } | 1197 | } |
1097 | 1198 | ||
1199 | static const struct of_device_id mxt_dt_ids[] = { | ||
1200 | { .compatible = "atmel,qt602240_ts", }, | ||
1201 | { .compatible = "atmel,atmel_mxt_ts", }, | ||
1202 | { .compatible = "atmel,mXT244", }, | ||
1203 | { /* sentinel */ } | ||
1204 | }; | ||
1205 | |||
1098 | static int mxt_probe(struct i2c_client *client, | 1206 | static int mxt_probe(struct i2c_client *client, |
1099 | const struct i2c_device_id *id) | 1207 | const struct i2c_device_id *id) |
1100 | { | 1208 | { |
1101 | const struct mxt_platform_data *pdata = client->dev.platform_data; | 1209 | struct mxt_platform_data *pdata; |
1102 | struct mxt_data *data; | 1210 | struct mxt_data *data; |
1103 | struct input_dev *input_dev; | 1211 | struct input_dev *input_dev; |
1104 | int error; | 1212 | int error; |
1105 | unsigned int num_mt_slots; | 1213 | unsigned int num_mt_slots; |
1106 | 1214 | const struct of_device_id *match; | |
1107 | if (!pdata) | 1215 | |
1108 | return -EINVAL; | 1216 | match = of_match_device(of_match_ptr(mxt_dt_ids), &client->dev); |
1217 | if (match) { | ||
1218 | pdata = devm_kzalloc(&client->dev, | ||
1219 | sizeof(struct mxt_platform_data), | ||
1220 | GFP_KERNEL); | ||
1221 | if (!pdata) | ||
1222 | return -ENOMEM; | ||
1223 | error = mxt_of_get_platform_info(client, pdata); | ||
1224 | if (error) | ||
1225 | return error; | ||
1226 | } else { | ||
1227 | pdata = client->dev.platform_data; | ||
1228 | if (!pdata) { | ||
1229 | dev_err(&client->dev, "Platform data not populated\n"); | ||
1230 | return -EINVAL; | ||
1231 | } | ||
1232 | } | ||
1109 | 1233 | ||
1110 | data = devm_kzalloc(&client->dev, sizeof(struct mxt_data), GFP_KERNEL); | 1234 | data = devm_kzalloc(&client->dev, sizeof(struct mxt_data), GFP_KERNEL); |
1111 | input_dev = input_allocate_device(); | 1235 | input_dev = input_allocate_device(); |
@@ -1167,7 +1291,7 @@ static int mxt_probe(struct i2c_client *client, | |||
1167 | 1291 | ||
1168 | error = devm_request_threaded_irq(&client->dev, client->irq, | 1292 | error = devm_request_threaded_irq(&client->dev, client->irq, |
1169 | NULL, mxt_interrupt, | 1293 | NULL, mxt_interrupt, |
1170 | pdata->irqflags | IRQF_ONESHOT, | 1294 | IRQF_ONESHOT, |
1171 | dev_name(&client->dev), data); | 1295 | dev_name(&client->dev), data); |
1172 | if (error) { | 1296 | if (error) { |
1173 | dev_err(&client->dev, "Failed to register interrupt\n"); | 1297 | dev_err(&client->dev, "Failed to register interrupt\n"); |
@@ -1264,6 +1388,7 @@ static struct i2c_driver mxt_driver = { | |||
1264 | .name = "atmel_mxt_ts", | 1388 | .name = "atmel_mxt_ts", |
1265 | .owner = THIS_MODULE, | 1389 | .owner = THIS_MODULE, |
1266 | .pm = &mxt_pm_ops, | 1390 | .pm = &mxt_pm_ops, |
1391 | .of_match_table = mxt_dt_ids, | ||
1267 | }, | 1392 | }, |
1268 | .probe = mxt_probe, | 1393 | .probe = mxt_probe, |
1269 | .remove = mxt_remove, | 1394 | .remove = mxt_remove, |