linux/drivers/input/touchscreen/hp680_ts_input.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2#include <linux/input.h>
   3#include <linux/module.h>
   4#include <linux/init.h>
   5#include <linux/interrupt.h>
   6#include <asm/io.h>
   7#include <asm/delay.h>
   8#include <asm/adc.h>
   9#include <mach/hp6xx.h>
  10
  11#define MODNAME "hp680_ts_input"
  12
  13#define HP680_TS_ABS_X_MIN      40
  14#define HP680_TS_ABS_X_MAX      950
  15#define HP680_TS_ABS_Y_MIN      80
  16#define HP680_TS_ABS_Y_MAX      910
  17
  18#define PHDR    0xa400012e
  19#define SCPDR   0xa4000136
  20
  21static void do_softint(struct work_struct *work);
  22
  23static struct input_dev *hp680_ts_dev;
  24static DECLARE_DELAYED_WORK(work, do_softint);
  25
  26static void do_softint(struct work_struct *work)
  27{
  28        int absx = 0, absy = 0;
  29        u8 scpdr;
  30        int touched = 0;
  31
  32        if (__raw_readb(PHDR) & PHDR_TS_PEN_DOWN) {
  33                scpdr = __raw_readb(SCPDR);
  34                scpdr |= SCPDR_TS_SCAN_ENABLE;
  35                scpdr &= ~SCPDR_TS_SCAN_Y;
  36                __raw_writeb(scpdr, SCPDR);
  37                udelay(30);
  38
  39                absy = adc_single(ADC_CHANNEL_TS_Y);
  40
  41                scpdr = __raw_readb(SCPDR);
  42                scpdr |= SCPDR_TS_SCAN_Y;
  43                scpdr &= ~SCPDR_TS_SCAN_X;
  44                __raw_writeb(scpdr, SCPDR);
  45                udelay(30);
  46
  47                absx = adc_single(ADC_CHANNEL_TS_X);
  48
  49                scpdr = __raw_readb(SCPDR);
  50                scpdr |= SCPDR_TS_SCAN_X;
  51                scpdr &= ~SCPDR_TS_SCAN_ENABLE;
  52                __raw_writeb(scpdr, SCPDR);
  53                udelay(100);
  54                touched = __raw_readb(PHDR) & PHDR_TS_PEN_DOWN;
  55        }
  56
  57        if (touched) {
  58                input_report_key(hp680_ts_dev, BTN_TOUCH, 1);
  59                input_report_abs(hp680_ts_dev, ABS_X, absx);
  60                input_report_abs(hp680_ts_dev, ABS_Y, absy);
  61        } else {
  62                input_report_key(hp680_ts_dev, BTN_TOUCH, 0);
  63        }
  64
  65        input_sync(hp680_ts_dev);
  66        enable_irq(HP680_TS_IRQ);
  67}
  68
  69static irqreturn_t hp680_ts_interrupt(int irq, void *dev)
  70{
  71        disable_irq_nosync(irq);
  72        schedule_delayed_work(&work, HZ / 20);
  73
  74        return IRQ_HANDLED;
  75}
  76
  77static int __init hp680_ts_init(void)
  78{
  79        int err;
  80
  81        hp680_ts_dev = input_allocate_device();
  82        if (!hp680_ts_dev)
  83                return -ENOMEM;
  84
  85        hp680_ts_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
  86        hp680_ts_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
  87
  88        input_set_abs_params(hp680_ts_dev, ABS_X,
  89                HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0);
  90        input_set_abs_params(hp680_ts_dev, ABS_Y,
  91                HP680_TS_ABS_Y_MIN, HP680_TS_ABS_Y_MAX, 0, 0);
  92
  93        hp680_ts_dev->name = "HP Jornada touchscreen";
  94        hp680_ts_dev->phys = "hp680_ts/input0";
  95
  96        if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
  97                        0, MODNAME, NULL) < 0) {
  98                printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
  99                       HP680_TS_IRQ);
 100                err = -EBUSY;
 101                goto fail1;
 102        }
 103
 104        err = input_register_device(hp680_ts_dev);
 105        if (err)
 106                goto fail2;
 107
 108        return 0;
 109
 110 fail2: free_irq(HP680_TS_IRQ, NULL);
 111        cancel_delayed_work_sync(&work);
 112 fail1: input_free_device(hp680_ts_dev);
 113        return err;
 114}
 115
 116static void __exit hp680_ts_exit(void)
 117{
 118        free_irq(HP680_TS_IRQ, NULL);
 119        cancel_delayed_work_sync(&work);
 120        input_unregister_device(hp680_ts_dev);
 121}
 122
 123module_init(hp680_ts_init);
 124module_exit(hp680_ts_exit);
 125
 126MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
 127MODULE_DESCRIPTION("HP Jornada 680 touchscreen driver");
 128MODULE_LICENSE("GPL");
 129