| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 |  *  Copyright (c) 2000-2001 Vojtech Pavlik | 
 | 3 |  *  Copyright (c) 2002 Russell King | 
 | 4 |  */ | 
 | 5 |  | 
 | 6 | /* | 
 | 7 |  * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM | 
 | 8 |  */ | 
 | 9 |  | 
 | 10 | /* | 
 | 11 |  * This program is free software; you can redistribute it and/or modify | 
 | 12 |  * it under the terms of the GNU General Public License as published by | 
 | 13 |  * the Free Software Foundation; either version 2 of the License, or | 
 | 14 |  * (at your option) any later version. | 
 | 15 |  * | 
 | 16 |  * This program is distributed in the hope that it will be useful, | 
 | 17 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 18 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 19 |  * GNU General Public License for more details. | 
 | 20 |  * | 
 | 21 |  * You should have received a copy of the GNU General Public License | 
 | 22 |  * along with this program; if not, write to the Free Software | 
 | 23 |  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 
 | 24 |  * | 
 | 25 |  * Should you need to contact me, the author, you can do so either by | 
 | 26 |  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | 
 | 27 |  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 
 | 28 |  */ | 
 | 29 |  | 
 | 30 | #include <linux/module.h> | 
 | 31 | #include <linux/interrupt.h> | 
 | 32 | #include <linux/init.h> | 
 | 33 | #include <linux/serio.h> | 
 | 34 | #include <linux/err.h> | 
| Russell King | d052d1b | 2005-10-29 19:07:23 +0100 | [diff] [blame] | 35 | #include <linux/platform_device.h> | 
| Russell King | 9973022 | 2009-03-25 10:21:35 +0000 | [diff] [blame] | 36 | #include <linux/io.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 37 | #include <linux/slab.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 38 |  | 
 | 39 | #include <asm/irq.h> | 
| Russell King | a09e64f | 2008-08-05 16:14:15 +0100 | [diff] [blame] | 40 | #include <mach/hardware.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 41 | #include <asm/hardware/iomd.h> | 
 | 42 | #include <asm/system.h> | 
 | 43 |  | 
 | 44 | MODULE_AUTHOR("Vojtech Pavlik, Russell King"); | 
 | 45 | MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); | 
 | 46 | MODULE_LICENSE("GPL"); | 
| Kay Sievers | d7b5247 | 2008-04-18 00:24:42 -0400 | [diff] [blame] | 47 | MODULE_ALIAS("platform:kart"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 48 |  | 
 | 49 | static int rpckbd_write(struct serio *port, unsigned char val) | 
 | 50 | { | 
 | 51 | 	while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) | 
 | 52 | 		cpu_relax(); | 
 | 53 |  | 
 | 54 | 	iomd_writeb(val, IOMD_KARTTX); | 
 | 55 |  | 
 | 56 | 	return 0; | 
 | 57 | } | 
 | 58 |  | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 59 | static irqreturn_t rpckbd_rx(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 60 | { | 
 | 61 | 	struct serio *port = dev_id; | 
 | 62 | 	unsigned int byte; | 
 | 63 | 	int handled = IRQ_NONE; | 
 | 64 |  | 
 | 65 | 	while (iomd_readb(IOMD_KCTRL) & (1 << 5)) { | 
 | 66 | 		byte = iomd_readb(IOMD_KARTRX); | 
 | 67 |  | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 68 | 		serio_interrupt(port, byte, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | 		handled = IRQ_HANDLED; | 
 | 70 | 	} | 
 | 71 | 	return handled; | 
 | 72 | } | 
 | 73 |  | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 74 | static irqreturn_t rpckbd_tx(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 75 | { | 
 | 76 | 	return IRQ_HANDLED; | 
 | 77 | } | 
 | 78 |  | 
 | 79 | static int rpckbd_open(struct serio *port) | 
 | 80 | { | 
 | 81 | 	/* Reset the keyboard state machine. */ | 
 | 82 | 	iomd_writeb(0, IOMD_KCTRL); | 
 | 83 | 	iomd_writeb(8, IOMD_KCTRL); | 
 | 84 | 	iomd_readb(IOMD_KARTRX); | 
 | 85 |  | 
 | 86 | 	if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", port) != 0) { | 
 | 87 | 		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n"); | 
 | 88 | 		return -EBUSY; | 
 | 89 | 	} | 
 | 90 |  | 
 | 91 | 	if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) { | 
 | 92 | 		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n"); | 
| Axel Lin | e28e1d9 | 2011-04-02 21:20:24 -0700 | [diff] [blame] | 93 | 		free_irq(IRQ_KEYBOARDRX, port); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 94 | 		return -EBUSY; | 
 | 95 | 	} | 
 | 96 |  | 
 | 97 | 	return 0; | 
 | 98 | } | 
 | 99 |  | 
 | 100 | static void rpckbd_close(struct serio *port) | 
 | 101 | { | 
 | 102 | 	free_irq(IRQ_KEYBOARDRX, port); | 
 | 103 | 	free_irq(IRQ_KEYBOARDTX, port); | 
 | 104 | } | 
 | 105 |  | 
 | 106 | /* | 
 | 107 |  * Allocate and initialize serio structure for subsequent registration | 
 | 108 |  * with serio core. | 
 | 109 |  */ | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 110 | static int __devinit rpckbd_probe(struct platform_device *dev) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | { | 
 | 112 | 	struct serio *serio; | 
 | 113 |  | 
| Eric Sesterhenn | b39787a | 2006-03-14 00:09:16 -0500 | [diff] [blame] | 114 | 	serio = kzalloc(sizeof(struct serio), GFP_KERNEL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 | 	if (!serio) | 
 | 116 | 		return -ENOMEM; | 
 | 117 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | 	serio->id.type		= SERIO_8042; | 
 | 119 | 	serio->write		= rpckbd_write; | 
 | 120 | 	serio->open		= rpckbd_open; | 
 | 121 | 	serio->close		= rpckbd_close; | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 122 | 	serio->dev.parent	= &dev->dev; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 | 	strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name)); | 
 | 124 | 	strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys)); | 
 | 125 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 126 | 	platform_set_drvdata(dev, serio); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | 	serio_register_port(serio); | 
 | 128 | 	return 0; | 
 | 129 | } | 
 | 130 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 131 | static int __devexit rpckbd_remove(struct platform_device *dev) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 | { | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 133 | 	struct serio *serio = platform_get_drvdata(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 134 | 	serio_unregister_port(serio); | 
 | 135 | 	return 0; | 
 | 136 | } | 
 | 137 |  | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 138 | static struct platform_driver rpckbd_driver = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 139 | 	.probe		= rpckbd_probe, | 
 | 140 | 	.remove		= __devexit_p(rpckbd_remove), | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 141 | 	.driver		= { | 
 | 142 | 		.name	= "kart", | 
| Kay Sievers | d7b5247 | 2008-04-18 00:24:42 -0400 | [diff] [blame] | 143 | 		.owner	= THIS_MODULE, | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 144 | 	}, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 145 | }; | 
 | 146 |  | 
 | 147 | static int __init rpckbd_init(void) | 
 | 148 | { | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 149 | 	return platform_driver_register(&rpckbd_driver); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 | } | 
 | 151 |  | 
 | 152 | static void __exit rpckbd_exit(void) | 
 | 153 | { | 
| Russell King | 3ae5eae | 2005-11-09 22:32:44 +0000 | [diff] [blame] | 154 | 	platform_driver_unregister(&rpckbd_driver); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 155 | } | 
 | 156 |  | 
 | 157 | module_init(rpckbd_init); | 
 | 158 | module_exit(rpckbd_exit); |