linux/drivers/input/touchscreen/ipaq-micro-ts.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *
   4 * h3600 atmel micro companion support, touchscreen subdevice
   5 * Author : Alessandro Gardich <gremlin@gremlin.it>
   6 * Author : Dmitry Artamonow <mad_soft@inbox.ru>
   7 * Author : Linus Walleij <linus.walleij@linaro.org>
   8 */
   9
  10#include <asm/byteorder.h>
  11#include <linux/module.h>
  12#include <linux/init.h>
  13#include <linux/interrupt.h>
  14#include <linux/pm.h>
  15#include <linux/delay.h>
  16#include <linux/device.h>
  17#include <linux/input.h>
  18#include <linux/platform_device.h>
  19#include <linux/slab.h>
  20#include <linux/mfd/ipaq-micro.h>
  21
  22struct touchscreen_data {
  23        struct input_dev *input;
  24        struct ipaq_micro *micro;
  25};
  26
  27static void micro_ts_receive(void *data, int len, unsigned char *msg)
  28{
  29        struct touchscreen_data *ts = data;
  30
  31        if (len == 4) {
  32                input_report_abs(ts->input, ABS_X,
  33                                 be16_to_cpup((__be16 *) &msg[2]));
  34                input_report_abs(ts->input, ABS_Y,
  35                                 be16_to_cpup((__be16 *) &msg[0]));
  36                input_report_key(ts->input, BTN_TOUCH, 1);
  37                input_sync(ts->input);
  38        } else if (len == 0) {
  39                input_report_abs(ts->input, ABS_X, 0);
  40                input_report_abs(ts->input, ABS_Y, 0);
  41                input_report_key(ts->input, BTN_TOUCH, 0);
  42                input_sync(ts->input);
  43        }
  44}
  45
  46static void micro_ts_toggle_receive(struct touchscreen_data *ts, bool enable)
  47{
  48        struct ipaq_micro *micro = ts->micro;
  49
  50        spin_lock_irq(&micro->lock);
  51
  52        if (enable) {
  53                micro->ts = micro_ts_receive;
  54                micro->ts_data = ts;
  55        } else {
  56                micro->ts = NULL;
  57                micro->ts_data = NULL;
  58        }
  59
  60        spin_unlock_irq(&ts->micro->lock);
  61}
  62
  63static int micro_ts_open(struct input_dev *input)
  64{
  65        struct touchscreen_data *ts = input_get_drvdata(input);
  66
  67        micro_ts_toggle_receive(ts, true);
  68
  69        return 0;
  70}
  71
  72static void micro_ts_close(struct input_dev *input)
  73{
  74        struct touchscreen_data *ts = input_get_drvdata(input);
  75
  76        micro_ts_toggle_receive(ts, false);
  77}
  78
  79static int micro_ts_probe(struct platform_device *pdev)
  80{
  81        struct ipaq_micro *micro = dev_get_drvdata(pdev->dev.parent);
  82        struct touchscreen_data *ts;
  83        int error;
  84
  85        ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
  86        if (!ts)
  87                return -ENOMEM;
  88
  89        ts->micro = micro;
  90
  91        ts->input = devm_input_allocate_device(&pdev->dev);
  92        if (!ts->input) {
  93                dev_err(&pdev->dev, "failed to allocate input device\n");
  94                return -ENOMEM;
  95        }
  96
  97        ts->input->name = "ipaq micro ts";
  98        ts->input->open = micro_ts_open;
  99        ts->input->close = micro_ts_close;
 100
 101        input_set_drvdata(ts->input, ts);
 102
 103        input_set_capability(ts->input, EV_KEY, BTN_TOUCH);
 104        input_set_capability(ts->input, EV_ABS, ABS_X);
 105        input_set_capability(ts->input, EV_ABS, ABS_Y);
 106        input_set_abs_params(ts->input, ABS_X, 0, 1023, 0, 0);
 107        input_set_abs_params(ts->input, ABS_Y, 0, 1023, 0, 0);
 108
 109        error = input_register_device(ts->input);
 110        if (error) {
 111                dev_err(&pdev->dev, "error registering touch input\n");
 112                return error;
 113        }
 114
 115        platform_set_drvdata(pdev, ts);
 116
 117        dev_info(&pdev->dev, "iPAQ micro touchscreen\n");
 118
 119        return 0;
 120}
 121
 122static int __maybe_unused micro_ts_suspend(struct device *dev)
 123{
 124        struct touchscreen_data *ts = dev_get_drvdata(dev);
 125
 126        micro_ts_toggle_receive(ts, false);
 127
 128        return 0;
 129}
 130
 131static int __maybe_unused micro_ts_resume(struct device *dev)
 132{
 133        struct touchscreen_data *ts = dev_get_drvdata(dev);
 134        struct input_dev *input = ts->input;
 135
 136        mutex_lock(&input->mutex);
 137
 138        if (input_device_enabled(input))
 139                micro_ts_toggle_receive(ts, true);
 140
 141        mutex_unlock(&input->mutex);
 142
 143        return 0;
 144}
 145
 146static const struct dev_pm_ops micro_ts_dev_pm_ops = {
 147        SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume)
 148};
 149
 150static struct platform_driver micro_ts_device_driver = {
 151        .driver = {
 152                .name   = "ipaq-micro-ts",
 153                .pm     = &micro_ts_dev_pm_ops,
 154        },
 155        .probe  = micro_ts_probe,
 156};
 157module_platform_driver(micro_ts_device_driver);
 158
 159MODULE_LICENSE("GPL");
 160MODULE_DESCRIPTION("driver for iPAQ Atmel micro touchscreen");
 161MODULE_ALIAS("platform:ipaq-micro-ts");
 162