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