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