File Index
Files and directories
Sign in
FILE

rmi_2d_sensor.c

File preview with syntax highlighting.

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