11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/drivers/input/serio/sa1111ps2.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 Russell King 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/input.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serio.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/hardware/sa1111.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 264f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2CR 0x0000 274f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT 0x0004 284f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2DATA 0x0008 294f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2CLKDIV 0x000c 304f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2PRECNT 0x0010 314f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King 324f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2CR_ENA 0x08 334f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2CR_FKD 0x02 344f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2CR_FKC 0x01 354f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King 364f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT_STP 0x0100 374f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT_TXE 0x0080 384f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT_TXB 0x0040 394f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT_RXF 0x0020 404f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT_RXB 0x0010 414f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT_ENA 0x0008 424f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT_RXP 0x0004 434f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT_KBD 0x0002 444f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King#define PS2STAT_KBC 0x0001 454f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ps2if { 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio *io; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sa1111_dev *dev; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *base; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int open; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int head; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int tail; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char buf[4]; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read all bytes waiting in the PS2 port. There should be 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * at the most one, but we loop for safety. If there was a 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * framing error, we have to manually clear the status. 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 627d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t ps2_rxint(int irq, void *dev_id) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2if *ps2if = dev_id; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int scancode, flag, status; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 674f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King status = sa1111_readl(ps2if->base + PS2STAT); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (status & PS2STAT_RXF) { 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & PS2STAT_STP) 704f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King sa1111_writel(PS2STAT_STP, ps2if->base + PS2STAT); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) | 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (status & PS2STAT_RXP ? 0 : SERIO_PARITY); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 754f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King scancode = sa1111_readl(ps2if->base + PS2DATA) & 0xff; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hweight8(scancode) & 1) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flag ^= SERIO_PARITY; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 807d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells serio_interrupt(ps2if->io, scancode, flag); 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 824f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King status = sa1111_readl(ps2if->base + PS2STAT); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Completion of ps2 write 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 917d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t ps2_txint(int irq, void *dev_id) 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2if *ps2if = dev_id; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&ps2if->lock); 974f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King status = sa1111_readl(ps2if->base + PS2STAT); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2if->head == ps2if->tail) { 99e4bd3e591c8cc52ccf7a0b27f33aa7a5a19058d7Ben Nizette disable_irq_nosync(irq); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* done */ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (status & PS2STAT_TXE) { 1024f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&ps2if->lock); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write a byte to the PS2 port. We have to wait for the 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * port to indicate that the transmitter is empty. 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ps2_write(struct serio *io, unsigned char val) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2if *ps2if = io->port_data; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int head; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&ps2if->lock, flags); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the TX register is empty, we can go straight out. 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1254f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King if (sa1111_readl(ps2if->base + PS2STAT) & PS2STAT_TXE) { 1264f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King sa1111_writel(val, ps2if->base + PS2DATA); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ps2if->head == ps2if->tail) 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_irq(ps2if->dev->irq[1]); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (head != ps2if->tail) { 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->buf[ps2if->head] = val; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->head = head; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&ps2if->lock, flags); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ps2_open(struct serio *io) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2if *ps2if = io->port_data; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 146ae99ddbc976572194e8a68cb9ca1e27805ce30c7Russell King ret = sa1111_enable_device(ps2if->dev); 147ae99ddbc976572194e8a68cb9ca1e27805ce30c7Russell King if (ret) 148ae99ddbc976572194e8a68cb9ca1e27805ce30c7Russell King return ret; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0, 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SA1111_DRIVER_NAME(ps2if->dev), ps2if); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->dev->irq[0], ret); 155ae99ddbc976572194e8a68cb9ca1e27805ce30c7Russell King sa1111_disable_device(ps2if->dev); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = request_irq(ps2if->dev->irq[1], ps2_txint, 0, 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SA1111_DRIVER_NAME(ps2if->dev), ps2if); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->dev->irq[1], ret); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(ps2if->dev->irq[0], ps2if); 165ae99ddbc976572194e8a68cb9ca1e27805ce30c7Russell King sa1111_disable_device(ps2if->dev); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->open = 1; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_irq_wake(ps2if->dev->irq[0]); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1734f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King sa1111_writel(PS2CR_ENA, ps2if->base + PS2CR); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ps2_close(struct serio *io) 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2if *ps2if = io->port_data; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1814f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King sa1111_writel(0, ps2if->base + PS2CR); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_irq_wake(ps2if->dev->irq[0]); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->open = 0; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(ps2if->dev->irq[1], ps2if); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(ps2if->dev->irq[0], ps2if); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sa1111_disable_device(ps2if->dev); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear the input buffer. 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1965298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic void ps2_clear_input(struct ps2if *ps2if) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int maxread = 100; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (maxread--) { 2014f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King if ((sa1111_readl(ps2if->base + PS2DATA) & 0xff) == 0xff) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2065298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic unsigned int ps2_test_one(struct ps2if *ps2if, 207010c33cc7907239ffc8f49f09ccb3dc6d84a0369Dmitry Torokhov unsigned int mask) 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int val; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2114f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King sa1111_writel(PS2CR_ENA | mask, ps2if->base + PS2CR); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(2); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2154f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King val = sa1111_readl(ps2if->base + PS2STAT); 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val & (PS2STAT_KBC | PS2STAT_KBD); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Test the keyboard interface. We basically check to make sure that 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we can drive each line to the keyboard independently of each other. 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2235298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic int ps2_test(struct ps2if *ps2if) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int stat; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat = ps2_test_one(ps2if, PS2CR_FKC); 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stat != PS2STAT_KBD) { 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("PS/2 interface test failed[1]: %02x\n", stat); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat = ps2_test_one(ps2if, 0); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stat != (PS2STAT_KBC | PS2STAT_KBD)) { 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("PS/2 interface test failed[2]: %02x\n", stat); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat = ps2_test_one(ps2if, PS2CR_FKD); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (stat != PS2STAT_KBC) { 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("PS/2 interface test failed[3]: %02x\n", stat); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2464f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King sa1111_writel(0, ps2if->base + PS2CR); 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add one device to this driver. 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2545298cc4cc753bbe4c530b41341834f6ef3344d0dBill Pembertonstatic int ps2_probe(struct sa1111_dev *dev) 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2if *ps2if; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct serio *serio; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 260dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL); 261dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ps2if || !serio) { 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio->id.type = SERIO_8042; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio->write = ps2_write; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio->open = ps2_open; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio->close = ps2_close; 2724e8718a1f960db0c48427f4583f89f4cb62f2480Kay Sievers strlcpy(serio->name, dev_name(&dev->dev), sizeof(serio->name)); 2734e8718a1f960db0c48427f4583f89f4cb62f2480Kay Sievers strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys)); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio->port_data = ps2if; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio->dev.parent = &dev->dev; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->io = serio; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->dev = dev; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sa1111_set_drvdata(dev, ps2if); 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&ps2if->lock); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Request the physical region for this PS2 port. 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_mem_region(dev->res.start, 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->res.end - dev->res.start + 1, 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SA1111_DRIVER_NAME(dev))) { 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EBUSY; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Our parent device has already mapped the region. 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2if->base = dev->mapbase; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sa1111_enable_device(ps2if->dev); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Incoming clock is 8MHz */ 3004f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King sa1111_writel(0, ps2if->base + PS2CLKDIV); 3014f8d9cae15b5b5c89ec17c8168215aa06a5c9b2cRussell King sa1111_writel(127, ps2if->base + PS2PRECNT); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Flush any pending input. 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_clear_input(ps2if); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Test the keyboard interface. 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = ps2_test(ps2if); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Flush any pending input. 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ps2_clear_input(ps2if); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sa1111_disable_device(ps2if->dev); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_register_port(ps2if->io); 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sa1111_disable_device(ps2if->dev); 32628f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches release_mem_region(dev->res.start, resource_size(&dev->res)); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free: 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sa1111_set_drvdata(dev, NULL); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(ps2if); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(serio); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove one device from this driver. 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 337e2619cf78e19476bfd7ceaefa9eff0847529346eBill Pembertonstatic int ps2_remove(struct sa1111_dev *dev) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ps2if *ps2if = sa1111_get_drvdata(dev); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serio_unregister_port(ps2if->io); 34228f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches release_mem_region(dev->res.start, resource_size(&dev->res)); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sa1111_set_drvdata(dev, NULL); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(ps2if); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Our device driver structure 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sa1111_driver ps2_driver = { 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drv = { 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "sa1111-ps2", 3561ebcd7654e4e391a36945c937c125995c737c446Russell King .owner = THIS_MODULE, 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .devid = SA1111_DEVID_PS2, 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = ps2_probe, 3601cb0aa88179b7a71c240529e9d781d7bbb43d2e8Bill Pemberton .remove = ps2_remove, 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ps2_init(void) 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sa1111_driver_register(&ps2_driver); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit ps2_exit(void) 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sa1111_driver_unregister(&ps2_driver); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(ps2_init); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(ps2_exit); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("SA1111 PS2 controller driver"); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 379