diff options
Diffstat (limited to 'drivers/input/touchscreen/resistive-adc-touch.c')
-rw-r--r-- | drivers/input/touchscreen/resistive-adc-touch.c | 136 |
1 files changed, 118 insertions, 18 deletions
diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c index e50af30183f4..744544a723b7 100644 --- a/drivers/input/touchscreen/resistive-adc-touch.c +++ b/drivers/input/touchscreen/resistive-adc-touch.c @@ -13,44 +13,78 @@ #include <linux/input/touchscreen.h> #include <linux/iio/consumer.h> #include <linux/iio/iio.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/property.h> #define DRIVER_NAME "resistive-adc-touch" #define GRTS_DEFAULT_PRESSURE_MIN 50000 +#define GRTS_DEFAULT_PRESSURE_MAX 65535 #define GRTS_MAX_POS_MASK GENMASK(11, 0) +#define GRTS_MAX_CHANNELS 4 + +enum grts_ch_type { + GRTS_CH_X, + GRTS_CH_Y, + GRTS_CH_PRESSURE, + GRTS_CH_Z1, + GRTS_CH_Z2, + GRTS_CH_MAX = GRTS_CH_Z2 + 1 +}; /** * struct grts_state - generic resistive touch screen information struct + * @x_plate_ohms: resistance of the X plate * @pressure_min: number representing the minimum for the pressure * @pressure: are we getting pressure info or not * @iio_chans: list of channels acquired * @iio_cb: iio_callback buffer for the data * @input: the input device structure that we register * @prop: touchscreen properties struct + * @ch_map: map of channels that are defined for the touchscreen */ struct grts_state { + u32 x_plate_ohms; u32 pressure_min; bool pressure; struct iio_channel *iio_chans; struct iio_cb_buffer *iio_cb; struct input_dev *input; struct touchscreen_properties prop; + u8 ch_map[GRTS_CH_MAX]; }; static int grts_cb(const void *data, void *private) { const u16 *touch_info = data; struct grts_state *st = private; - unsigned int x, y, press = 0x0; - - /* channel data coming in buffer in the order below */ - x = touch_info[0]; - y = touch_info[1]; - if (st->pressure) - press = touch_info[2]; + unsigned int x, y, press = 0; + + x = touch_info[st->ch_map[GRTS_CH_X]]; + y = touch_info[st->ch_map[GRTS_CH_Y]]; + + if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) { + press = touch_info[st->ch_map[GRTS_CH_PRESSURE]]; + } else if (st->ch_map[GRTS_CH_Z1] < GRTS_MAX_CHANNELS) { + unsigned int z1 = touch_info[st->ch_map[GRTS_CH_Z1]]; + unsigned int z2 = touch_info[st->ch_map[GRTS_CH_Z2]]; + unsigned int Rt; + + 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; + } if ((!x && !y) || (st->pressure && (press < st->pressure_min))) { /* report end of touch */ @@ -94,12 +128,77 @@ static void grts_disable(void *data) iio_channel_release_all_cb(data); } +static int grts_map_channel(struct grts_state *st, struct device *dev, + enum grts_ch_type type, const char *name, + bool optional) +{ + int idx; + + idx = device_property_match_string(dev, "io-channel-names", name); + if (idx < 0) { + if (!optional) + return idx; + idx = GRTS_MAX_CHANNELS; + } else if (idx >= GRTS_MAX_CHANNELS) { + return -EOVERFLOW; + } + + st->ch_map[type] = idx; + return 0; +} + +static int grts_get_properties(struct grts_state *st, struct device *dev) +{ + int error; + + error = grts_map_channel(st, dev, GRTS_CH_X, "x", false); + if (error) + return error; + + error = grts_map_channel(st, dev, GRTS_CH_Y, "y", false); + if (error) + return error; + + /* pressure is optional */ + error = grts_map_channel(st, dev, GRTS_CH_PRESSURE, "pressure", true); + if (error) + return error; + + if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) { + st->pressure = true; + return 0; + } + + /* if no pressure is defined, try optional z1 + z2 */ + error = grts_map_channel(st, dev, GRTS_CH_Z1, "z1", true); + if (error) + return error; + + if (st->ch_map[GRTS_CH_Z1] >= GRTS_MAX_CHANNELS) + return 0; + + /* if z1 is provided z2 is not optional */ + error = grts_map_channel(st, dev, GRTS_CH_Z2, "z2", true); + if (error) + return error; + + 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; + } + + st->pressure = true; + return 0; +} + static int grts_probe(struct platform_device *pdev) { struct grts_state *st; struct input_dev *input; struct device *dev = &pdev->dev; - struct iio_channel *chan; int error; st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL); @@ -115,12 +214,13 @@ static int grts_probe(struct platform_device *pdev) return error; } - chan = &st->iio_chans[0]; - st->pressure = false; - while (chan && chan->indio_dev) { - if (!strcmp(chan->channel->datasheet_name, "pressure")) - st->pressure = true; - chan++; + if (!device_property_present(dev, "io-channel-names")) + return -ENODEV; + + error = grts_get_properties(st, dev); + if (error) { + dev_err(dev, "Failed to parse properties\n"); + return error; } if (st->pressure) { @@ -148,7 +248,7 @@ static int grts_probe(struct platform_device *pdev) input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0); if (st->pressure) 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); @@ -193,7 +293,7 @@ static struct platform_driver grts_driver = { .probe = grts_probe, .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(grts_of_match), + .of_match_table = grts_of_match, }, }; |