Commit | Line | Data |
---|---|---|
b98abe52 SR |
1 | /* |
2 | * Generic DT helper functions for touchscreen devices | |
3 | * | |
4 | * Copyright (c) 2014 Sebastian Reichel <sre@kernel.org> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | */ | |
11 | ||
4200e831 | 12 | #include <linux/property.h> |
b98abe52 | 13 | #include <linux/input.h> |
0a363a38 | 14 | #include <linux/input/mt.h> |
b98abe52 | 15 | #include <linux/input/touchscreen.h> |
43173a0e | 16 | #include <linux/module.h> |
b98abe52 | 17 | |
4200e831 | 18 | static bool touchscreen_get_prop_u32(struct device *dev, |
7c494375 DT |
19 | const char *property, |
20 | unsigned int default_value, | |
21 | unsigned int *value) | |
3eea8b5d | 22 | { |
7c494375 DT |
23 | u32 val; |
24 | int error; | |
3eea8b5d | 25 | |
4200e831 | 26 | error = device_property_read_u32(dev, property, &val); |
7c494375 DT |
27 | if (error) { |
28 | *value = default_value; | |
29 | return false; | |
30 | } | |
3eea8b5d | 31 | |
7c494375 DT |
32 | *value = val; |
33 | return true; | |
3eea8b5d MR |
34 | } |
35 | ||
36 | static void touchscreen_set_params(struct input_dev *dev, | |
37 | unsigned long axis, | |
38 | int max, int fuzz) | |
39 | { | |
40 | struct input_absinfo *absinfo; | |
41 | ||
42 | if (!test_bit(axis, dev->absbit)) { | |
f61fd21d DT |
43 | dev_warn(&dev->dev, |
44 | "DT specifies parameters but the axis %lu is not set up\n", | |
45 | axis); | |
3eea8b5d MR |
46 | return; |
47 | } | |
48 | ||
49 | absinfo = &dev->absinfo[axis]; | |
50 | absinfo->maximum = max; | |
51 | absinfo->fuzz = fuzz; | |
52 | } | |
53 | ||
b98abe52 | 54 | /** |
4200e831 DT |
55 | * touchscreen_parse_properties - parse common touchscreen DT properties |
56 | * @input: input device that should be parsed | |
57 | * @multitouch: specifies whether parsed properties should be applied to | |
58 | * single-touch or multi-touch axes | |
ed7c9870 HG |
59 | * @prop: pointer to a struct touchscreen_properties into which to store |
60 | * axis swap and invert info for use with touchscreen_report_x_y(); | |
61 | * or %NULL | |
b98abe52 SR |
62 | * |
63 | * This function parses common DT properties for touchscreens and setups the | |
4200e831 | 64 | * input device accordingly. The function keeps previously set up default |
b98abe52 SR |
65 | * values if no value is specified via DT. |
66 | */ | |
ed7c9870 HG |
67 | void touchscreen_parse_properties(struct input_dev *input, bool multitouch, |
68 | struct touchscreen_properties *prop) | |
b98abe52 | 69 | { |
4200e831 | 70 | struct device *dev = input->dev.parent; |
7c494375 DT |
71 | unsigned int axis; |
72 | unsigned int maximum, fuzz; | |
73 | bool data_present; | |
b98abe52 | 74 | |
4200e831 DT |
75 | input_alloc_absinfo(input); |
76 | if (!input->absinfo) | |
b98abe52 SR |
77 | return; |
78 | ||
7c494375 | 79 | axis = multitouch ? ABS_MT_POSITION_X : ABS_X; |
4200e831 DT |
80 | data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-x", |
81 | input_abs_get_max(input, | |
51717869 | 82 | axis) + 1, |
7c494375 | 83 | &maximum) | |
4200e831 DT |
84 | touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x", |
85 | input_abs_get_fuzz(input, axis), | |
7c494375 DT |
86 | &fuzz); |
87 | if (data_present) | |
4200e831 | 88 | touchscreen_set_params(input, axis, maximum - 1, fuzz); |
b98abe52 | 89 | |
7c494375 | 90 | axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; |
4200e831 DT |
91 | data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-y", |
92 | input_abs_get_max(input, | |
51717869 | 93 | axis) + 1, |
7c494375 | 94 | &maximum) | |
4200e831 DT |
95 | touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y", |
96 | input_abs_get_fuzz(input, axis), | |
7c494375 DT |
97 | &fuzz); |
98 | if (data_present) | |
4200e831 | 99 | touchscreen_set_params(input, axis, maximum - 1, fuzz); |
b98abe52 | 100 | |
7c494375 | 101 | axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; |
4200e831 DT |
102 | data_present = touchscreen_get_prop_u32(dev, |
103 | "touchscreen-max-pressure", | |
104 | input_abs_get_max(input, axis), | |
7c494375 | 105 | &maximum) | |
4200e831 DT |
106 | touchscreen_get_prop_u32(dev, |
107 | "touchscreen-fuzz-pressure", | |
108 | input_abs_get_fuzz(input, axis), | |
7c494375 DT |
109 | &fuzz); |
110 | if (data_present) | |
4200e831 | 111 | touchscreen_set_params(input, axis, maximum, fuzz); |
ed7c9870 HG |
112 | |
113 | if (!prop) | |
114 | return; | |
115 | ||
116 | axis = multitouch ? ABS_MT_POSITION_X : ABS_X; | |
117 | ||
118 | prop->max_x = input_abs_get_max(input, axis); | |
119 | prop->max_y = input_abs_get_max(input, axis + 1); | |
120 | prop->invert_x = | |
121 | device_property_read_bool(dev, "touchscreen-inverted-x"); | |
122 | prop->invert_y = | |
123 | device_property_read_bool(dev, "touchscreen-inverted-y"); | |
124 | prop->swap_x_y = | |
125 | device_property_read_bool(dev, "touchscreen-swapped-x-y"); | |
126 | ||
127 | if (prop->swap_x_y) | |
128 | swap(input->absinfo[axis], input->absinfo[axis + 1]); | |
b98abe52 | 129 | } |
4200e831 | 130 | EXPORT_SYMBOL(touchscreen_parse_properties); |
ed7c9870 HG |
131 | |
132 | static void | |
133 | touchscreen_apply_prop_to_x_y(const struct touchscreen_properties *prop, | |
134 | unsigned int *x, unsigned int *y) | |
135 | { | |
136 | if (prop->invert_x) | |
137 | *x = prop->max_x - *x; | |
138 | ||
139 | if (prop->invert_y) | |
140 | *y = prop->max_y - *y; | |
141 | ||
142 | if (prop->swap_x_y) | |
143 | swap(*x, *y); | |
144 | } | |
145 | ||
146 | /** | |
147 | * touchscreen_set_mt_pos - Set input_mt_pos coordinates | |
148 | * @pos: input_mt_pos to set coordinates of | |
149 | * @prop: pointer to a struct touchscreen_properties | |
150 | * @x: X coordinate to store in pos | |
151 | * @y: Y coordinate to store in pos | |
152 | * | |
153 | * Adjust the passed in x and y values applying any axis inversion and | |
154 | * swapping requested in the passed in touchscreen_properties and store | |
155 | * the result in a struct input_mt_pos. | |
156 | */ | |
157 | void touchscreen_set_mt_pos(struct input_mt_pos *pos, | |
158 | const struct touchscreen_properties *prop, | |
159 | unsigned int x, unsigned int y) | |
160 | { | |
161 | touchscreen_apply_prop_to_x_y(prop, &x, &y); | |
162 | pos->x = x; | |
163 | pos->y = y; | |
164 | } | |
165 | EXPORT_SYMBOL(touchscreen_set_mt_pos); | |
166 | ||
167 | /** | |
168 | * touchscreen_report_pos - Report touchscreen coordinates | |
169 | * @input: input_device to report coordinates for | |
170 | * @prop: pointer to a struct touchscreen_properties | |
171 | * @x: X coordinate to report | |
172 | * @y: Y coordinate to report | |
173 | * @multitouch: Report coordinates on single-touch or multi-touch axes | |
174 | * | |
175 | * Adjust the passed in x and y values applying any axis inversion and | |
176 | * swapping requested in the passed in touchscreen_properties and then | |
177 | * report the resulting coordinates on the input_dev's x and y axis. | |
178 | */ | |
179 | void touchscreen_report_pos(struct input_dev *input, | |
180 | const struct touchscreen_properties *prop, | |
181 | unsigned int x, unsigned int y, | |
182 | bool multitouch) | |
183 | { | |
184 | touchscreen_apply_prop_to_x_y(prop, &x, &y); | |
185 | input_report_abs(input, multitouch ? ABS_MT_POSITION_X : ABS_X, x); | |
186 | input_report_abs(input, multitouch ? ABS_MT_POSITION_Y : ABS_Y, y); | |
187 | } | |
188 | EXPORT_SYMBOL(touchscreen_report_pos); | |
43173a0e AB |
189 | |
190 | MODULE_LICENSE("GPL v2"); | |
191 | MODULE_DESCRIPTION("Device-tree helpers functions for touchscreen devices"); |