1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ADC generic resistive touchscreen (GRTS) 4 * This is a generic input driver that connects to an ADC 5 * given the channels in device tree, and reports events to the input 6 * subsystem. 7 * 8 * Copyright (C) 2017,2018 Microchip Technology, 9 * Author: Eugen Hristev <eugen.hristev@microchip.com> 10 * 11 */ 12 #include <linux/input.h> 13 #include <linux/input/touchscreen.h> 14 #include <linux/iio/consumer.h> 15 #include <linux/iio/iio.h> 16 #include <linux/mod_devicetable.h> 17 #include <linux/module.h> 18 #include <linux/platform_device.h> 19 #include <linux/property.h> 20 21 #define DRIVER_NAME "resistive-adc-touch" 22 #define GRTS_DEFAULT_PRESSURE_MIN 50000 23 #define GRTS_DEFAULT_PRESSURE_MAX 65535 24 #define GRTS_MAX_POS_MASK GENMASK(11, 0) 25 #define GRTS_MAX_CHANNELS 4 26 27 enum grts_ch_type { 28 GRTS_CH_X, 29 GRTS_CH_Y, 30 GRTS_CH_PRESSURE, 31 GRTS_CH_Z1, 32 GRTS_CH_Z2, 33 GRTS_CH_MAX = GRTS_CH_Z2 + 1 34 }; 35 36 /** 37 * struct grts_state - generic resistive touch screen information struct 38 * @x_plate_ohms: resistance of the X plate 39 * @pressure_min: number representing the minimum for the pressure 40 * @pressure: are we getting pressure info or not 41 * @iio_chans: list of channels acquired 42 * @iio_cb: iio_callback buffer for the data 43 * @input: the input device structure that we register 44 * @prop: touchscreen properties struct 45 * @ch_map: map of channels that are defined for the touchscreen 46 */ 47 struct grts_state { 48 u32 x_plate_ohms; 49 u32 pressure_min; 50 bool pressure; 51 struct iio_channel *iio_chans; 52 struct iio_cb_buffer *iio_cb; 53 struct input_dev *input; 54 struct touchscreen_properties prop; 55 u8 ch_map[GRTS_CH_MAX]; 56 }; 57 58 static int grts_cb(const void *data, void *private) 59 { 60 const u16 *touch_info = data; 61 struct grts_state *st = private; 62 unsigned int x, y, press = 0; 63 64 x = touch_info[st->ch_map[GRTS_CH_X]]; 65 y = touch_info[st->ch_map[GRTS_CH_Y]]; 66 67 if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) { 68 press = touch_info[st->ch_map[GRTS_CH_PRESSURE]]; 69 } else if (st->ch_map[GRTS_CH_Z1] < GRTS_MAX_CHANNELS) { 70 unsigned int z1 = touch_info[st->ch_map[GRTS_CH_Z1]]; 71 unsigned int z2 = touch_info[st->ch_map[GRTS_CH_Z2]]; 72 unsigned int Rt; 73 74 Rt = z2; 75 Rt -= z1; 76 Rt *= st->x_plate_ohms; 77 Rt = DIV_ROUND_CLOSEST(Rt, 16); 78 Rt *= x; 79 Rt /= z1; 80 Rt = DIV_ROUND_CLOSEST(Rt, 256); 81 /* 82 * On increased pressure the resistance (Rt) is decreasing 83 * so, convert values to make it looks as real pressure. 84 */ 85 if (Rt < GRTS_DEFAULT_PRESSURE_MAX) 86 press = GRTS_DEFAULT_PRESSURE_MAX - Rt; 87 } 88 89 if ((!x && !y) || (st->pressure && (press < st->pressure_min))) { 90 /* report end of touch */ 91 input_report_key(st->input, BTN_TOUCH, 0); 92 input_sync(st->input); 93 return 0; 94 } 95 96 /* report proper touch to subsystem*/ 97 touchscreen_report_pos(st->input, &st->prop, x, y, false); 98 if (st->pressure) 99 input_report_abs(st->input, ABS_PRESSURE, press); 100 input_report_key(st->input, BTN_TOUCH, 1); 101 input_sync(st->input); 102 103 return 0; 104 } 105 106 static int grts_open(struct input_dev *dev) 107 { 108 int error; 109 struct grts_state *st = input_get_drvdata(dev); 110 111 error = iio_channel_start_all_cb(st->iio_cb); 112 if (error) { 113 dev_err(dev->dev.parent, "failed to start callback buffer.\n"); 114 return error; 115 } 116 return 0; 117 } 118 119 static void grts_close(struct input_dev *dev) 120 { 121 struct grts_state *st = input_get_drvdata(dev); 122 123 iio_channel_stop_all_cb(st->iio_cb); 124 } 125 126 static void grts_disable(void *data) 127 { 128 iio_channel_release_all_cb(data); 129 } 130 131 static int grts_map_channel(struct grts_state *st, struct device *dev, 132 enum grts_ch_type type, const char *name, 133 bool optional) 134 { 135 int idx; 136 137 idx = device_property_match_string(dev, "io-channel-names", name); 138 if (idx < 0) { 139 if (!optional) 140 return idx; 141 idx = GRTS_MAX_CHANNELS; 142 } else if (idx >= GRTS_MAX_CHANNELS) { 143 return -EOVERFLOW; 144 } 145 146 st->ch_map[type] = idx; 147 return 0; 148 } 149 150 static int grts_get_properties(struct grts_state *st, struct device *dev) 151 { 152 int error; 153 154 error = grts_map_channel(st, dev, GRTS_CH_X, "x", false); 155 if (error) 156 return error; 157 158 error = grts_map_channel(st, dev, GRTS_CH_Y, "y", false); 159 if (error) 160 return error; 161 162 /* pressure is optional */ 163 error = grts_map_channel(st, dev, GRTS_CH_PRESSURE, "pressure", true); 164 if (error) 165 return error; 166 167 if (st->ch_map[GRTS_CH_PRESSURE] < GRTS_MAX_CHANNELS) { 168 st->pressure = true; 169 return 0; 170 } 171 172 /* if no pressure is defined, try optional z1 + z2 */ 173 error = grts_map_channel(st, dev, GRTS_CH_Z1, "z1", true); 174 if (error) 175 return error; 176 177 if (st->ch_map[GRTS_CH_Z1] >= GRTS_MAX_CHANNELS) 178 return 0; 179 180 /* if z1 is provided z2 is not optional */ 181 error = grts_map_channel(st, dev, GRTS_CH_Z2, "z2", true); 182 if (error) 183 return error; 184 185 error = device_property_read_u32(dev, 186 "touchscreen-x-plate-ohms", 187 &st->x_plate_ohms); 188 if (error) { 189 dev_err(dev, "can't get touchscreen-x-plate-ohms property\n"); 190 return error; 191 } 192 193 st->pressure = true; 194 return 0; 195 } 196 197 static int grts_probe(struct platform_device *pdev) 198 { 199 struct grts_state *st; 200 struct input_dev *input; 201 struct device *dev = &pdev->dev; 202 int error; 203 204 st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL); 205 if (!st) 206 return -ENOMEM; 207 208 /* get the channels from IIO device */ 209 st->iio_chans = devm_iio_channel_get_all(dev); 210 if (IS_ERR(st->iio_chans)) { 211 error = PTR_ERR(st->iio_chans); 212 if (error != -EPROBE_DEFER) 213 dev_err(dev, "can't get iio channels.\n"); 214 return error; 215 } 216 217 if (!device_property_present(dev, "io-channel-names")) 218 return -ENODEV; 219 220 error = grts_get_properties(st, dev); 221 if (error) { 222 dev_err(dev, "Failed to parse properties\n"); 223 return error; 224 } 225 226 if (st->pressure) { 227 error = device_property_read_u32(dev, 228 "touchscreen-min-pressure", 229 &st->pressure_min); 230 if (error) { 231 dev_dbg(dev, "can't get touchscreen-min-pressure property.\n"); 232 st->pressure_min = GRTS_DEFAULT_PRESSURE_MIN; 233 } 234 } 235 236 input = devm_input_allocate_device(dev); 237 if (!input) { 238 dev_err(dev, "failed to allocate input device.\n"); 239 return -ENOMEM; 240 } 241 242 input->name = DRIVER_NAME; 243 input->id.bustype = BUS_HOST; 244 input->open = grts_open; 245 input->close = grts_close; 246 247 input_set_abs_params(input, ABS_X, 0, GRTS_MAX_POS_MASK - 1, 0, 0); 248 input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0); 249 if (st->pressure) 250 input_set_abs_params(input, ABS_PRESSURE, st->pressure_min, 251 GRTS_DEFAULT_PRESSURE_MAX, 0, 0); 252 253 input_set_capability(input, EV_KEY, BTN_TOUCH); 254 255 /* parse optional device tree properties */ 256 touchscreen_parse_properties(input, false, &st->prop); 257 258 st->input = input; 259 input_set_drvdata(input, st); 260 261 error = input_register_device(input); 262 if (error) { 263 dev_err(dev, "failed to register input device."); 264 return error; 265 } 266 267 st->iio_cb = iio_channel_get_all_cb(dev, grts_cb, st); 268 if (IS_ERR(st->iio_cb)) { 269 dev_err(dev, "failed to allocate callback buffer.\n"); 270 return PTR_ERR(st->iio_cb); 271 } 272 273 error = devm_add_action_or_reset(dev, grts_disable, st->iio_cb); 274 if (error) { 275 dev_err(dev, "failed to add disable action.\n"); 276 return error; 277 } 278 279 return 0; 280 } 281 282 static const struct of_device_id grts_of_match[] = { 283 { 284 .compatible = "resistive-adc-touch", 285 }, { 286 /* sentinel */ 287 }, 288 }; 289 290 MODULE_DEVICE_TABLE(of, grts_of_match); 291 292 static struct platform_driver grts_driver = { 293 .probe = grts_probe, 294 .driver = { 295 .name = DRIVER_NAME, 296 .of_match_table = grts_of_match, 297 }, 298 }; 299 300 module_platform_driver(grts_driver); 301 302 MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>"); 303 MODULE_DESCRIPTION("Generic ADC Resistive Touch Driver"); 304 MODULE_LICENSE("GPL v2"); 305