Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ICS MK712 touchscreen controller driver
0004  *
0005  * Copyright (c) 1999-2002 Transmeta Corporation
0006  * Copyright (c) 2005 Rick Koch <n1gp@hotmail.com>
0007  * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
0008  */
0009 
0010 
0011 /*
0012  * This driver supports the ICS MicroClock MK712 TouchScreen controller,
0013  * found in Gateway AOL Connected Touchpad computers.
0014  *
0015  * Documentation for ICS MK712 can be found at:
0016  *  https://www.idt.com/general-parts/mk712-touch-screen-controller
0017  */
0018 
0019 /*
0020  * 1999-12-18: original version, Daniel Quinlan
0021  * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
0022  *             to use queue_empty, Nathan Laredo
0023  * 1999-12-20: improved random point rejection, Nathan Laredo
0024  * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
0025  *             queue code, added module options, other fixes, Daniel Quinlan
0026  * 2002-03-15: Clean up for kernel merge <alan@redhat.com>
0027  *             Fixed multi open race, fixed memory checks, fixed resource
0028  *             allocation, fixed close/powerdown bug, switched to new init
0029  * 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch
0030  * 2005-02-05: Rewritten for the input layer, Vojtech Pavlik
0031  *
0032  */
0033 
0034 #include <linux/module.h>
0035 #include <linux/kernel.h>
0036 #include <linux/init.h>
0037 #include <linux/errno.h>
0038 #include <linux/delay.h>
0039 #include <linux/ioport.h>
0040 #include <linux/interrupt.h>
0041 #include <linux/input.h>
0042 #include <asm/io.h>
0043 
0044 MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>");
0045 MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
0046 MODULE_LICENSE("GPL");
0047 
0048 static unsigned int mk712_io = 0x260;   /* Also 0x200, 0x208, 0x300 */
0049 module_param_hw_named(io, mk712_io, uint, ioport, 0);
0050 MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
0051 
0052 static unsigned int mk712_irq = 10; /* Also 12, 14, 15 */
0053 module_param_hw_named(irq, mk712_irq, uint, irq, 0);
0054 MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
0055 
0056 /* eight 8-bit registers */
0057 #define MK712_STATUS        0
0058 #define MK712_X         2
0059 #define MK712_Y         4
0060 #define MK712_CONTROL       6
0061 #define MK712_RATE      7
0062 
0063 /* status */
0064 #define MK712_STATUS_TOUCH          0x10
0065 #define MK712_CONVERSION_COMPLETE       0x80
0066 
0067 /* control */
0068 #define MK712_ENABLE_INT            0x01
0069 #define MK712_INT_ON_CONVERSION_COMPLETE    0x02
0070 #define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS 0x04
0071 #define MK712_ENABLE_PERIODIC_CONVERSIONS   0x10
0072 #define MK712_READ_ONE_POINT            0x20
0073 #define MK712_POWERUP               0x40
0074 
0075 static struct input_dev *mk712_dev;
0076 static DEFINE_SPINLOCK(mk712_lock);
0077 
0078 static irqreturn_t mk712_interrupt(int irq, void *dev_id)
0079 {
0080     unsigned char status;
0081     static int debounce = 1;
0082     static unsigned short last_x;
0083     static unsigned short last_y;
0084 
0085     spin_lock(&mk712_lock);
0086 
0087     status = inb(mk712_io + MK712_STATUS);
0088 
0089     if (~status & MK712_CONVERSION_COMPLETE) {
0090         debounce = 1;
0091         goto end;
0092     }
0093 
0094     if (~status & MK712_STATUS_TOUCH) {
0095         debounce = 1;
0096         input_report_key(mk712_dev, BTN_TOUCH, 0);
0097         goto end;
0098     }
0099 
0100     if (debounce) {
0101         debounce = 0;
0102         goto end;
0103     }
0104 
0105     input_report_key(mk712_dev, BTN_TOUCH, 1);
0106     input_report_abs(mk712_dev, ABS_X, last_x);
0107     input_report_abs(mk712_dev, ABS_Y, last_y);
0108 
0109  end:
0110     last_x = inw(mk712_io + MK712_X) & 0x0fff;
0111     last_y = inw(mk712_io + MK712_Y) & 0x0fff;
0112     input_sync(mk712_dev);
0113     spin_unlock(&mk712_lock);
0114     return IRQ_HANDLED;
0115 }
0116 
0117 static int mk712_open(struct input_dev *dev)
0118 {
0119     unsigned long flags;
0120 
0121     spin_lock_irqsave(&mk712_lock, flags);
0122 
0123     outb(0, mk712_io + MK712_CONTROL); /* Reset */
0124 
0125     outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
0126         MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
0127         MK712_ENABLE_PERIODIC_CONVERSIONS |
0128         MK712_POWERUP, mk712_io + MK712_CONTROL);
0129 
0130     outb(10, mk712_io + MK712_RATE); /* 187 points per second */
0131 
0132     spin_unlock_irqrestore(&mk712_lock, flags);
0133 
0134     return 0;
0135 }
0136 
0137 static void mk712_close(struct input_dev *dev)
0138 {
0139     unsigned long flags;
0140 
0141     spin_lock_irqsave(&mk712_lock, flags);
0142 
0143     outb(0, mk712_io + MK712_CONTROL);
0144 
0145     spin_unlock_irqrestore(&mk712_lock, flags);
0146 }
0147 
0148 static int __init mk712_init(void)
0149 {
0150     int err;
0151 
0152     if (!request_region(mk712_io, 8, "mk712")) {
0153         printk(KERN_WARNING "mk712: unable to get IO region\n");
0154         return -ENODEV;
0155     }
0156 
0157     outb(0, mk712_io + MK712_CONTROL);
0158 
0159     if ((inw(mk712_io + MK712_X) & 0xf000) ||   /* Sanity check */
0160         (inw(mk712_io + MK712_Y) & 0xf000) ||
0161         (inw(mk712_io + MK712_STATUS) & 0xf333)) {
0162         printk(KERN_WARNING "mk712: device not present\n");
0163         err = -ENODEV;
0164         goto fail1;
0165     }
0166 
0167     mk712_dev = input_allocate_device();
0168     if (!mk712_dev) {
0169         printk(KERN_ERR "mk712: not enough memory\n");
0170         err = -ENOMEM;
0171         goto fail1;
0172     }
0173 
0174     mk712_dev->name = "ICS MicroClock MK712 TouchScreen";
0175     mk712_dev->phys = "isa0260/input0";
0176     mk712_dev->id.bustype = BUS_ISA;
0177     mk712_dev->id.vendor  = 0x0005;
0178     mk712_dev->id.product = 0x0001;
0179     mk712_dev->id.version = 0x0100;
0180 
0181     mk712_dev->open    = mk712_open;
0182     mk712_dev->close   = mk712_close;
0183 
0184     mk712_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
0185     mk712_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
0186     input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0);
0187     input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0);
0188 
0189     if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) {
0190         printk(KERN_WARNING "mk712: unable to get IRQ\n");
0191         err = -EBUSY;
0192         goto fail1;
0193     }
0194 
0195     err = input_register_device(mk712_dev);
0196     if (err)
0197         goto fail2;
0198 
0199     return 0;
0200 
0201  fail2: free_irq(mk712_irq, mk712_dev);
0202  fail1: input_free_device(mk712_dev);
0203     release_region(mk712_io, 8);
0204     return err;
0205 }
0206 
0207 static void __exit mk712_exit(void)
0208 {
0209     input_unregister_device(mk712_dev);
0210     free_irq(mk712_irq, mk712_dev);
0211     release_region(mk712_io, 8);
0212 }
0213 
0214 module_init(mk712_init);
0215 module_exit(mk712_exit);