mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 02:50:43 +00:00
Input: resistive-adc-touch - add support for z1 and z2 channels
This patch adds support for the z1 and z2 channels. These are used to calculate the applied pressure. As there is no common order of the individual channels of a resistive touch ADC, support for io-channel-names is added (although the DT bindings stated the driver already supports these). Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Link: https://lore.kernel.org/r/20210525054634.9134-5-o.rempel@pengutronix.de Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
241a952f90
commit
fb082cd59a
1 changed files with 126 additions and 14 deletions
|
@ -20,7 +20,18 @@
|
||||||
|
|
||||||
#define DRIVER_NAME "resistive-adc-touch"
|
#define DRIVER_NAME "resistive-adc-touch"
|
||||||
#define GRTS_DEFAULT_PRESSURE_MIN 50000
|
#define GRTS_DEFAULT_PRESSURE_MIN 50000
|
||||||
|
#define GRTS_DEFAULT_PRESSURE_MAX 65535
|
||||||
#define GRTS_MAX_POS_MASK GENMASK(11, 0)
|
#define GRTS_MAX_POS_MASK GENMASK(11, 0)
|
||||||
|
#define GRTS_MAX_CHANNELS 4
|
||||||
|
|
||||||
|
enum grts_ch_type {
|
||||||
|
GRTS_CH_NONE = 0,
|
||||||
|
GRTS_CH_X,
|
||||||
|
GRTS_CH_Y,
|
||||||
|
GRTS_CH_PRESSURE,
|
||||||
|
GRTS_CH_Z1,
|
||||||
|
GRTS_CH_Z2,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct grts_state - generic resistive touch screen information struct
|
* struct grts_state - generic resistive touch screen information struct
|
||||||
|
@ -33,24 +44,59 @@
|
||||||
*/
|
*/
|
||||||
struct grts_state {
|
struct grts_state {
|
||||||
u32 pressure_min;
|
u32 pressure_min;
|
||||||
|
u32 x_plate_ohms;
|
||||||
bool pressure;
|
bool pressure;
|
||||||
struct iio_channel *iio_chans;
|
struct iio_channel *iio_chans;
|
||||||
struct iio_cb_buffer *iio_cb;
|
struct iio_cb_buffer *iio_cb;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
struct touchscreen_properties prop;
|
struct touchscreen_properties prop;
|
||||||
|
u8 ch[GRTS_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int grts_cb(const void *data, void *private)
|
static int grts_cb(const void *data, void *private)
|
||||||
{
|
{
|
||||||
const u16 *touch_info = data;
|
const u16 *touch_info = data;
|
||||||
struct grts_state *st = private;
|
struct grts_state *st = private;
|
||||||
unsigned int x, y, press = 0x0;
|
unsigned int x, y, press = 0, z1 = 0, z2;
|
||||||
|
unsigned int Rt, i;
|
||||||
|
|
||||||
/* channel data coming in buffer in the order below */
|
for (i = 0; i < ARRAY_SIZE(st->ch) && st->ch[i] != GRTS_CH_NONE; i++) {
|
||||||
x = touch_info[0];
|
switch (st->ch[i]) {
|
||||||
y = touch_info[1];
|
case GRTS_CH_X:
|
||||||
if (st->pressure)
|
x = touch_info[i];
|
||||||
press = touch_info[2];
|
break;
|
||||||
|
case GRTS_CH_Y:
|
||||||
|
y = touch_info[i];
|
||||||
|
break;
|
||||||
|
case GRTS_CH_PRESSURE:
|
||||||
|
press = touch_info[i];
|
||||||
|
break;
|
||||||
|
case GRTS_CH_Z1:
|
||||||
|
z1 = touch_info[i];
|
||||||
|
break;
|
||||||
|
case GRTS_CH_Z2:
|
||||||
|
z2 = touch_info[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z1) {
|
||||||
|
Rt = z2;
|
||||||
|
Rt -= z1;
|
||||||
|
Rt *= st->x_plate_ohms;
|
||||||
|
Rt = DIV_ROUND_CLOSEST(Rt, 16);
|
||||||
|
Rt *= x;
|
||||||
|
Rt /= z1;
|
||||||
|
Rt = DIV_ROUND_CLOSEST(Rt, 256);
|
||||||
|
/*
|
||||||
|
* On increased pressure the resistance (Rt) is decreasing
|
||||||
|
* so, convert values to make it looks as real pressure.
|
||||||
|
*/
|
||||||
|
if (Rt < GRTS_DEFAULT_PRESSURE_MAX)
|
||||||
|
press = GRTS_DEFAULT_PRESSURE_MAX - Rt;
|
||||||
|
else
|
||||||
|
press = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((!x && !y) || (st->pressure && (press < st->pressure_min))) {
|
if ((!x && !y) || (st->pressure && (press < st->pressure_min))) {
|
||||||
/* report end of touch */
|
/* report end of touch */
|
||||||
|
@ -94,12 +140,77 @@ static void grts_disable(void *data)
|
||||||
iio_channel_release_all_cb(data);
|
iio_channel_release_all_cb(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int grts_get_properties(struct grts_state *st, struct device *dev)
|
||||||
|
{
|
||||||
|
int idx, error;
|
||||||
|
|
||||||
|
idx = device_property_match_string(dev, "io-channel-names", "x");
|
||||||
|
if (idx < 0)
|
||||||
|
return idx;
|
||||||
|
|
||||||
|
if (idx >= ARRAY_SIZE(st->ch))
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
st->ch[idx] = GRTS_CH_X;
|
||||||
|
|
||||||
|
idx = device_property_match_string(dev, "io-channel-names", "y");
|
||||||
|
if (idx < 0)
|
||||||
|
return idx;
|
||||||
|
|
||||||
|
if (idx >= ARRAY_SIZE(st->ch))
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
st->ch[idx] = GRTS_CH_Y;
|
||||||
|
|
||||||
|
/* pressure is optional */
|
||||||
|
idx = device_property_match_string(dev, "io-channel-names", "pressure");
|
||||||
|
if (idx >= 0) {
|
||||||
|
if (idx >= ARRAY_SIZE(st->ch))
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
st->ch[idx] = GRTS_CH_PRESSURE;
|
||||||
|
st->pressure = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if no pressure is defined, try optional z1 + z2 */
|
||||||
|
idx = device_property_match_string(dev, "io-channel-names", "z1");
|
||||||
|
if (idx < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (idx >= ARRAY_SIZE(st->ch))
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
st->ch[idx] = GRTS_CH_Z1;
|
||||||
|
|
||||||
|
/* if z1 is provided z2 is not optional */
|
||||||
|
idx = device_property_match_string(dev, "io-channel-names", "z2");
|
||||||
|
if (idx < 0)
|
||||||
|
return idx;
|
||||||
|
|
||||||
|
if (idx >= ARRAY_SIZE(st->ch))
|
||||||
|
return -EOVERFLOW;
|
||||||
|
|
||||||
|
st->ch[idx] = GRTS_CH_Z2;
|
||||||
|
st->pressure = true;
|
||||||
|
|
||||||
|
error = device_property_read_u32(dev,
|
||||||
|
"touchscreen-x-plate-ohms",
|
||||||
|
&st->x_plate_ohms);
|
||||||
|
if (error) {
|
||||||
|
dev_err(dev, "can't get touchscreen-x-plate-ohms property\n");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int grts_probe(struct platform_device *pdev)
|
static int grts_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct grts_state *st;
|
struct grts_state *st;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct iio_channel *chan;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL);
|
st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL);
|
||||||
|
@ -115,12 +226,13 @@ static int grts_probe(struct platform_device *pdev)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
chan = &st->iio_chans[0];
|
if (!device_property_present(dev, "io-channel-names"))
|
||||||
st->pressure = false;
|
return -ENODEV;
|
||||||
while (chan && chan->indio_dev) {
|
|
||||||
if (!strcmp(chan->channel->datasheet_name, "pressure"))
|
error = grts_get_properties(st, dev);
|
||||||
st->pressure = true;
|
if (error) {
|
||||||
chan++;
|
dev_err(dev, "Failed to parse properties\n");
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->pressure) {
|
if (st->pressure) {
|
||||||
|
@ -148,7 +260,7 @@ static int grts_probe(struct platform_device *pdev)
|
||||||
input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
|
input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
|
||||||
if (st->pressure)
|
if (st->pressure)
|
||||||
input_set_abs_params(input, ABS_PRESSURE, st->pressure_min,
|
input_set_abs_params(input, ABS_PRESSURE, st->pressure_min,
|
||||||
0xffff, 0, 0);
|
GRTS_DEFAULT_PRESSURE_MAX, 0, 0);
|
||||||
|
|
||||||
input_set_capability(input, EV_KEY, BTN_TOUCH);
|
input_set_capability(input, EV_KEY, BTN_TOUCH);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue