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