Path: blob/master/drivers/input/touchscreen/mk712.c
15111 views
/*1* ICS MK712 touchscreen controller driver2*3* Copyright (c) 1999-2002 Transmeta Corporation4* Copyright (c) 2005 Rick Koch <[email protected]>5* Copyright (c) 2005 Vojtech Pavlik <[email protected]>6*/78/*9* This program is free software; you can redistribute it and/or modify it10* under the terms of the GNU General Public License version 2 as published by11* the Free Software Foundation.12*/1314/*15* This driver supports the ICS MicroClock MK712 TouchScreen controller,16* found in Gateway AOL Connected Touchpad computers.17*18* Documentation for ICS MK712 can be found at:19* http://www.idt.com/products/getDoc.cfm?docID=1871392320*/2122/*23* 1999-12-18: original version, Daniel Quinlan24* 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll25* to use queue_empty, Nathan Laredo26* 1999-12-20: improved random point rejection, Nathan Laredo27* 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed28* queue code, added module options, other fixes, Daniel Quinlan29* 2002-03-15: Clean up for kernel merge <[email protected]>30* Fixed multi open race, fixed memory checks, fixed resource31* allocation, fixed close/powerdown bug, switched to new init32* 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch33* 2005-02-05: Rewritten for the input layer, Vojtech Pavlik34*35*/3637#include <linux/module.h>38#include <linux/kernel.h>39#include <linux/init.h>40#include <linux/errno.h>41#include <linux/delay.h>42#include <linux/ioport.h>43#include <linux/interrupt.h>44#include <linux/input.h>45#include <asm/io.h>4647MODULE_AUTHOR("Daniel Quinlan <[email protected]>, Vojtech Pavlik <[email protected]>");48MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");49MODULE_LICENSE("GPL");5051static unsigned int mk712_io = 0x260; /* Also 0x200, 0x208, 0x300 */52module_param_named(io, mk712_io, uint, 0);53MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");5455static unsigned int mk712_irq = 10; /* Also 12, 14, 15 */56module_param_named(irq, mk712_irq, uint, 0);57MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");5859/* eight 8-bit registers */60#define MK712_STATUS 061#define MK712_X 262#define MK712_Y 463#define MK712_CONTROL 664#define MK712_RATE 76566/* status */67#define MK712_STATUS_TOUCH 0x1068#define MK712_CONVERSION_COMPLETE 0x806970/* control */71#define MK712_ENABLE_INT 0x0172#define MK712_INT_ON_CONVERSION_COMPLETE 0x0273#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS 0x0474#define MK712_ENABLE_PERIODIC_CONVERSIONS 0x1075#define MK712_READ_ONE_POINT 0x2076#define MK712_POWERUP 0x407778static struct input_dev *mk712_dev;79static DEFINE_SPINLOCK(mk712_lock);8081static irqreturn_t mk712_interrupt(int irq, void *dev_id)82{83unsigned char status;84static int debounce = 1;85static unsigned short last_x;86static unsigned short last_y;8788spin_lock(&mk712_lock);8990status = inb(mk712_io + MK712_STATUS);9192if (~status & MK712_CONVERSION_COMPLETE) {93debounce = 1;94goto end;95}9697if (~status & MK712_STATUS_TOUCH) {98debounce = 1;99input_report_key(mk712_dev, BTN_TOUCH, 0);100goto end;101}102103if (debounce) {104debounce = 0;105goto end;106}107108input_report_key(mk712_dev, BTN_TOUCH, 1);109input_report_abs(mk712_dev, ABS_X, last_x);110input_report_abs(mk712_dev, ABS_Y, last_y);111112end:113last_x = inw(mk712_io + MK712_X) & 0x0fff;114last_y = inw(mk712_io + MK712_Y) & 0x0fff;115input_sync(mk712_dev);116spin_unlock(&mk712_lock);117return IRQ_HANDLED;118}119120static int mk712_open(struct input_dev *dev)121{122unsigned long flags;123124spin_lock_irqsave(&mk712_lock, flags);125126outb(0, mk712_io + MK712_CONTROL); /* Reset */127128outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |129MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |130MK712_ENABLE_PERIODIC_CONVERSIONS |131MK712_POWERUP, mk712_io + MK712_CONTROL);132133outb(10, mk712_io + MK712_RATE); /* 187 points per second */134135spin_unlock_irqrestore(&mk712_lock, flags);136137return 0;138}139140static void mk712_close(struct input_dev *dev)141{142unsigned long flags;143144spin_lock_irqsave(&mk712_lock, flags);145146outb(0, mk712_io + MK712_CONTROL);147148spin_unlock_irqrestore(&mk712_lock, flags);149}150151static int __init mk712_init(void)152{153int err;154155if (!request_region(mk712_io, 8, "mk712")) {156printk(KERN_WARNING "mk712: unable to get IO region\n");157return -ENODEV;158}159160outb(0, mk712_io + MK712_CONTROL);161162if ((inw(mk712_io + MK712_X) & 0xf000) || /* Sanity check */163(inw(mk712_io + MK712_Y) & 0xf000) ||164(inw(mk712_io + MK712_STATUS) & 0xf333)) {165printk(KERN_WARNING "mk712: device not present\n");166err = -ENODEV;167goto fail1;168}169170mk712_dev = input_allocate_device();171if (!mk712_dev) {172printk(KERN_ERR "mk712: not enough memory\n");173err = -ENOMEM;174goto fail1;175}176177mk712_dev->name = "ICS MicroClock MK712 TouchScreen";178mk712_dev->phys = "isa0260/input0";179mk712_dev->id.bustype = BUS_ISA;180mk712_dev->id.vendor = 0x0005;181mk712_dev->id.product = 0x0001;182mk712_dev->id.version = 0x0100;183184mk712_dev->open = mk712_open;185mk712_dev->close = mk712_close;186187mk712_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);188mk712_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);189input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0);190input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0);191192if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) {193printk(KERN_WARNING "mk712: unable to get IRQ\n");194err = -EBUSY;195goto fail1;196}197198err = input_register_device(mk712_dev);199if (err)200goto fail2;201202return 0;203204fail2: free_irq(mk712_irq, mk712_dev);205fail1: input_free_device(mk712_dev);206release_region(mk712_io, 8);207return err;208}209210static void __exit mk712_exit(void)211{212input_unregister_device(mk712_dev);213free_irq(mk712_irq, mk712_dev);214release_region(mk712_io, 8);215}216217module_init(mk712_init);218module_exit(mk712_exit);219220221