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