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, | |
d9265e8a | 38 | int min, int max, int fuzz) |
3eea8b5d MR |
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]; | |
d9265e8a | 50 | absinfo->minimum = min; |
3eea8b5d MR |
51 | absinfo->maximum = max; |
52 | absinfo->fuzz = fuzz; | |
53 | } | |
54 | ||
b98abe52 | 55 | /** |
4200e831 DT |
56 | * touchscreen_parse_properties - parse common touchscreen DT properties |
57 | * @input: input device that should be parsed | |
58 | * @multitouch: specifies whether parsed properties should be applied to | |
59 | * single-touch or multi-touch axes | |
ed7c9870 HG |
60 | * @prop: pointer to a struct touchscreen_properties into which to store |
61 | * axis swap and invert info for use with touchscreen_report_x_y(); | |
62 | * or %NULL | |
b98abe52 SR |
63 | * |
64 | * This function parses common DT properties for touchscreens and setups the | |
4200e831 | 65 | * input device accordingly. The function keeps previously set up default |
b98abe52 SR |
66 | * values if no value is specified via DT. |
67 | */ | |
ed7c9870 HG |
68 | void touchscreen_parse_properties(struct input_dev *input, bool multitouch, |
69 | struct touchscreen_properties *prop) | |
b98abe52 | 70 | { |
4200e831 | 71 | struct device *dev = input->dev.parent; |
d9265e8a | 72 | struct input_absinfo *absinfo; |
7c494375 | 73 | unsigned int axis; |
d9265e8a | 74 | unsigned int minimum, maximum, fuzz; |
7c494375 | 75 | bool data_present; |
b98abe52 | 76 | |
4200e831 DT |
77 | input_alloc_absinfo(input); |
78 | if (!input->absinfo) | |
b98abe52 SR |
79 | return; |
80 | ||
7c494375 | 81 | axis = multitouch ? ABS_MT_POSITION_X : ABS_X; |
d9265e8a HG |
82 | data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x", |
83 | input_abs_get_min(input, axis), | |
84 | &minimum) | | |
85 | touchscreen_get_prop_u32(dev, "touchscreen-size-x", | |
4200e831 | 86 | input_abs_get_max(input, |
51717869 | 87 | axis) + 1, |
7c494375 | 88 | &maximum) | |
4200e831 DT |
89 | touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x", |
90 | input_abs_get_fuzz(input, axis), | |
7c494375 DT |
91 | &fuzz); |
92 | if (data_present) | |
d9265e8a | 93 | touchscreen_set_params(input, axis, minimum, maximum - 1, fuzz); |
b98abe52 | 94 | |
7c494375 | 95 | axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; |
d9265e8a HG |
96 | data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y", |
97 | input_abs_get_min(input, axis), | |
98 | &minimum) | | |
99 | touchscreen_get_prop_u32(dev, "touchscreen-size-y", | |
4200e831 | 100 | input_abs_get_max(input, |
51717869 | 101 | axis) + 1, |
7c494375 | 102 | &maximum) | |
4200e831 DT |
103 | touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y", |
104 | input_abs_get_fuzz(input, axis), | |
7c494375 DT |
105 | &fuzz); |
106 | if (data_present) | |
d9265e8a | 107 | touchscreen_set_params(input, axis, minimum, maximum - 1, fuzz); |
b98abe52 | 108 | |
7c494375 | 109 | axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; |
4200e831 DT |
110 | data_present = touchscreen_get_prop_u32(dev, |
111 | "touchscreen-max-pressure", | |
112 | input_abs_get_max(input, axis), | |
7c494375 | 113 | &maximum) | |
4200e831 DT |
114 | touchscreen_get_prop_u32(dev, |
115 | "touchscreen-fuzz-pressure", | |
116 | input_abs_get_fuzz(input, axis), | |
7c494375 DT |
117 | &fuzz); |
118 | if (data_present) | |
d9265e8a | 119 | touchscreen_set_params(input, axis, 0, maximum, fuzz); |
ed7c9870 HG |
120 | |
121 | if (!prop) | |
122 | return; | |
123 | ||
124 | axis = multitouch ? ABS_MT_POSITION_X : ABS_X; | |
125 | ||
126 | prop->max_x = input_abs_get_max(input, axis); | |
127 | prop->max_y = input_abs_get_max(input, axis + 1); | |
d9265e8a | 128 | |
ed7c9870 HG |
129 | prop->invert_x = |
130 | device_property_read_bool(dev, "touchscreen-inverted-x"); | |
d9265e8a HG |
131 | if (prop->invert_x) { |
132 | absinfo = &input->absinfo[axis]; | |
133 | absinfo->maximum -= absinfo->minimum; | |
134 | absinfo->minimum = 0; | |
135 | } | |
136 | ||
ed7c9870 HG |
137 | prop->invert_y = |
138 | device_property_read_bool(dev, "touchscreen-inverted-y"); | |
d9265e8a HG |
139 | if (prop->invert_y) { |
140 | absinfo = &input->absinfo[axis + 1]; | |
141 | absinfo->maximum -= absinfo->minimum; | |
142 | absinfo->minimum = 0; | |
143 | } | |
144 | ||
ed7c9870 HG |
145 | prop->swap_x_y = |
146 | device_property_read_bool(dev, "touchscreen-swapped-x-y"); | |
ed7c9870 HG |
147 | if (prop->swap_x_y) |
148 | swap(input->absinfo[axis], input->absinfo[axis + 1]); | |
b98abe52 | 149 | } |
4200e831 | 150 | EXPORT_SYMBOL(touchscreen_parse_properties); |
ed7c9870 HG |
151 | |
152 | static void | |
153 | touchscreen_apply_prop_to_x_y(const struct touchscreen_properties *prop, | |
154 | unsigned int *x, unsigned int *y) | |
155 | { | |
156 | if (prop->invert_x) | |
157 | *x = prop->max_x - *x; | |
158 | ||
159 | if (prop->invert_y) | |
160 | *y = prop->max_y - *y; | |
161 | ||
162 | if (prop->swap_x_y) | |
163 | swap(*x, *y); | |
164 | } | |
165 | ||
166 | /** | |
167 | * touchscreen_set_mt_pos - Set input_mt_pos coordinates | |
168 | * @pos: input_mt_pos to set coordinates of | |
169 | * @prop: pointer to a struct touchscreen_properties | |
170 | * @x: X coordinate to store in pos | |
171 | * @y: Y coordinate to store in pos | |
172 | * | |
173 | * Adjust the passed in x and y values applying any axis inversion and | |
174 | * swapping requested in the passed in touchscreen_properties and store | |
175 | * the result in a struct input_mt_pos. | |
176 | */ | |
177 | void touchscreen_set_mt_pos(struct input_mt_pos *pos, | |
178 | const struct touchscreen_properties *prop, | |
179 | unsigned int x, unsigned int y) | |
180 | { | |
181 | touchscreen_apply_prop_to_x_y(prop, &x, &y); | |
182 | pos->x = x; | |
183 | pos->y = y; | |
184 | } | |
185 | EXPORT_SYMBOL(touchscreen_set_mt_pos); | |
186 | ||
187 | /** | |
188 | * touchscreen_report_pos - Report touchscreen coordinates | |
189 | * @input: input_device to report coordinates for | |
190 | * @prop: pointer to a struct touchscreen_properties | |
191 | * @x: X coordinate to report | |
192 | * @y: Y coordinate to report | |
193 | * @multitouch: Report coordinates on single-touch or multi-touch axes | |
194 | * | |
195 | * Adjust the passed in x and y values applying any axis inversion and | |
196 | * swapping requested in the passed in touchscreen_properties and then | |
197 | * report the resulting coordinates on the input_dev's x and y axis. | |
198 | */ | |
199 | void touchscreen_report_pos(struct input_dev *input, | |
200 | const struct touchscreen_properties *prop, | |
201 | unsigned int x, unsigned int y, | |
202 | bool multitouch) | |
203 | { | |
204 | touchscreen_apply_prop_to_x_y(prop, &x, &y); | |
205 | input_report_abs(input, multitouch ? ABS_MT_POSITION_X : ABS_X, x); | |
206 | input_report_abs(input, multitouch ? ABS_MT_POSITION_Y : ABS_Y, y); | |
207 | } | |
208 | EXPORT_SYMBOL(touchscreen_report_pos); | |
43173a0e AB |
209 | |
210 | MODULE_LICENSE("GPL v2"); | |
211 | MODULE_DESCRIPTION("Device-tree helpers functions for touchscreen devices"); |