xref: /linux/drivers/input/serio/rpckbd.c (revision 997302259f386bca8fe1db67c50296ca426c438f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  Copyright (c) 2000-2001 Vojtech Pavlik
31da177e4SLinus Torvalds  *  Copyright (c) 2002 Russell King
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds /*
71da177e4SLinus Torvalds  * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds /*
111da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
121da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
131da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or
141da177e4SLinus Torvalds  * (at your option) any later version.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful,
171da177e4SLinus Torvalds  * but WITHOUT ANY WARRANTY; without even the implied warranty of
181da177e4SLinus Torvalds  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
191da177e4SLinus Torvalds  * GNU General Public License for more details.
201da177e4SLinus Torvalds  *
211da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
221da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
231da177e4SLinus Torvalds  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  * Should you need to contact me, the author, you can do so either by
261da177e4SLinus Torvalds  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
271da177e4SLinus Torvalds  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
281da177e4SLinus Torvalds  */
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/module.h>
311da177e4SLinus Torvalds #include <linux/interrupt.h>
321da177e4SLinus Torvalds #include <linux/init.h>
331da177e4SLinus Torvalds #include <linux/serio.h>
341da177e4SLinus Torvalds #include <linux/err.h>
35d052d1beSRussell King #include <linux/platform_device.h>
36*99730225SRussell King #include <linux/io.h>
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds #include <asm/irq.h>
39a09e64fbSRussell King #include <mach/hardware.h>
401da177e4SLinus Torvalds #include <asm/hardware/iomd.h>
411da177e4SLinus Torvalds #include <asm/system.h>
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik, Russell King");
441da177e4SLinus Torvalds MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
451da177e4SLinus Torvalds MODULE_LICENSE("GPL");
46d7b5247bSKay Sievers MODULE_ALIAS("platform:kart");
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds static int rpckbd_write(struct serio *port, unsigned char val)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds 	while (!(iomd_readb(IOMD_KCTRL) & (1 << 7)))
511da177e4SLinus Torvalds 		cpu_relax();
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 	iomd_writeb(val, IOMD_KARTTX);
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds 	return 0;
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
587d12e780SDavid Howells static irqreturn_t rpckbd_rx(int irq, void *dev_id)
591da177e4SLinus Torvalds {
601da177e4SLinus Torvalds 	struct serio *port = dev_id;
611da177e4SLinus Torvalds 	unsigned int byte;
621da177e4SLinus Torvalds 	int handled = IRQ_NONE;
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds 	while (iomd_readb(IOMD_KCTRL) & (1 << 5)) {
651da177e4SLinus Torvalds 		byte = iomd_readb(IOMD_KARTRX);
661da177e4SLinus Torvalds 
677d12e780SDavid Howells 		serio_interrupt(port, byte, 0);
681da177e4SLinus Torvalds 		handled = IRQ_HANDLED;
691da177e4SLinus Torvalds 	}
701da177e4SLinus Torvalds 	return handled;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
737d12e780SDavid Howells static irqreturn_t rpckbd_tx(int irq, void *dev_id)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds 	return IRQ_HANDLED;
761da177e4SLinus Torvalds }
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds static int rpckbd_open(struct serio *port)
791da177e4SLinus Torvalds {
801da177e4SLinus Torvalds 	/* Reset the keyboard state machine. */
811da177e4SLinus Torvalds 	iomd_writeb(0, IOMD_KCTRL);
821da177e4SLinus Torvalds 	iomd_writeb(8, IOMD_KCTRL);
831da177e4SLinus Torvalds 	iomd_readb(IOMD_KARTRX);
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 	if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", port) != 0) {
861da177e4SLinus Torvalds 		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n");
871da177e4SLinus Torvalds 		return -EBUSY;
881da177e4SLinus Torvalds 	}
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 	if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) {
911da177e4SLinus Torvalds 		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n");
921da177e4SLinus Torvalds 		free_irq(IRQ_KEYBOARDRX, NULL);
931da177e4SLinus Torvalds 		return -EBUSY;
941da177e4SLinus Torvalds 	}
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	return 0;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds static void rpckbd_close(struct serio *port)
1001da177e4SLinus Torvalds {
1011da177e4SLinus Torvalds 	free_irq(IRQ_KEYBOARDRX, port);
1021da177e4SLinus Torvalds 	free_irq(IRQ_KEYBOARDTX, port);
1031da177e4SLinus Torvalds }
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds /*
1061da177e4SLinus Torvalds  * Allocate and initialize serio structure for subsequent registration
1071da177e4SLinus Torvalds  * with serio core.
1081da177e4SLinus Torvalds  */
1093ae5eaecSRussell King static int __devinit rpckbd_probe(struct platform_device *dev)
1101da177e4SLinus Torvalds {
1111da177e4SLinus Torvalds 	struct serio *serio;
1121da177e4SLinus Torvalds 
113b39787a9SEric Sesterhenn 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
1141da177e4SLinus Torvalds 	if (!serio)
1151da177e4SLinus Torvalds 		return -ENOMEM;
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds 	serio->id.type		= SERIO_8042;
1181da177e4SLinus Torvalds 	serio->write		= rpckbd_write;
1191da177e4SLinus Torvalds 	serio->open		= rpckbd_open;
1201da177e4SLinus Torvalds 	serio->close		= rpckbd_close;
1213ae5eaecSRussell King 	serio->dev.parent	= &dev->dev;
1221da177e4SLinus Torvalds 	strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name));
1231da177e4SLinus Torvalds 	strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys));
1241da177e4SLinus Torvalds 
1253ae5eaecSRussell King 	platform_set_drvdata(dev, serio);
1261da177e4SLinus Torvalds 	serio_register_port(serio);
1271da177e4SLinus Torvalds 	return 0;
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds 
1303ae5eaecSRussell King static int __devexit rpckbd_remove(struct platform_device *dev)
1311da177e4SLinus Torvalds {
1323ae5eaecSRussell King 	struct serio *serio = platform_get_drvdata(dev);
1331da177e4SLinus Torvalds 	serio_unregister_port(serio);
1341da177e4SLinus Torvalds 	return 0;
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds 
1373ae5eaecSRussell King static struct platform_driver rpckbd_driver = {
1381da177e4SLinus Torvalds 	.probe		= rpckbd_probe,
1391da177e4SLinus Torvalds 	.remove		= __devexit_p(rpckbd_remove),
1403ae5eaecSRussell King 	.driver		= {
1413ae5eaecSRussell King 		.name	= "kart",
142d7b5247bSKay Sievers 		.owner	= THIS_MODULE,
1433ae5eaecSRussell King 	},
1441da177e4SLinus Torvalds };
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds static int __init rpckbd_init(void)
1471da177e4SLinus Torvalds {
1483ae5eaecSRussell King 	return platform_driver_register(&rpckbd_driver);
1491da177e4SLinus Torvalds }
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds static void __exit rpckbd_exit(void)
1521da177e4SLinus Torvalds {
1533ae5eaecSRussell King 	platform_driver_unregister(&rpckbd_driver);
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds module_init(rpckbd_init);
1571da177e4SLinus Torvalds module_exit(rpckbd_exit);
158