0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/delay.h>
0011 #include <linux/err.h>
0012 #include <linux/gpio/consumer.h>
0013 #include <linux/iio/consumer.h>
0014 #include <linux/iio/types.h>
0015 #include <linux/input.h>
0016 #include <linux/interrupt.h>
0017 #include <linux/kernel.h>
0018 #include <linux/module.h>
0019 #include <linux/of.h>
0020 #include <linux/pinctrl/consumer.h>
0021 #include <linux/platform_device.h>
0022 #include <linux/slab.h>
0023 #include <linux/types.h>
0024
0025 #define DRIVER_NAME "colibri-vf50-ts"
0026
0027 #define VF_ADC_MAX ((1 << 12) - 1)
0028
0029 #define COLI_TOUCH_MIN_DELAY_US 1000
0030 #define COLI_TOUCH_MAX_DELAY_US 2000
0031 #define COLI_PULLUP_MIN_DELAY_US 10000
0032 #define COLI_PULLUP_MAX_DELAY_US 11000
0033 #define COLI_TOUCH_NO_OF_AVGS 5
0034 #define COLI_TOUCH_REQ_ADC_CHAN 4
0035
0036 struct vf50_touch_device {
0037 struct platform_device *pdev;
0038 struct input_dev *ts_input;
0039 struct iio_channel *channels;
0040 struct gpio_desc *gpio_xp;
0041 struct gpio_desc *gpio_xm;
0042 struct gpio_desc *gpio_yp;
0043 struct gpio_desc *gpio_ym;
0044 int pen_irq;
0045 int min_pressure;
0046 bool stop_touchscreen;
0047 };
0048
0049
0050
0051
0052 static int adc_ts_measure(struct iio_channel *channel,
0053 struct gpio_desc *plate_p, struct gpio_desc *plate_m)
0054 {
0055 int i, value = 0, val = 0;
0056 int error;
0057
0058 gpiod_set_value(plate_p, 1);
0059 gpiod_set_value(plate_m, 1);
0060
0061 usleep_range(COLI_TOUCH_MIN_DELAY_US, COLI_TOUCH_MAX_DELAY_US);
0062
0063 for (i = 0; i < COLI_TOUCH_NO_OF_AVGS; i++) {
0064 error = iio_read_channel_raw(channel, &val);
0065 if (error < 0) {
0066 value = error;
0067 goto error_iio_read;
0068 }
0069
0070 value += val;
0071 }
0072
0073 value /= COLI_TOUCH_NO_OF_AVGS;
0074
0075 error_iio_read:
0076 gpiod_set_value(plate_p, 0);
0077 gpiod_set_value(plate_m, 0);
0078
0079 return value;
0080 }
0081
0082
0083
0084
0085 static void vf50_ts_enable_touch_detection(struct vf50_touch_device *vf50_ts)
0086 {
0087
0088 gpiod_set_value(vf50_ts->gpio_ym, 1);
0089
0090
0091
0092
0093
0094 pinctrl_pm_select_idle_state(&vf50_ts->pdev->dev);
0095
0096
0097 usleep_range(COLI_PULLUP_MIN_DELAY_US, COLI_PULLUP_MAX_DELAY_US);
0098 }
0099
0100
0101
0102
0103 static irqreturn_t vf50_ts_irq_bh(int irq, void *private)
0104 {
0105 struct vf50_touch_device *vf50_ts = private;
0106 struct device *dev = &vf50_ts->pdev->dev;
0107 int val_x, val_y, val_z1, val_z2, val_p = 0;
0108 bool discard_val_on_start = true;
0109
0110
0111 gpiod_set_value(vf50_ts->gpio_ym, 0);
0112
0113
0114 pinctrl_pm_select_default_state(dev);
0115
0116 while (!vf50_ts->stop_touchscreen) {
0117
0118 val_x = adc_ts_measure(&vf50_ts->channels[0],
0119 vf50_ts->gpio_xp, vf50_ts->gpio_xm);
0120 if (val_x < 0)
0121 break;
0122
0123
0124 val_y = adc_ts_measure(&vf50_ts->channels[1],
0125 vf50_ts->gpio_yp, vf50_ts->gpio_ym);
0126 if (val_y < 0)
0127 break;
0128
0129
0130
0131
0132
0133 val_z1 = adc_ts_measure(&vf50_ts->channels[2],
0134 vf50_ts->gpio_yp, vf50_ts->gpio_xm);
0135 if (val_z1 < 0)
0136 break;
0137 val_z2 = adc_ts_measure(&vf50_ts->channels[3],
0138 vf50_ts->gpio_yp, vf50_ts->gpio_xm);
0139 if (val_z2 < 0)
0140 break;
0141
0142
0143 if (val_z1 > 64 && val_x > 64) {
0144
0145
0146
0147
0148 int r_x = (1000 * val_x) / VF_ADC_MAX;
0149
0150 val_p = (r_x * val_z2) / val_z1 - r_x;
0151
0152 } else {
0153 val_p = 2000;
0154 }
0155
0156 val_p = 2000 - val_p;
0157 dev_dbg(dev,
0158 "Measured values: x: %d, y: %d, z1: %d, z2: %d, p: %d\n",
0159 val_x, val_y, val_z1, val_z2, val_p);
0160
0161
0162
0163
0164
0165 if (val_p < vf50_ts->min_pressure || val_p > 2000)
0166 break;
0167
0168
0169
0170
0171
0172
0173
0174 if (discard_val_on_start) {
0175 discard_val_on_start = false;
0176 } else {
0177
0178
0179
0180
0181 input_report_abs(vf50_ts->ts_input,
0182 ABS_X, VF_ADC_MAX - val_x);
0183 input_report_abs(vf50_ts->ts_input,
0184 ABS_Y, VF_ADC_MAX - val_y);
0185 input_report_abs(vf50_ts->ts_input,
0186 ABS_PRESSURE, val_p);
0187 input_report_key(vf50_ts->ts_input, BTN_TOUCH, 1);
0188 input_sync(vf50_ts->ts_input);
0189 }
0190
0191 usleep_range(COLI_PULLUP_MIN_DELAY_US,
0192 COLI_PULLUP_MAX_DELAY_US);
0193 }
0194
0195
0196 input_report_abs(vf50_ts->ts_input, ABS_PRESSURE, 0);
0197 input_report_key(vf50_ts->ts_input, BTN_TOUCH, 0);
0198 input_sync(vf50_ts->ts_input);
0199
0200 vf50_ts_enable_touch_detection(vf50_ts);
0201
0202 return IRQ_HANDLED;
0203 }
0204
0205 static int vf50_ts_open(struct input_dev *dev_input)
0206 {
0207 struct vf50_touch_device *touchdev = input_get_drvdata(dev_input);
0208 struct device *dev = &touchdev->pdev->dev;
0209
0210 dev_dbg(dev, "Input device %s opened, starting touch detection\n",
0211 dev_input->name);
0212
0213 touchdev->stop_touchscreen = false;
0214
0215
0216 vf50_ts_enable_touch_detection(touchdev);
0217
0218 return 0;
0219 }
0220
0221 static void vf50_ts_close(struct input_dev *dev_input)
0222 {
0223 struct vf50_touch_device *touchdev = input_get_drvdata(dev_input);
0224 struct device *dev = &touchdev->pdev->dev;
0225
0226 touchdev->stop_touchscreen = true;
0227
0228
0229 mb();
0230 synchronize_irq(touchdev->pen_irq);
0231
0232 gpiod_set_value(touchdev->gpio_ym, 0);
0233 pinctrl_pm_select_default_state(dev);
0234
0235 dev_dbg(dev, "Input device %s closed, disable touch detection\n",
0236 dev_input->name);
0237 }
0238
0239 static int vf50_ts_get_gpiod(struct device *dev, struct gpio_desc **gpio_d,
0240 const char *con_id, enum gpiod_flags flags)
0241 {
0242 int error;
0243
0244 *gpio_d = devm_gpiod_get(dev, con_id, flags);
0245 if (IS_ERR(*gpio_d)) {
0246 error = PTR_ERR(*gpio_d);
0247 dev_err(dev, "Could not get gpio_%s %d\n", con_id, error);
0248 return error;
0249 }
0250
0251 return 0;
0252 }
0253
0254 static void vf50_ts_channel_release(void *data)
0255 {
0256 struct iio_channel *channels = data;
0257
0258 iio_channel_release_all(channels);
0259 }
0260
0261 static int vf50_ts_probe(struct platform_device *pdev)
0262 {
0263 struct input_dev *input;
0264 struct iio_channel *channels;
0265 struct device *dev = &pdev->dev;
0266 struct vf50_touch_device *touchdev;
0267 int num_adc_channels;
0268 int error;
0269
0270 channels = iio_channel_get_all(dev);
0271 if (IS_ERR(channels))
0272 return PTR_ERR(channels);
0273
0274 error = devm_add_action(dev, vf50_ts_channel_release, channels);
0275 if (error) {
0276 iio_channel_release_all(channels);
0277 dev_err(dev, "Failed to register iio channel release action");
0278 return error;
0279 }
0280
0281 num_adc_channels = 0;
0282 while (channels[num_adc_channels].indio_dev)
0283 num_adc_channels++;
0284
0285 if (num_adc_channels != COLI_TOUCH_REQ_ADC_CHAN) {
0286 dev_err(dev, "Inadequate ADC channels specified\n");
0287 return -EINVAL;
0288 }
0289
0290 touchdev = devm_kzalloc(dev, sizeof(*touchdev), GFP_KERNEL);
0291 if (!touchdev)
0292 return -ENOMEM;
0293
0294 touchdev->pdev = pdev;
0295 touchdev->channels = channels;
0296
0297 error = of_property_read_u32(dev->of_node, "vf50-ts-min-pressure",
0298 &touchdev->min_pressure);
0299 if (error)
0300 return error;
0301
0302 input = devm_input_allocate_device(dev);
0303 if (!input) {
0304 dev_err(dev, "Failed to allocate TS input device\n");
0305 return -ENOMEM;
0306 }
0307
0308 input->name = DRIVER_NAME;
0309 input->id.bustype = BUS_HOST;
0310 input->dev.parent = dev;
0311 input->open = vf50_ts_open;
0312 input->close = vf50_ts_close;
0313
0314 input_set_capability(input, EV_KEY, BTN_TOUCH);
0315 input_set_abs_params(input, ABS_X, 0, VF_ADC_MAX, 0, 0);
0316 input_set_abs_params(input, ABS_Y, 0, VF_ADC_MAX, 0, 0);
0317 input_set_abs_params(input, ABS_PRESSURE, 0, VF_ADC_MAX, 0, 0);
0318
0319 touchdev->ts_input = input;
0320 input_set_drvdata(input, touchdev);
0321
0322 error = input_register_device(input);
0323 if (error) {
0324 dev_err(dev, "Failed to register input device\n");
0325 return error;
0326 }
0327
0328 error = vf50_ts_get_gpiod(dev, &touchdev->gpio_xp, "xp", GPIOD_OUT_LOW);
0329 if (error)
0330 return error;
0331
0332 error = vf50_ts_get_gpiod(dev, &touchdev->gpio_xm,
0333 "xm", GPIOD_OUT_LOW);
0334 if (error)
0335 return error;
0336
0337 error = vf50_ts_get_gpiod(dev, &touchdev->gpio_yp, "yp", GPIOD_OUT_LOW);
0338 if (error)
0339 return error;
0340
0341 error = vf50_ts_get_gpiod(dev, &touchdev->gpio_ym, "ym", GPIOD_OUT_LOW);
0342 if (error)
0343 return error;
0344
0345 touchdev->pen_irq = platform_get_irq(pdev, 0);
0346 if (touchdev->pen_irq < 0)
0347 return touchdev->pen_irq;
0348
0349 error = devm_request_threaded_irq(dev, touchdev->pen_irq,
0350 NULL, vf50_ts_irq_bh, IRQF_ONESHOT,
0351 "vf50 touch", touchdev);
0352 if (error) {
0353 dev_err(dev, "Failed to request IRQ %d: %d\n",
0354 touchdev->pen_irq, error);
0355 return error;
0356 }
0357
0358 return 0;
0359 }
0360
0361 static const struct of_device_id vf50_touch_of_match[] = {
0362 { .compatible = "toradex,vf50-touchscreen", },
0363 { }
0364 };
0365 MODULE_DEVICE_TABLE(of, vf50_touch_of_match);
0366
0367 static struct platform_driver vf50_touch_driver = {
0368 .driver = {
0369 .name = "toradex,vf50_touchctrl",
0370 .of_match_table = vf50_touch_of_match,
0371 },
0372 .probe = vf50_ts_probe,
0373 };
0374 module_platform_driver(vf50_touch_driver);
0375
0376 MODULE_AUTHOR("Sanchayan Maity");
0377 MODULE_DESCRIPTION("Colibri VF50 Touchscreen driver");
0378 MODULE_LICENSE("GPL");