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