18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Generic DT helper functions for touchscreen devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Sebastian Reichel <sre@kernel.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/property.h> 98c2ecf20Sopenharmony_ci#include <linux/input.h> 108c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 118c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic bool touchscreen_get_prop_u32(struct device *dev, 158c2ecf20Sopenharmony_ci const char *property, 168c2ecf20Sopenharmony_ci unsigned int default_value, 178c2ecf20Sopenharmony_ci unsigned int *value) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci u32 val; 208c2ecf20Sopenharmony_ci int error; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci error = device_property_read_u32(dev, property, &val); 238c2ecf20Sopenharmony_ci if (error) { 248c2ecf20Sopenharmony_ci *value = default_value; 258c2ecf20Sopenharmony_ci return false; 268c2ecf20Sopenharmony_ci } 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci *value = val; 298c2ecf20Sopenharmony_ci return true; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic void touchscreen_set_params(struct input_dev *dev, 338c2ecf20Sopenharmony_ci unsigned long axis, 348c2ecf20Sopenharmony_ci int min, int max, int fuzz) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct input_absinfo *absinfo; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (!test_bit(axis, dev->absbit)) { 398c2ecf20Sopenharmony_ci dev_warn(&dev->dev, 408c2ecf20Sopenharmony_ci "DT specifies parameters but the axis %lu is not set up\n", 418c2ecf20Sopenharmony_ci axis); 428c2ecf20Sopenharmony_ci return; 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci absinfo = &dev->absinfo[axis]; 468c2ecf20Sopenharmony_ci absinfo->minimum = min; 478c2ecf20Sopenharmony_ci absinfo->maximum = max; 488c2ecf20Sopenharmony_ci absinfo->fuzz = fuzz; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/** 528c2ecf20Sopenharmony_ci * touchscreen_parse_properties - parse common touchscreen DT properties 538c2ecf20Sopenharmony_ci * @input: input device that should be parsed 548c2ecf20Sopenharmony_ci * @multitouch: specifies whether parsed properties should be applied to 558c2ecf20Sopenharmony_ci * single-touch or multi-touch axes 568c2ecf20Sopenharmony_ci * @prop: pointer to a struct touchscreen_properties into which to store 578c2ecf20Sopenharmony_ci * axis swap and invert info for use with touchscreen_report_x_y(); 588c2ecf20Sopenharmony_ci * or %NULL 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * This function parses common DT properties for touchscreens and setups the 618c2ecf20Sopenharmony_ci * input device accordingly. The function keeps previously set up default 628c2ecf20Sopenharmony_ci * values if no value is specified via DT. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_civoid touchscreen_parse_properties(struct input_dev *input, bool multitouch, 658c2ecf20Sopenharmony_ci struct touchscreen_properties *prop) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct device *dev = input->dev.parent; 688c2ecf20Sopenharmony_ci struct input_absinfo *absinfo; 698c2ecf20Sopenharmony_ci unsigned int axis, axis_x, axis_y; 708c2ecf20Sopenharmony_ci unsigned int minimum, maximum, fuzz; 718c2ecf20Sopenharmony_ci bool data_present; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci input_alloc_absinfo(input); 748c2ecf20Sopenharmony_ci if (!input->absinfo) 758c2ecf20Sopenharmony_ci return; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci axis_x = multitouch ? ABS_MT_POSITION_X : ABS_X; 788c2ecf20Sopenharmony_ci axis_y = multitouch ? ABS_MT_POSITION_Y : ABS_Y; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x", 818c2ecf20Sopenharmony_ci input_abs_get_min(input, axis_x), 828c2ecf20Sopenharmony_ci &minimum); 838c2ecf20Sopenharmony_ci data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-x", 848c2ecf20Sopenharmony_ci input_abs_get_max(input, 858c2ecf20Sopenharmony_ci axis_x) + 1, 868c2ecf20Sopenharmony_ci &maximum); 878c2ecf20Sopenharmony_ci data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x", 888c2ecf20Sopenharmony_ci input_abs_get_fuzz(input, axis_x), 898c2ecf20Sopenharmony_ci &fuzz); 908c2ecf20Sopenharmony_ci if (data_present) 918c2ecf20Sopenharmony_ci touchscreen_set_params(input, axis_x, minimum, maximum - 1, fuzz); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y", 948c2ecf20Sopenharmony_ci input_abs_get_min(input, axis_y), 958c2ecf20Sopenharmony_ci &minimum); 968c2ecf20Sopenharmony_ci data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-y", 978c2ecf20Sopenharmony_ci input_abs_get_max(input, 988c2ecf20Sopenharmony_ci axis_y) + 1, 998c2ecf20Sopenharmony_ci &maximum); 1008c2ecf20Sopenharmony_ci data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y", 1018c2ecf20Sopenharmony_ci input_abs_get_fuzz(input, axis_y), 1028c2ecf20Sopenharmony_ci &fuzz); 1038c2ecf20Sopenharmony_ci if (data_present) 1048c2ecf20Sopenharmony_ci touchscreen_set_params(input, axis_y, minimum, maximum - 1, fuzz); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; 1078c2ecf20Sopenharmony_ci data_present = touchscreen_get_prop_u32(dev, 1088c2ecf20Sopenharmony_ci "touchscreen-max-pressure", 1098c2ecf20Sopenharmony_ci input_abs_get_max(input, axis), 1108c2ecf20Sopenharmony_ci &maximum); 1118c2ecf20Sopenharmony_ci data_present |= touchscreen_get_prop_u32(dev, 1128c2ecf20Sopenharmony_ci "touchscreen-fuzz-pressure", 1138c2ecf20Sopenharmony_ci input_abs_get_fuzz(input, axis), 1148c2ecf20Sopenharmony_ci &fuzz); 1158c2ecf20Sopenharmony_ci if (data_present) 1168c2ecf20Sopenharmony_ci touchscreen_set_params(input, axis, 0, maximum, fuzz); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (!prop) 1198c2ecf20Sopenharmony_ci return; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci prop->max_x = input_abs_get_max(input, axis_x); 1228c2ecf20Sopenharmony_ci prop->max_y = input_abs_get_max(input, axis_y); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci prop->invert_x = 1258c2ecf20Sopenharmony_ci device_property_read_bool(dev, "touchscreen-inverted-x"); 1268c2ecf20Sopenharmony_ci if (prop->invert_x) { 1278c2ecf20Sopenharmony_ci absinfo = &input->absinfo[axis_x]; 1288c2ecf20Sopenharmony_ci absinfo->maximum -= absinfo->minimum; 1298c2ecf20Sopenharmony_ci absinfo->minimum = 0; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci prop->invert_y = 1338c2ecf20Sopenharmony_ci device_property_read_bool(dev, "touchscreen-inverted-y"); 1348c2ecf20Sopenharmony_ci if (prop->invert_y) { 1358c2ecf20Sopenharmony_ci absinfo = &input->absinfo[axis_y]; 1368c2ecf20Sopenharmony_ci absinfo->maximum -= absinfo->minimum; 1378c2ecf20Sopenharmony_ci absinfo->minimum = 0; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci prop->swap_x_y = 1418c2ecf20Sopenharmony_ci device_property_read_bool(dev, "touchscreen-swapped-x-y"); 1428c2ecf20Sopenharmony_ci if (prop->swap_x_y) 1438c2ecf20Sopenharmony_ci swap(input->absinfo[axis_x], input->absinfo[axis_y]); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(touchscreen_parse_properties); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic void 1488c2ecf20Sopenharmony_citouchscreen_apply_prop_to_x_y(const struct touchscreen_properties *prop, 1498c2ecf20Sopenharmony_ci unsigned int *x, unsigned int *y) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci if (prop->invert_x) 1528c2ecf20Sopenharmony_ci *x = prop->max_x - *x; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (prop->invert_y) 1558c2ecf20Sopenharmony_ci *y = prop->max_y - *y; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (prop->swap_x_y) 1588c2ecf20Sopenharmony_ci swap(*x, *y); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/** 1628c2ecf20Sopenharmony_ci * touchscreen_set_mt_pos - Set input_mt_pos coordinates 1638c2ecf20Sopenharmony_ci * @pos: input_mt_pos to set coordinates of 1648c2ecf20Sopenharmony_ci * @prop: pointer to a struct touchscreen_properties 1658c2ecf20Sopenharmony_ci * @x: X coordinate to store in pos 1668c2ecf20Sopenharmony_ci * @y: Y coordinate to store in pos 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * Adjust the passed in x and y values applying any axis inversion and 1698c2ecf20Sopenharmony_ci * swapping requested in the passed in touchscreen_properties and store 1708c2ecf20Sopenharmony_ci * the result in a struct input_mt_pos. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_civoid touchscreen_set_mt_pos(struct input_mt_pos *pos, 1738c2ecf20Sopenharmony_ci const struct touchscreen_properties *prop, 1748c2ecf20Sopenharmony_ci unsigned int x, unsigned int y) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci touchscreen_apply_prop_to_x_y(prop, &x, &y); 1778c2ecf20Sopenharmony_ci pos->x = x; 1788c2ecf20Sopenharmony_ci pos->y = y; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(touchscreen_set_mt_pos); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/** 1838c2ecf20Sopenharmony_ci * touchscreen_report_pos - Report touchscreen coordinates 1848c2ecf20Sopenharmony_ci * @input: input_device to report coordinates for 1858c2ecf20Sopenharmony_ci * @prop: pointer to a struct touchscreen_properties 1868c2ecf20Sopenharmony_ci * @x: X coordinate to report 1878c2ecf20Sopenharmony_ci * @y: Y coordinate to report 1888c2ecf20Sopenharmony_ci * @multitouch: Report coordinates on single-touch or multi-touch axes 1898c2ecf20Sopenharmony_ci * 1908c2ecf20Sopenharmony_ci * Adjust the passed in x and y values applying any axis inversion and 1918c2ecf20Sopenharmony_ci * swapping requested in the passed in touchscreen_properties and then 1928c2ecf20Sopenharmony_ci * report the resulting coordinates on the input_dev's x and y axis. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_civoid touchscreen_report_pos(struct input_dev *input, 1958c2ecf20Sopenharmony_ci const struct touchscreen_properties *prop, 1968c2ecf20Sopenharmony_ci unsigned int x, unsigned int y, 1978c2ecf20Sopenharmony_ci bool multitouch) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci touchscreen_apply_prop_to_x_y(prop, &x, &y); 2008c2ecf20Sopenharmony_ci input_report_abs(input, multitouch ? ABS_MT_POSITION_X : ABS_X, x); 2018c2ecf20Sopenharmony_ci input_report_abs(input, multitouch ? ABS_MT_POSITION_Y : ABS_Y, y); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(touchscreen_report_pos); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2068c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Device-tree helpers functions for touchscreen devices"); 207