Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
ff8f8370 AD |
2 | /* |
3 | * Copyright (c) 2011-2016 Synaptics Incorporated | |
4 | * Copyright (c) 2011 Unixphere | |
ff8f8370 AD |
5 | */ |
6 | ||
7 | #include <linux/kernel.h> | |
8 | #include <linux/device.h> | |
9 | #include <linux/of.h> | |
10 | #include <linux/input.h> | |
11 | #include <linux/input/mt.h> | |
12 | #include <linux/rmi.h> | |
13 | #include "rmi_driver.h" | |
14 | #include "rmi_2d_sensor.h" | |
15 | ||
16 | #define RMI_2D_REL_POS_MIN -128 | |
17 | #define RMI_2D_REL_POS_MAX 127 | |
18 | ||
19 | /* maximum ABS_MT_POSITION displacement (in mm) */ | |
20 | #define DMAX 10 | |
21 | ||
22 | void rmi_2d_sensor_abs_process(struct rmi_2d_sensor *sensor, | |
23 | struct rmi_2d_sensor_abs_object *obj, | |
24 | int slot) | |
25 | { | |
26 | struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align; | |
27 | ||
28 | /* we keep the previous values if the finger is released */ | |
29 | if (obj->type == RMI_2D_OBJECT_NONE) | |
30 | return; | |
31 | ||
ff8f8370 AD |
32 | if (axis_align->flip_x) |
33 | obj->x = sensor->max_x - obj->x; | |
34 | ||
35 | if (axis_align->flip_y) | |
36 | obj->y = sensor->max_y - obj->y; | |
37 | ||
645a397d LS |
38 | if (axis_align->swap_axes) |
39 | swap(obj->x, obj->y); | |
40 | ||
ff8f8370 AD |
41 | /* |
42 | * Here checking if X offset or y offset are specified is | |
43 | * redundant. We just add the offsets or clip the values. | |
44 | * | |
45 | * Note: offsets need to be applied before clipping occurs, | |
46 | * or we could get funny values that are outside of | |
47 | * clipping boundaries. | |
48 | */ | |
49 | obj->x += axis_align->offset_x; | |
50 | obj->y += axis_align->offset_y; | |
51 | ||
52 | obj->x = max(axis_align->clip_x_low, obj->x); | |
53 | obj->y = max(axis_align->clip_y_low, obj->y); | |
54 | ||
55 | if (axis_align->clip_x_high) | |
56 | obj->x = min(sensor->max_x, obj->x); | |
57 | ||
58 | if (axis_align->clip_y_high) | |
59 | obj->y = min(sensor->max_y, obj->y); | |
60 | ||
61 | sensor->tracking_pos[slot].x = obj->x; | |
62 | sensor->tracking_pos[slot].y = obj->y; | |
63 | } | |
64 | EXPORT_SYMBOL_GPL(rmi_2d_sensor_abs_process); | |
65 | ||
66 | void rmi_2d_sensor_abs_report(struct rmi_2d_sensor *sensor, | |
67 | struct rmi_2d_sensor_abs_object *obj, | |
68 | int slot) | |
69 | { | |
70 | struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align; | |
71 | struct input_dev *input = sensor->input; | |
72 | int wide, major, minor; | |
73 | ||
74 | if (sensor->kernel_tracking) | |
75 | input_mt_slot(input, sensor->tracking_slots[slot]); | |
76 | else | |
77 | input_mt_slot(input, slot); | |
78 | ||
79 | input_mt_report_slot_state(input, obj->mt_tool, | |
80 | obj->type != RMI_2D_OBJECT_NONE); | |
81 | ||
82 | if (obj->type != RMI_2D_OBJECT_NONE) { | |
83 | obj->x = sensor->tracking_pos[slot].x; | |
84 | obj->y = sensor->tracking_pos[slot].y; | |
85 | ||
86 | if (axis_align->swap_axes) | |
87 | swap(obj->wx, obj->wy); | |
88 | ||
89 | wide = (obj->wx > obj->wy); | |
90 | major = max(obj->wx, obj->wy); | |
91 | minor = min(obj->wx, obj->wy); | |
92 | ||
93 | if (obj->type == RMI_2D_OBJECT_STYLUS) { | |
94 | major = max(1, major); | |
95 | minor = max(1, minor); | |
96 | } | |
97 | ||
98 | input_event(sensor->input, EV_ABS, ABS_MT_POSITION_X, obj->x); | |
99 | input_event(sensor->input, EV_ABS, ABS_MT_POSITION_Y, obj->y); | |
100 | input_event(sensor->input, EV_ABS, ABS_MT_ORIENTATION, wide); | |
101 | input_event(sensor->input, EV_ABS, ABS_MT_PRESSURE, obj->z); | |
102 | input_event(sensor->input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); | |
103 | input_event(sensor->input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); | |
104 | ||
105 | rmi_dbg(RMI_DEBUG_2D_SENSOR, &sensor->input->dev, | |
106 | "%s: obj[%d]: type: 0x%02x X: %d Y: %d Z: %d WX: %d WY: %d\n", | |
107 | __func__, slot, obj->type, obj->x, obj->y, obj->z, | |
108 | obj->wx, obj->wy); | |
109 | } | |
110 | } | |
111 | EXPORT_SYMBOL_GPL(rmi_2d_sensor_abs_report); | |
112 | ||
113 | void rmi_2d_sensor_rel_report(struct rmi_2d_sensor *sensor, int x, int y) | |
114 | { | |
115 | struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align; | |
116 | ||
117 | x = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)x)); | |
118 | y = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)y)); | |
119 | ||
ff8f8370 AD |
120 | if (axis_align->flip_x) |
121 | x = min(RMI_2D_REL_POS_MAX, -x); | |
122 | ||
123 | if (axis_align->flip_y) | |
124 | y = min(RMI_2D_REL_POS_MAX, -y); | |
125 | ||
645a397d LS |
126 | if (axis_align->swap_axes) |
127 | swap(x, y); | |
128 | ||
ff8f8370 AD |
129 | if (x || y) { |
130 | input_report_rel(sensor->input, REL_X, x); | |
131 | input_report_rel(sensor->input, REL_Y, y); | |
132 | } | |
133 | } | |
134 | EXPORT_SYMBOL_GPL(rmi_2d_sensor_rel_report); | |
135 | ||
136 | static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor) | |
137 | { | |
138 | struct input_dev *input = sensor->input; | |
139 | int res_x; | |
140 | int res_y; | |
645a397d | 141 | int max_x, max_y; |
ff8f8370 AD |
142 | int input_flags = 0; |
143 | ||
144 | if (sensor->report_abs) { | |
ff8f8370 AD |
145 | sensor->min_x = sensor->axis_align.clip_x_low; |
146 | if (sensor->axis_align.clip_x_high) | |
147 | sensor->max_x = min(sensor->max_x, | |
148 | sensor->axis_align.clip_x_high); | |
149 | ||
150 | sensor->min_y = sensor->axis_align.clip_y_low; | |
151 | if (sensor->axis_align.clip_y_high) | |
152 | sensor->max_y = min(sensor->max_y, | |
153 | sensor->axis_align.clip_y_high); | |
154 | ||
155 | set_bit(EV_ABS, input->evbit); | |
645a397d LS |
156 | |
157 | max_x = sensor->max_x; | |
158 | max_y = sensor->max_y; | |
159 | if (sensor->axis_align.swap_axes) | |
160 | swap(max_x, max_y); | |
161 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_x, 0, 0); | |
162 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_y, 0, 0); | |
ff8f8370 AD |
163 | |
164 | if (sensor->x_mm && sensor->y_mm) { | |
165 | res_x = (sensor->max_x - sensor->min_x) / sensor->x_mm; | |
166 | res_y = (sensor->max_y - sensor->min_y) / sensor->y_mm; | |
645a397d LS |
167 | if (sensor->axis_align.swap_axes) |
168 | swap(res_x, res_y); | |
ff8f8370 AD |
169 | |
170 | input_abs_set_res(input, ABS_X, res_x); | |
171 | input_abs_set_res(input, ABS_Y, res_y); | |
172 | ||
173 | input_abs_set_res(input, ABS_MT_POSITION_X, res_x); | |
174 | input_abs_set_res(input, ABS_MT_POSITION_Y, res_y); | |
175 | ||
176 | if (!sensor->dmax) | |
177 | sensor->dmax = DMAX * res_x; | |
178 | } | |
179 | ||
332c3988 AD |
180 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0); |
181 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0); | |
182 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0); | |
183 | input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); | |
184 | input_set_abs_params(input, ABS_MT_TOOL_TYPE, | |
185 | 0, MT_TOOL_MAX, 0, 0); | |
ff8f8370 AD |
186 | |
187 | if (sensor->sensor_type == rmi_sensor_touchpad) | |
188 | input_flags = INPUT_MT_POINTER; | |
189 | else | |
190 | input_flags = INPUT_MT_DIRECT; | |
191 | ||
192 | if (sensor->kernel_tracking) | |
193 | input_flags |= INPUT_MT_TRACK; | |
194 | ||
195 | input_mt_init_slots(input, sensor->nbr_fingers, input_flags); | |
196 | } | |
197 | ||
198 | if (sensor->report_rel) { | |
199 | set_bit(EV_REL, input->evbit); | |
200 | set_bit(REL_X, input->relbit); | |
201 | set_bit(REL_Y, input->relbit); | |
202 | } | |
203 | ||
204 | if (sensor->topbuttonpad) | |
205 | set_bit(INPUT_PROP_TOPBUTTONPAD, input->propbit); | |
206 | } | |
ff8f8370 AD |
207 | |
208 | int rmi_2d_sensor_configure_input(struct rmi_function *fn, | |
209 | struct rmi_2d_sensor *sensor) | |
210 | { | |
211 | struct rmi_device *rmi_dev = fn->rmi_dev; | |
212 | struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); | |
213 | ||
214 | if (!drv_data->input) | |
215 | return -ENODEV; | |
216 | ||
217 | sensor->input = drv_data->input; | |
218 | rmi_2d_sensor_set_input_params(sensor); | |
219 | ||
220 | return 0; | |
221 | } | |
222 | EXPORT_SYMBOL_GPL(rmi_2d_sensor_configure_input); | |
aaa27982 AD |
223 | |
224 | #ifdef CONFIG_OF | |
225 | int rmi_2d_sensor_of_probe(struct device *dev, | |
226 | struct rmi_2d_sensor_platform_data *pdata) | |
227 | { | |
228 | int retval; | |
229 | u32 val; | |
230 | ||
231 | pdata->axis_align.swap_axes = of_property_read_bool(dev->of_node, | |
232 | "touchscreen-swapped-x-y"); | |
233 | ||
234 | pdata->axis_align.flip_x = of_property_read_bool(dev->of_node, | |
235 | "touchscreen-inverted-x"); | |
236 | ||
237 | pdata->axis_align.flip_y = of_property_read_bool(dev->of_node, | |
238 | "touchscreen-inverted-y"); | |
239 | ||
240 | retval = rmi_of_property_read_u32(dev, &val, "syna,clip-x-low", 1); | |
241 | if (retval) | |
242 | return retval; | |
243 | ||
244 | pdata->axis_align.clip_x_low = val; | |
245 | ||
246 | retval = rmi_of_property_read_u32(dev, &val, "syna,clip-y-low", 1); | |
247 | if (retval) | |
248 | return retval; | |
249 | ||
250 | pdata->axis_align.clip_y_low = val; | |
251 | ||
252 | retval = rmi_of_property_read_u32(dev, &val, "syna,clip-x-high", 1); | |
253 | if (retval) | |
254 | return retval; | |
255 | ||
256 | pdata->axis_align.clip_x_high = val; | |
257 | ||
258 | retval = rmi_of_property_read_u32(dev, &val, "syna,clip-y-high", 1); | |
259 | if (retval) | |
260 | return retval; | |
261 | ||
262 | pdata->axis_align.clip_y_high = val; | |
263 | ||
264 | retval = rmi_of_property_read_u32(dev, &val, "syna,offset-x", 1); | |
265 | if (retval) | |
266 | return retval; | |
267 | ||
268 | pdata->axis_align.offset_x = val; | |
269 | ||
270 | retval = rmi_of_property_read_u32(dev, &val, "syna,offset-y", 1); | |
271 | if (retval) | |
272 | return retval; | |
273 | ||
274 | pdata->axis_align.offset_y = val; | |
275 | ||
276 | retval = rmi_of_property_read_u32(dev, &val, "syna,delta-x-threshold", | |
277 | 1); | |
278 | if (retval) | |
279 | return retval; | |
280 | ||
281 | pdata->axis_align.delta_x_threshold = val; | |
282 | ||
283 | retval = rmi_of_property_read_u32(dev, &val, "syna,delta-y-threshold", | |
284 | 1); | |
285 | if (retval) | |
286 | return retval; | |
287 | ||
288 | pdata->axis_align.delta_y_threshold = val; | |
289 | ||
290 | retval = rmi_of_property_read_u32(dev, (u32 *)&pdata->sensor_type, | |
291 | "syna,sensor-type", 1); | |
292 | if (retval) | |
293 | return retval; | |
294 | ||
295 | retval = rmi_of_property_read_u32(dev, &val, "touchscreen-x-mm", 1); | |
296 | if (retval) | |
297 | return retval; | |
298 | ||
299 | pdata->x_mm = val; | |
300 | ||
301 | retval = rmi_of_property_read_u32(dev, &val, "touchscreen-y-mm", 1); | |
302 | if (retval) | |
303 | return retval; | |
304 | ||
305 | pdata->y_mm = val; | |
306 | ||
307 | retval = rmi_of_property_read_u32(dev, &val, | |
308 | "syna,disable-report-mask", 1); | |
309 | if (retval) | |
310 | return retval; | |
311 | ||
312 | pdata->disable_report_mask = val; | |
313 | ||
314 | retval = rmi_of_property_read_u32(dev, &val, "syna,rezero-wait-ms", | |
315 | 1); | |
316 | if (retval) | |
317 | return retval; | |
318 | ||
319 | pdata->rezero_wait = val; | |
320 | ||
321 | return 0; | |
322 | } | |
323 | #else | |
324 | inline int rmi_2d_sensor_of_probe(struct device *dev, | |
325 | struct rmi_2d_sensor_platform_data *pdata) | |
326 | { | |
327 | return -ENODEV; | |
328 | } | |
329 | #endif | |
330 | EXPORT_SYMBOL_GPL(rmi_2d_sensor_of_probe); |