// SPDX-License-Identifier: GPL-2.0-or-later /* * Allwinner sunxi resistive touchscreen controller driver * * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com> * * The hwmon parts are based on work by Corentin LABBE which is: * Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com>
*/
/* * The sun4i-ts controller is capable of detecting a second touch, but when a * second touch is present then the accuracy becomes so bad the reported touch * location is not useable. * * The original android driver contains some complicated heuristics using the * aprox. distance between the 2 touches to see if the user is making a pinch * open / close movement, and then reports emulated multi-touch events around * the last touch coordinate (as the dual-touch coordinates are worthless). * * These kinds of heuristics are just asking for trouble (and don't belong * in the kernel). So this driver offers straight forward, reliable single * touch functionality only. * * s.a. A20 User Manual "1.15 TP" (Documentation/arch/arm/sunxi.rst) * (looks like the description in the A20 User Manual v1.3 is better * than the one in the A10 User Manual v.1.5)
*/
if (reg_val & FIFO_DATA_PENDING) {
x = readl(ts->base + TP_DATA);
y = readl(ts->base + TP_DATA); /* The 1st location reported after an up event is unreliable */ if (!ts->ignore_fifo_data) {
input_report_abs(ts->input, ABS_X, x);
input_report_abs(ts->input, ABS_Y, y); /* * The hardware has a separate down status bit, but * that gets set before we get the first location, * resulting in reporting a click on the old location.
*/
input_report_key(ts->input, BTN_TOUCH, 1);
input_sync(ts->input);
} else {
ts->ignore_fifo_data = false;
}
}
ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); if (!ts) return -ENOMEM;
ts->dev = dev;
ts->ignore_fifo_data = true;
ts->temp_data = -1; if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) { /* Allwinner SDK has temperature (C) = (value / 6) - 271 */
ts->temp_offset = 271000;
ts->temp_step = 167;
} elseif (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) { /* * The A10 temperature sensor has quite a wide spread, these * parameters are based on the averaging of the calibration * results of 4 completely different boards, with a spread of * temp_step from 0.096 - 0.170 and temp_offset from 176 - 331.
*/
ts->temp_offset = 257000;
ts->temp_step = 133;
} else { /* * The user manuals do not contain the formula for calculating * the temperature. The formula used here is from the AXP209, * which is designed by X-Powers, an affiliate of Allwinner: * * temperature (C) = (value * 0.1) - 144.7 * * Allwinner does not have any documentation whatsoever for * this hardware. Moreover, it is claimed that the sensor * is inaccurate and cannot work properly.
*/
ts->temp_offset = 144700;
ts->temp_step = 100;
}
ts_attached = of_property_read_bool(np, "allwinner,ts-attached"); if (ts_attached) {
ts->input = devm_input_allocate_device(dev); if (!ts->input) return -ENOMEM;
/* * tp_sensitive_adjust is an optional property * tp_mode = 0 : only x and y coordinates, as we don't use dual touch
*/
of_property_read_u32(np, "allwinner,tp-sensitive-adjust",
&tp_sensitive_adjust);
writel(TP_SENSITIVE_ADJUST(tp_sensitive_adjust) | TP_MODE_SELECT(0),
ts->base + TP_CTRL2);
/* * Enable median and averaging filter, optional property for * filter type.
*/
of_property_read_u32(np, "allwinner,filter-type", &filter_type);
writel(FILTER_EN(1) | FILTER_TYPE(filter_type), ts->base + TP_CTRL3);
/* Enable temperature measurement, period 1953 (2 seconds) */
writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);
/* * Set stylus up debounce to aprox 10 ms, enable debounce, and * finally enable tp mode.
*/
reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1); if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts"))
reg |= SUN6I_TP_MODE_EN(1); else
reg |= TP_MODE_EN(1);
writel(reg, ts->base + TP_CTRL1);
/* * The thermal core does not register hwmon devices for DT-based * thermal zone sensors, such as this one.
*/
hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
ts, sun4i_ts_groups); if (IS_ERR(hwmon)) return PTR_ERR(hwmon);
thermal = devm_thermal_of_zone_register(ts->dev, 0, ts,
&sun4i_ts_tz_ops); if (IS_ERR(thermal)) return PTR_ERR(thermal);
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
if (ts_attached) {
error = input_register_device(ts->input); if (error) {
writel(0, ts->base + TP_INT_FIFOC); return error;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.