root/drivers/input/touchscreen/mk712.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mk712_interrupt
  2. mk712_open
  3. mk712_close
  4. mk712_init
  5. mk712_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * ICS MK712 touchscreen controller driver
   4  *
   5  * Copyright (c) 1999-2002 Transmeta Corporation
   6  * Copyright (c) 2005 Rick Koch <n1gp@hotmail.com>
   7  * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
   8  */
   9 
  10 
  11 /*
  12  * This driver supports the ICS MicroClock MK712 TouchScreen controller,
  13  * found in Gateway AOL Connected Touchpad computers.
  14  *
  15  * Documentation for ICS MK712 can be found at:
  16  *      https://www.idt.com/general-parts/mk712-touch-screen-controller
  17  */
  18 
  19 /*
  20  * 1999-12-18: original version, Daniel Quinlan
  21  * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
  22  *             to use queue_empty, Nathan Laredo
  23  * 1999-12-20: improved random point rejection, Nathan Laredo
  24  * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
  25  *             queue code, added module options, other fixes, Daniel Quinlan
  26  * 2002-03-15: Clean up for kernel merge <alan@redhat.com>
  27  *             Fixed multi open race, fixed memory checks, fixed resource
  28  *             allocation, fixed close/powerdown bug, switched to new init
  29  * 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch
  30  * 2005-02-05: Rewritten for the input layer, Vojtech Pavlik
  31  *
  32  */
  33 
  34 #include <linux/module.h>
  35 #include <linux/kernel.h>
  36 #include <linux/init.h>
  37 #include <linux/errno.h>
  38 #include <linux/delay.h>
  39 #include <linux/ioport.h>
  40 #include <linux/interrupt.h>
  41 #include <linux/input.h>
  42 #include <asm/io.h>
  43 
  44 MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>");
  45 MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
  46 MODULE_LICENSE("GPL");
  47 
  48 static unsigned int mk712_io = 0x260;   /* Also 0x200, 0x208, 0x300 */
  49 module_param_hw_named(io, mk712_io, uint, ioport, 0);
  50 MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
  51 
  52 static unsigned int mk712_irq = 10;     /* Also 12, 14, 15 */
  53 module_param_hw_named(irq, mk712_irq, uint, irq, 0);
  54 MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
  55 
  56 /* eight 8-bit registers */
  57 #define MK712_STATUS            0
  58 #define MK712_X                 2
  59 #define MK712_Y                 4
  60 #define MK712_CONTROL           6
  61 #define MK712_RATE              7
  62 
  63 /* status */
  64 #define MK712_STATUS_TOUCH                      0x10
  65 #define MK712_CONVERSION_COMPLETE               0x80
  66 
  67 /* control */
  68 #define MK712_ENABLE_INT                        0x01
  69 #define MK712_INT_ON_CONVERSION_COMPLETE        0x02
  70 #define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS     0x04
  71 #define MK712_ENABLE_PERIODIC_CONVERSIONS       0x10
  72 #define MK712_READ_ONE_POINT                    0x20
  73 #define MK712_POWERUP                           0x40
  74 
  75 static struct input_dev *mk712_dev;
  76 static DEFINE_SPINLOCK(mk712_lock);
  77 
  78 static irqreturn_t mk712_interrupt(int irq, void *dev_id)
  79 {
  80         unsigned char status;
  81         static int debounce = 1;
  82         static unsigned short last_x;
  83         static unsigned short last_y;
  84 
  85         spin_lock(&mk712_lock);
  86 
  87         status = inb(mk712_io + MK712_STATUS);
  88 
  89         if (~status & MK712_CONVERSION_COMPLETE) {
  90                 debounce = 1;
  91                 goto end;
  92         }
  93 
  94         if (~status & MK712_STATUS_TOUCH) {
  95                 debounce = 1;
  96                 input_report_key(mk712_dev, BTN_TOUCH, 0);
  97                 goto end;
  98         }
  99 
 100         if (debounce) {
 101                 debounce = 0;
 102                 goto end;
 103         }
 104 
 105         input_report_key(mk712_dev, BTN_TOUCH, 1);
 106         input_report_abs(mk712_dev, ABS_X, last_x);
 107         input_report_abs(mk712_dev, ABS_Y, last_y);
 108 
 109  end:
 110         last_x = inw(mk712_io + MK712_X) & 0x0fff;
 111         last_y = inw(mk712_io + MK712_Y) & 0x0fff;
 112         input_sync(mk712_dev);
 113         spin_unlock(&mk712_lock);
 114         return IRQ_HANDLED;
 115 }
 116 
 117 static int mk712_open(struct input_dev *dev)
 118 {
 119         unsigned long flags;
 120 
 121         spin_lock_irqsave(&mk712_lock, flags);
 122 
 123         outb(0, mk712_io + MK712_CONTROL); /* Reset */
 124 
 125         outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
 126                 MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
 127                 MK712_ENABLE_PERIODIC_CONVERSIONS |
 128                 MK712_POWERUP, mk712_io + MK712_CONTROL);
 129 
 130         outb(10, mk712_io + MK712_RATE); /* 187 points per second */
 131 
 132         spin_unlock_irqrestore(&mk712_lock, flags);
 133 
 134         return 0;
 135 }
 136 
 137 static void mk712_close(struct input_dev *dev)
 138 {
 139         unsigned long flags;
 140 
 141         spin_lock_irqsave(&mk712_lock, flags);
 142 
 143         outb(0, mk712_io + MK712_CONTROL);
 144 
 145         spin_unlock_irqrestore(&mk712_lock, flags);
 146 }
 147 
 148 static int __init mk712_init(void)
 149 {
 150         int err;
 151 
 152         if (!request_region(mk712_io, 8, "mk712")) {
 153                 printk(KERN_WARNING "mk712: unable to get IO region\n");
 154                 return -ENODEV;
 155         }
 156 
 157         outb(0, mk712_io + MK712_CONTROL);
 158 
 159         if ((inw(mk712_io + MK712_X) & 0xf000) ||       /* Sanity check */
 160             (inw(mk712_io + MK712_Y) & 0xf000) ||
 161             (inw(mk712_io + MK712_STATUS) & 0xf333)) {
 162                 printk(KERN_WARNING "mk712: device not present\n");
 163                 err = -ENODEV;
 164                 goto fail1;
 165         }
 166 
 167         mk712_dev = input_allocate_device();
 168         if (!mk712_dev) {
 169                 printk(KERN_ERR "mk712: not enough memory\n");
 170                 err = -ENOMEM;
 171                 goto fail1;
 172         }
 173 
 174         mk712_dev->name = "ICS MicroClock MK712 TouchScreen";
 175         mk712_dev->phys = "isa0260/input0";
 176         mk712_dev->id.bustype = BUS_ISA;
 177         mk712_dev->id.vendor  = 0x0005;
 178         mk712_dev->id.product = 0x0001;
 179         mk712_dev->id.version = 0x0100;
 180 
 181         mk712_dev->open    = mk712_open;
 182         mk712_dev->close   = mk712_close;
 183 
 184         mk712_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 185         mk712_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 186         input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0);
 187         input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0);
 188 
 189         if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) {
 190                 printk(KERN_WARNING "mk712: unable to get IRQ\n");
 191                 err = -EBUSY;
 192                 goto fail1;
 193         }
 194 
 195         err = input_register_device(mk712_dev);
 196         if (err)
 197                 goto fail2;
 198 
 199         return 0;
 200 
 201  fail2: free_irq(mk712_irq, mk712_dev);
 202  fail1: input_free_device(mk712_dev);
 203         release_region(mk712_io, 8);
 204         return err;
 205 }
 206 
 207 static void __exit mk712_exit(void)
 208 {
 209         input_unregister_device(mk712_dev);
 210         free_irq(mk712_irq, mk712_dev);
 211         release_region(mk712_io, 8);
 212 }
 213 
 214 module_init(mk712_init);
 215 module_exit(mk712_exit);

/* [<][>][^][v][top][bottom][index][help] */