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