Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add support for GRLIB APBPS2 PS/2 Keyboard/Mouse

APBPS2 is a PS/2 core part of GRLIB found in SPARC32/LEON
products.

Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Daniel Hellstrom and committed by
Dmitry Torokhov
b4a034da bfc29e95

+257
+16
Documentation/devicetree/bindings/input/ps2keyb-mouse-apbps2.txt
··· 1 + Aeroflex Gaisler APBPS2 PS/2 Core, supporting Keyboard or Mouse. 2 + 3 + The APBPS2 PS/2 core is available in the GRLIB VHDL IP core library. 4 + 5 + Note: In the ordinary environment for the APBPS2 core, a LEON SPARC system, 6 + these properties are built from information in the AMBA plug&play and from 7 + bootloader settings. 8 + 9 + Required properties: 10 + 11 + - name : Should be "GAISLER_APBPS2" or "01_060" 12 + - reg : Address and length of the register set for the device 13 + - interrupts : Interrupt numbers for this device 14 + 15 + For further information look in the documentation for the GLIB IP core library: 16 + http://www.gaisler.com/products/grlib/grip.pdf
+10
drivers/input/serio/Kconfig
··· 244 244 To compile this driver as a module, choose M here; the module 245 245 will be called arc_ps2. 246 246 247 + config SERIO_APBPS2 248 + tristate "GRLIB APBPS2 PS/2 keyboard/mouse controller" 249 + depends on OF 250 + help 251 + Say Y here if you want support for GRLIB APBPS2 peripherals used 252 + to connect to PS/2 keyboard and/or mouse. 253 + 254 + To compile this driver as a module, choose M here: the module will 255 + be called apbps2. 256 + 247 257 endif
+1
drivers/input/serio/Makefile
··· 26 26 obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o 27 27 obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o 28 28 obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o 29 + obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
+230
drivers/input/serio/apbps2.c
··· 1 + /* 2 + * Copyright (C) 2013 Aeroflex Gaisler 3 + * 4 + * This driver supports the APBPS2 PS/2 core available in the GRLIB 5 + * VHDL IP core library. 6 + * 7 + * Full documentation of the APBPS2 core can be found here: 8 + * http://www.gaisler.com/products/grlib/grip.pdf 9 + * 10 + * See "Documentation/devicetree/bindings/input/ps2keyb-mouse-apbps2.txt" for 11 + * information on open firmware properties. 12 + * 13 + * This program is free software; you can redistribute it and/or modify 14 + * it under the terms of the GNU General Public License as published by 15 + * the Free Software Foundation; either version 2 of the License, or 16 + * (at your option) any later version. 17 + * 18 + * Contributors: Daniel Hellstrom <daniel@gaisler.com> 19 + */ 20 + #include <linux/platform_device.h> 21 + #include <linux/of_device.h> 22 + #include <linux/module.h> 23 + #include <linux/serio.h> 24 + #include <linux/errno.h> 25 + #include <linux/interrupt.h> 26 + #include <linux/of_irq.h> 27 + #include <linux/device.h> 28 + #include <linux/delay.h> 29 + #include <linux/err.h> 30 + #include <linux/slab.h> 31 + #include <linux/string.h> 32 + #include <linux/kernel.h> 33 + #include <linux/io.h> 34 + 35 + struct apbps2_regs { 36 + u32 __iomem data; /* 0x00 */ 37 + u32 __iomem status; /* 0x04 */ 38 + u32 __iomem ctrl; /* 0x08 */ 39 + u32 __iomem reload; /* 0x0c */ 40 + }; 41 + 42 + #define APBPS2_STATUS_DR (1<<0) 43 + #define APBPS2_STATUS_PE (1<<1) 44 + #define APBPS2_STATUS_FE (1<<2) 45 + #define APBPS2_STATUS_KI (1<<3) 46 + #define APBPS2_STATUS_RF (1<<4) 47 + #define APBPS2_STATUS_TF (1<<5) 48 + #define APBPS2_STATUS_TCNT (0x1f<<22) 49 + #define APBPS2_STATUS_RCNT (0x1f<<27) 50 + 51 + #define APBPS2_CTRL_RE (1<<0) 52 + #define APBPS2_CTRL_TE (1<<1) 53 + #define APBPS2_CTRL_RI (1<<2) 54 + #define APBPS2_CTRL_TI (1<<3) 55 + 56 + struct apbps2_priv { 57 + struct serio *io; 58 + struct apbps2_regs *regs; 59 + }; 60 + 61 + static int apbps2_idx; 62 + 63 + static irqreturn_t apbps2_isr(int irq, void *dev_id) 64 + { 65 + struct apbps2_priv *priv = dev_id; 66 + unsigned long status, data, rxflags; 67 + irqreturn_t ret = IRQ_NONE; 68 + 69 + while ((status = ioread32be(&priv->regs->status)) & APBPS2_STATUS_DR) { 70 + data = ioread32be(&priv->regs->data); 71 + rxflags = (status & APBPS2_STATUS_PE) ? SERIO_PARITY : 0; 72 + rxflags |= (status & APBPS2_STATUS_FE) ? SERIO_FRAME : 0; 73 + 74 + /* clear error bits? */ 75 + if (rxflags) 76 + iowrite32be(0, &priv->regs->status); 77 + 78 + serio_interrupt(priv->io, data, rxflags); 79 + 80 + ret = IRQ_HANDLED; 81 + } 82 + 83 + return ret; 84 + } 85 + 86 + static int apbps2_write(struct serio *io, unsigned char val) 87 + { 88 + struct apbps2_priv *priv = io->port_data; 89 + unsigned int tleft = 10000; /* timeout in 100ms */ 90 + 91 + /* delay until PS/2 controller has room for more chars */ 92 + while ((ioread32be(&priv->regs->status) & APBPS2_STATUS_TF) && tleft--) 93 + udelay(10); 94 + 95 + if ((ioread32be(&priv->regs->status) & APBPS2_STATUS_TF) == 0) { 96 + iowrite32be(val, &priv->regs->data); 97 + 98 + iowrite32be(APBPS2_CTRL_RE | APBPS2_CTRL_RI | APBPS2_CTRL_TE, 99 + &priv->regs->ctrl); 100 + return 0; 101 + } 102 + 103 + return -ETIMEDOUT; 104 + } 105 + 106 + static int apbps2_open(struct serio *io) 107 + { 108 + struct apbps2_priv *priv = io->port_data; 109 + int limit; 110 + unsigned long tmp; 111 + 112 + /* clear error flags */ 113 + iowrite32be(0, &priv->regs->status); 114 + 115 + /* Clear old data if available (unlikely) */ 116 + limit = 1024; 117 + while ((ioread32be(&priv->regs->status) & APBPS2_STATUS_DR) && --limit) 118 + tmp = ioread32be(&priv->regs->data); 119 + 120 + /* Enable reciever and it's interrupt */ 121 + iowrite32be(APBPS2_CTRL_RE | APBPS2_CTRL_RI, &priv->regs->ctrl); 122 + 123 + return 0; 124 + } 125 + 126 + static void apbps2_close(struct serio *io) 127 + { 128 + struct apbps2_priv *priv = io->port_data; 129 + 130 + /* stop interrupts at PS/2 HW level */ 131 + iowrite32be(0, &priv->regs->ctrl); 132 + } 133 + 134 + /* Initialize one APBPS2 PS/2 core */ 135 + static int apbps2_of_probe(struct platform_device *ofdev) 136 + { 137 + struct apbps2_priv *priv; 138 + int irq, err; 139 + u32 freq_hz; 140 + struct resource *res; 141 + 142 + priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); 143 + if (!priv) { 144 + dev_err(&ofdev->dev, "memory allocation failed\n"); 145 + return -ENOMEM; 146 + } 147 + 148 + /* Find Device Address */ 149 + res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); 150 + priv->regs = devm_request_and_ioremap(&ofdev->dev, res); 151 + if (!priv->regs) { 152 + dev_err(&ofdev->dev, "io-regs mapping failed\n"); 153 + return -EBUSY; 154 + } 155 + 156 + /* Reset hardware, disable interrupt */ 157 + iowrite32be(0, &priv->regs->ctrl); 158 + 159 + /* IRQ */ 160 + irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); 161 + err = devm_request_irq(&ofdev->dev, irq, apbps2_isr, 162 + IRQF_SHARED, "apbps2", priv); 163 + if (err) { 164 + dev_err(&ofdev->dev, "request IRQ%d failed\n", irq); 165 + return err; 166 + } 167 + 168 + /* Get core frequency */ 169 + if (of_property_read_u32(ofdev->dev.of_node, "freq", &freq_hz)) { 170 + dev_err(&ofdev->dev, "unable to get core frequency\n"); 171 + return -EINVAL; 172 + } 173 + 174 + /* Set reload register to core freq in kHz/10 */ 175 + iowrite32be(freq_hz / 10000, &priv->regs->reload); 176 + 177 + priv->io = kzalloc(sizeof(struct serio), GFP_KERNEL); 178 + if (!priv->io) 179 + return -ENOMEM; 180 + 181 + priv->io->id.type = SERIO_8042; 182 + priv->io->open = apbps2_open; 183 + priv->io->close = apbps2_close; 184 + priv->io->write = apbps2_write; 185 + priv->io->port_data = priv; 186 + strlcpy(priv->io->name, "APBPS2 PS/2", sizeof(priv->io->name)); 187 + snprintf(priv->io->phys, sizeof(priv->io->phys), 188 + "apbps2_%d", apbps2_idx++); 189 + 190 + dev_info(&ofdev->dev, "irq = %d, base = 0x%p\n", irq, priv->regs); 191 + 192 + serio_register_port(priv->io); 193 + 194 + platform_set_drvdata(ofdev, priv); 195 + 196 + return 0; 197 + } 198 + 199 + static int apbps2_of_remove(struct platform_device *of_dev) 200 + { 201 + struct apbps2_priv *priv = platform_get_drvdata(of_dev); 202 + 203 + serio_unregister_port(priv->io); 204 + 205 + return 0; 206 + } 207 + 208 + static struct of_device_id apbps2_of_match[] = { 209 + { .name = "GAISLER_APBPS2", }, 210 + { .name = "01_060", }, 211 + {} 212 + }; 213 + 214 + MODULE_DEVICE_TABLE(of, apbps2_of_match); 215 + 216 + static struct platform_driver apbps2_of_driver = { 217 + .driver = { 218 + .name = "grlib-apbps2", 219 + .owner = THIS_MODULE, 220 + .of_match_table = apbps2_of_match, 221 + }, 222 + .probe = apbps2_of_probe, 223 + .remove = apbps2_of_remove, 224 + }; 225 + 226 + module_platform_driver(apbps2_of_driver); 227 + 228 + MODULE_AUTHOR("Aeroflex Gaisler AB."); 229 + MODULE_DESCRIPTION("GRLIB APBPS2 PS/2 serial I/O"); 230 + MODULE_LICENSE("GPL");