1*e443631dSVishnu Patekar /* 2*e443631dSVishnu Patekar * Driver for Allwinner A10 PS2 host controller 3*e443631dSVishnu Patekar * 4*e443631dSVishnu Patekar * Author: Vishnu Patekar <vishnupatekar0510@gmail.com> 5*e443631dSVishnu Patekar * Aaron.maoye <leafy.myeh@newbietech.com> 6*e443631dSVishnu Patekar */ 7*e443631dSVishnu Patekar 8*e443631dSVishnu Patekar #include <linux/module.h> 9*e443631dSVishnu Patekar #include <linux/serio.h> 10*e443631dSVishnu Patekar #include <linux/interrupt.h> 11*e443631dSVishnu Patekar #include <linux/errno.h> 12*e443631dSVishnu Patekar #include <linux/slab.h> 13*e443631dSVishnu Patekar #include <linux/io.h> 14*e443631dSVishnu Patekar #include <linux/clk.h> 15*e443631dSVishnu Patekar #include <linux/mod_devicetable.h> 16*e443631dSVishnu Patekar #include <linux/platform_device.h> 17*e443631dSVishnu Patekar 18*e443631dSVishnu Patekar #define DRIVER_NAME "sun4i-ps2" 19*e443631dSVishnu Patekar 20*e443631dSVishnu Patekar /* register offset definitions */ 21*e443631dSVishnu Patekar #define PS2_REG_GCTL 0x00 /* PS2 Module Global Control Reg */ 22*e443631dSVishnu Patekar #define PS2_REG_DATA 0x04 /* PS2 Module Data Reg */ 23*e443631dSVishnu Patekar #define PS2_REG_LCTL 0x08 /* PS2 Module Line Control Reg */ 24*e443631dSVishnu Patekar #define PS2_REG_LSTS 0x0C /* PS2 Module Line Status Reg */ 25*e443631dSVishnu Patekar #define PS2_REG_FCTL 0x10 /* PS2 Module FIFO Control Reg */ 26*e443631dSVishnu Patekar #define PS2_REG_FSTS 0x14 /* PS2 Module FIFO Status Reg */ 27*e443631dSVishnu Patekar #define PS2_REG_CLKDR 0x18 /* PS2 Module Clock Divider Reg*/ 28*e443631dSVishnu Patekar 29*e443631dSVishnu Patekar /* PS2 GLOBAL CONTROL REGISTER PS2_GCTL */ 30*e443631dSVishnu Patekar #define PS2_GCTL_INTFLAG BIT(4) 31*e443631dSVishnu Patekar #define PS2_GCTL_INTEN BIT(3) 32*e443631dSVishnu Patekar #define PS2_GCTL_RESET BIT(2) 33*e443631dSVishnu Patekar #define PS2_GCTL_MASTER BIT(1) 34*e443631dSVishnu Patekar #define PS2_GCTL_BUSEN BIT(0) 35*e443631dSVishnu Patekar 36*e443631dSVishnu Patekar /* PS2 LINE CONTROL REGISTER */ 37*e443631dSVishnu Patekar #define PS2_LCTL_NOACK BIT(18) 38*e443631dSVishnu Patekar #define PS2_LCTL_TXDTOEN BIT(8) 39*e443631dSVishnu Patekar #define PS2_LCTL_STOPERREN BIT(3) 40*e443631dSVishnu Patekar #define PS2_LCTL_ACKERREN BIT(2) 41*e443631dSVishnu Patekar #define PS2_LCTL_PARERREN BIT(1) 42*e443631dSVishnu Patekar #define PS2_LCTL_RXDTOEN BIT(0) 43*e443631dSVishnu Patekar 44*e443631dSVishnu Patekar /* PS2 LINE STATUS REGISTER */ 45*e443631dSVishnu Patekar #define PS2_LSTS_TXTDO BIT(8) 46*e443631dSVishnu Patekar #define PS2_LSTS_STOPERR BIT(3) 47*e443631dSVishnu Patekar #define PS2_LSTS_ACKERR BIT(2) 48*e443631dSVishnu Patekar #define PS2_LSTS_PARERR BIT(1) 49*e443631dSVishnu Patekar #define PS2_LSTS_RXTDO BIT(0) 50*e443631dSVishnu Patekar 51*e443631dSVishnu Patekar #define PS2_LINE_ERROR_BIT \ 52*e443631dSVishnu Patekar (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \ 53*e443631dSVishnu Patekar PS2_LSTS_PARERR | PS2_LSTS_RXTDO) 54*e443631dSVishnu Patekar 55*e443631dSVishnu Patekar /* PS2 FIFO CONTROL REGISTER */ 56*e443631dSVishnu Patekar #define PS2_FCTL_TXRST BIT(17) 57*e443631dSVishnu Patekar #define PS2_FCTL_RXRST BIT(16) 58*e443631dSVishnu Patekar #define PS2_FCTL_TXUFIEN BIT(10) 59*e443631dSVishnu Patekar #define PS2_FCTL_TXOFIEN BIT(9) 60*e443631dSVishnu Patekar #define PS2_FCTL_TXRDYIEN BIT(8) 61*e443631dSVishnu Patekar #define PS2_FCTL_RXUFIEN BIT(2) 62*e443631dSVishnu Patekar #define PS2_FCTL_RXOFIEN BIT(1) 63*e443631dSVishnu Patekar #define PS2_FCTL_RXRDYIEN BIT(0) 64*e443631dSVishnu Patekar 65*e443631dSVishnu Patekar /* PS2 FIFO STATUS REGISTER */ 66*e443631dSVishnu Patekar #define PS2_FSTS_TXUF BIT(10) 67*e443631dSVishnu Patekar #define PS2_FSTS_TXOF BIT(9) 68*e443631dSVishnu Patekar #define PS2_FSTS_TXRDY BIT(8) 69*e443631dSVishnu Patekar #define PS2_FSTS_RXUF BIT(2) 70*e443631dSVishnu Patekar #define PS2_FSTS_RXOF BIT(1) 71*e443631dSVishnu Patekar #define PS2_FSTS_RXRDY BIT(0) 72*e443631dSVishnu Patekar 73*e443631dSVishnu Patekar #define PS2_FIFO_ERROR_BIT \ 74*e443631dSVishnu Patekar (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF) 75*e443631dSVishnu Patekar 76*e443631dSVishnu Patekar #define PS2_SAMPLE_CLK 1000000 77*e443631dSVishnu Patekar #define PS2_SCLK 125000 78*e443631dSVishnu Patekar 79*e443631dSVishnu Patekar struct sun4i_ps2data { 80*e443631dSVishnu Patekar struct serio *serio; 81*e443631dSVishnu Patekar struct device *dev; 82*e443631dSVishnu Patekar 83*e443631dSVishnu Patekar /* IO mapping base */ 84*e443631dSVishnu Patekar void __iomem *reg_base; 85*e443631dSVishnu Patekar 86*e443631dSVishnu Patekar /* clock management */ 87*e443631dSVishnu Patekar struct clk *clk; 88*e443631dSVishnu Patekar 89*e443631dSVishnu Patekar /* irq */ 90*e443631dSVishnu Patekar spinlock_t lock; 91*e443631dSVishnu Patekar int irq; 92*e443631dSVishnu Patekar }; 93*e443631dSVishnu Patekar 94*e443631dSVishnu Patekar static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id) 95*e443631dSVishnu Patekar { 96*e443631dSVishnu Patekar struct sun4i_ps2data *drvdata = dev_id; 97*e443631dSVishnu Patekar u32 intr_status; 98*e443631dSVishnu Patekar u32 fifo_status; 99*e443631dSVishnu Patekar unsigned char byte; 100*e443631dSVishnu Patekar unsigned int rxflags = 0; 101*e443631dSVishnu Patekar u32 rval; 102*e443631dSVishnu Patekar 103*e443631dSVishnu Patekar spin_lock(&drvdata->lock); 104*e443631dSVishnu Patekar 105*e443631dSVishnu Patekar /* Get the PS/2 interrupts and clear them */ 106*e443631dSVishnu Patekar intr_status = readl(drvdata->reg_base + PS2_REG_LSTS); 107*e443631dSVishnu Patekar fifo_status = readl(drvdata->reg_base + PS2_REG_FSTS); 108*e443631dSVishnu Patekar 109*e443631dSVishnu Patekar /* Check line status register */ 110*e443631dSVishnu Patekar if (intr_status & PS2_LINE_ERROR_BIT) { 111*e443631dSVishnu Patekar rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0; 112*e443631dSVishnu Patekar rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0; 113*e443631dSVishnu Patekar rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0; 114*e443631dSVishnu Patekar 115*e443631dSVishnu Patekar rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | 116*e443631dSVishnu Patekar PS2_LSTS_PARERR | PS2_LSTS_RXTDO; 117*e443631dSVishnu Patekar writel(rval, drvdata->reg_base + PS2_REG_LSTS); 118*e443631dSVishnu Patekar } 119*e443631dSVishnu Patekar 120*e443631dSVishnu Patekar /* Check FIFO status register */ 121*e443631dSVishnu Patekar if (fifo_status & PS2_FIFO_ERROR_BIT) { 122*e443631dSVishnu Patekar rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY | 123*e443631dSVishnu Patekar PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY; 124*e443631dSVishnu Patekar writel(rval, drvdata->reg_base + PS2_REG_FSTS); 125*e443631dSVishnu Patekar } 126*e443631dSVishnu Patekar 127*e443631dSVishnu Patekar rval = (fifo_status >> 16) & 0x3; 128*e443631dSVishnu Patekar while (rval--) { 129*e443631dSVishnu Patekar byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff; 130*e443631dSVishnu Patekar serio_interrupt(drvdata->serio, byte, rxflags); 131*e443631dSVishnu Patekar } 132*e443631dSVishnu Patekar 133*e443631dSVishnu Patekar writel(intr_status, drvdata->reg_base + PS2_REG_LSTS); 134*e443631dSVishnu Patekar writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS); 135*e443631dSVishnu Patekar 136*e443631dSVishnu Patekar spin_unlock(&drvdata->lock); 137*e443631dSVishnu Patekar 138*e443631dSVishnu Patekar return IRQ_HANDLED; 139*e443631dSVishnu Patekar } 140*e443631dSVishnu Patekar 141*e443631dSVishnu Patekar static int sun4i_ps2_open(struct serio *serio) 142*e443631dSVishnu Patekar { 143*e443631dSVishnu Patekar struct sun4i_ps2data *drvdata = serio->port_data; 144*e443631dSVishnu Patekar u32 src_clk = 0; 145*e443631dSVishnu Patekar u32 clk_scdf; 146*e443631dSVishnu Patekar u32 clk_pcdf; 147*e443631dSVishnu Patekar u32 rval; 148*e443631dSVishnu Patekar unsigned long flags; 149*e443631dSVishnu Patekar 150*e443631dSVishnu Patekar /* Set line control and enable interrupt */ 151*e443631dSVishnu Patekar rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN 152*e443631dSVishnu Patekar | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN; 153*e443631dSVishnu Patekar writel(rval, drvdata->reg_base + PS2_REG_LCTL); 154*e443631dSVishnu Patekar 155*e443631dSVishnu Patekar /* Reset FIFO */ 156*e443631dSVishnu Patekar rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN 157*e443631dSVishnu Patekar | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN 158*e443631dSVishnu Patekar | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN; 159*e443631dSVishnu Patekar 160*e443631dSVishnu Patekar writel(rval, drvdata->reg_base + PS2_REG_FCTL); 161*e443631dSVishnu Patekar 162*e443631dSVishnu Patekar src_clk = clk_get_rate(drvdata->clk); 163*e443631dSVishnu Patekar /* Set clock divider register */ 164*e443631dSVishnu Patekar clk_scdf = src_clk / PS2_SAMPLE_CLK - 1; 165*e443631dSVishnu Patekar clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1; 166*e443631dSVishnu Patekar rval = (clk_scdf << 8) | clk_pcdf; 167*e443631dSVishnu Patekar writel(rval, drvdata->reg_base + PS2_REG_CLKDR); 168*e443631dSVishnu Patekar 169*e443631dSVishnu Patekar /* Set global control register */ 170*e443631dSVishnu Patekar rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER 171*e443631dSVishnu Patekar | PS2_GCTL_BUSEN; 172*e443631dSVishnu Patekar 173*e443631dSVishnu Patekar spin_lock_irqsave(&drvdata->lock, flags); 174*e443631dSVishnu Patekar writel(rval, drvdata->reg_base + PS2_REG_GCTL); 175*e443631dSVishnu Patekar spin_unlock_irqrestore(&drvdata->lock, flags); 176*e443631dSVishnu Patekar 177*e443631dSVishnu Patekar return 0; 178*e443631dSVishnu Patekar } 179*e443631dSVishnu Patekar 180*e443631dSVishnu Patekar static void sun4i_ps2_close(struct serio *serio) 181*e443631dSVishnu Patekar { 182*e443631dSVishnu Patekar struct sun4i_ps2data *drvdata = serio->port_data; 183*e443631dSVishnu Patekar u32 rval; 184*e443631dSVishnu Patekar 185*e443631dSVishnu Patekar /* Shut off the interrupt */ 186*e443631dSVishnu Patekar rval = readl(drvdata->reg_base + PS2_REG_GCTL); 187*e443631dSVishnu Patekar writel(rval & ~(PS2_GCTL_INTEN), drvdata->reg_base + PS2_REG_GCTL); 188*e443631dSVishnu Patekar 189*e443631dSVishnu Patekar synchronize_irq(drvdata->irq); 190*e443631dSVishnu Patekar } 191*e443631dSVishnu Patekar 192*e443631dSVishnu Patekar static int sun4i_ps2_write(struct serio *serio, unsigned char val) 193*e443631dSVishnu Patekar { 194*e443631dSVishnu Patekar unsigned long expire = jiffies + msecs_to_jiffies(10000); 195*e443631dSVishnu Patekar struct sun4i_ps2data *drvdata = serio->port_data; 196*e443631dSVishnu Patekar 197*e443631dSVishnu Patekar do { 198*e443631dSVishnu Patekar if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) { 199*e443631dSVishnu Patekar writel(val, drvdata->reg_base + PS2_REG_DATA); 200*e443631dSVishnu Patekar return 0; 201*e443631dSVishnu Patekar } 202*e443631dSVishnu Patekar } while (time_before(jiffies, expire)); 203*e443631dSVishnu Patekar 204*e443631dSVishnu Patekar return SERIO_TIMEOUT; 205*e443631dSVishnu Patekar } 206*e443631dSVishnu Patekar 207*e443631dSVishnu Patekar static int sun4i_ps2_probe(struct platform_device *pdev) 208*e443631dSVishnu Patekar { 209*e443631dSVishnu Patekar struct resource *res; /* IO mem resources */ 210*e443631dSVishnu Patekar struct sun4i_ps2data *drvdata; 211*e443631dSVishnu Patekar struct serio *serio; 212*e443631dSVishnu Patekar struct device *dev = &pdev->dev; 213*e443631dSVishnu Patekar unsigned int irq; 214*e443631dSVishnu Patekar int error; 215*e443631dSVishnu Patekar 216*e443631dSVishnu Patekar drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL); 217*e443631dSVishnu Patekar serio = kzalloc(sizeof(struct serio), GFP_KERNEL); 218*e443631dSVishnu Patekar if (!drvdata || !serio) { 219*e443631dSVishnu Patekar error = -ENOMEM; 220*e443631dSVishnu Patekar goto err_free_mem; 221*e443631dSVishnu Patekar } 222*e443631dSVishnu Patekar 223*e443631dSVishnu Patekar spin_lock_init(&drvdata->lock); 224*e443631dSVishnu Patekar 225*e443631dSVishnu Patekar /* IO */ 226*e443631dSVishnu Patekar res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 227*e443631dSVishnu Patekar if (!res) { 228*e443631dSVishnu Patekar dev_err(dev, "failed to locate registers\n"); 229*e443631dSVishnu Patekar error = -ENXIO; 230*e443631dSVishnu Patekar goto err_free_mem; 231*e443631dSVishnu Patekar } 232*e443631dSVishnu Patekar 233*e443631dSVishnu Patekar drvdata->reg_base = ioremap(res->start, resource_size(res)); 234*e443631dSVishnu Patekar if (!drvdata->reg_base) { 235*e443631dSVishnu Patekar dev_err(dev, "failed to map registers\n"); 236*e443631dSVishnu Patekar error = -ENOMEM; 237*e443631dSVishnu Patekar goto err_free_mem; 238*e443631dSVishnu Patekar } 239*e443631dSVishnu Patekar 240*e443631dSVishnu Patekar drvdata->clk = clk_get(dev, NULL); 241*e443631dSVishnu Patekar if (IS_ERR(drvdata->clk)) { 242*e443631dSVishnu Patekar error = PTR_ERR(drvdata->clk); 243*e443631dSVishnu Patekar dev_err(dev, "couldn't get clock %d\n", error); 244*e443631dSVishnu Patekar goto err_ioremap; 245*e443631dSVishnu Patekar } 246*e443631dSVishnu Patekar 247*e443631dSVishnu Patekar error = clk_prepare_enable(drvdata->clk); 248*e443631dSVishnu Patekar if (error) { 249*e443631dSVishnu Patekar dev_err(dev, "failed to enable clock %d\n", error); 250*e443631dSVishnu Patekar goto err_clk; 251*e443631dSVishnu Patekar } 252*e443631dSVishnu Patekar 253*e443631dSVishnu Patekar serio->id.type = SERIO_8042; 254*e443631dSVishnu Patekar serio->write = sun4i_ps2_write; 255*e443631dSVishnu Patekar serio->open = sun4i_ps2_open; 256*e443631dSVishnu Patekar serio->close = sun4i_ps2_close; 257*e443631dSVishnu Patekar serio->port_data = drvdata; 258*e443631dSVishnu Patekar serio->dev.parent = dev; 259*e443631dSVishnu Patekar strlcpy(serio->name, dev_name(dev), sizeof(serio->name)); 260*e443631dSVishnu Patekar strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys)); 261*e443631dSVishnu Patekar 262*e443631dSVishnu Patekar /* shutoff interrupt */ 263*e443631dSVishnu Patekar writel(0, drvdata->reg_base + PS2_REG_GCTL); 264*e443631dSVishnu Patekar 265*e443631dSVishnu Patekar /* Get IRQ for the device */ 266*e443631dSVishnu Patekar irq = platform_get_irq(pdev, 0); 267*e443631dSVishnu Patekar if (!irq) { 268*e443631dSVishnu Patekar dev_err(dev, "no IRQ found\n"); 269*e443631dSVishnu Patekar error = -ENXIO; 270*e443631dSVishnu Patekar goto err_disable_clk; 271*e443631dSVishnu Patekar } 272*e443631dSVishnu Patekar 273*e443631dSVishnu Patekar drvdata->irq = irq; 274*e443631dSVishnu Patekar drvdata->serio = serio; 275*e443631dSVishnu Patekar drvdata->dev = dev; 276*e443631dSVishnu Patekar 277*e443631dSVishnu Patekar error = request_irq(drvdata->irq, sun4i_ps2_interrupt, 0, 278*e443631dSVishnu Patekar DRIVER_NAME, drvdata); 279*e443631dSVishnu Patekar if (error) { 280*e443631dSVishnu Patekar dev_err(drvdata->dev, "failed to allocate interrupt %d: %d\n", 281*e443631dSVishnu Patekar drvdata->irq, error); 282*e443631dSVishnu Patekar goto err_disable_clk; 283*e443631dSVishnu Patekar } 284*e443631dSVishnu Patekar 285*e443631dSVishnu Patekar serio_register_port(serio); 286*e443631dSVishnu Patekar platform_set_drvdata(pdev, drvdata); 287*e443631dSVishnu Patekar 288*e443631dSVishnu Patekar return 0; /* success */ 289*e443631dSVishnu Patekar 290*e443631dSVishnu Patekar err_disable_clk: 291*e443631dSVishnu Patekar clk_disable_unprepare(drvdata->clk); 292*e443631dSVishnu Patekar err_clk: 293*e443631dSVishnu Patekar clk_put(drvdata->clk); 294*e443631dSVishnu Patekar err_ioremap: 295*e443631dSVishnu Patekar iounmap(drvdata->reg_base); 296*e443631dSVishnu Patekar err_free_mem: 297*e443631dSVishnu Patekar kfree(serio); 298*e443631dSVishnu Patekar kfree(drvdata); 299*e443631dSVishnu Patekar return error; 300*e443631dSVishnu Patekar } 301*e443631dSVishnu Patekar 302*e443631dSVishnu Patekar static int sun4i_ps2_remove(struct platform_device *pdev) 303*e443631dSVishnu Patekar { 304*e443631dSVishnu Patekar struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev); 305*e443631dSVishnu Patekar 306*e443631dSVishnu Patekar serio_unregister_port(drvdata->serio); 307*e443631dSVishnu Patekar 308*e443631dSVishnu Patekar free_irq(drvdata->irq, drvdata); 309*e443631dSVishnu Patekar 310*e443631dSVishnu Patekar clk_disable_unprepare(drvdata->clk); 311*e443631dSVishnu Patekar clk_put(drvdata->clk); 312*e443631dSVishnu Patekar 313*e443631dSVishnu Patekar iounmap(drvdata->reg_base); 314*e443631dSVishnu Patekar 315*e443631dSVishnu Patekar kfree(drvdata); 316*e443631dSVishnu Patekar 317*e443631dSVishnu Patekar return 0; 318*e443631dSVishnu Patekar } 319*e443631dSVishnu Patekar 320*e443631dSVishnu Patekar static const struct of_device_id sun4i_ps2_match[] = { 321*e443631dSVishnu Patekar { .compatible = "allwinner,sun4i-a10-ps2", }, 322*e443631dSVishnu Patekar { }, 323*e443631dSVishnu Patekar }; 324*e443631dSVishnu Patekar 325*e443631dSVishnu Patekar MODULE_DEVICE_TABLE(of, sun4i_ps2_match); 326*e443631dSVishnu Patekar 327*e443631dSVishnu Patekar static struct platform_driver sun4i_ps2_driver = { 328*e443631dSVishnu Patekar .probe = sun4i_ps2_probe, 329*e443631dSVishnu Patekar .remove = sun4i_ps2_remove, 330*e443631dSVishnu Patekar .driver = { 331*e443631dSVishnu Patekar .name = DRIVER_NAME, 332*e443631dSVishnu Patekar .of_match_table = sun4i_ps2_match, 333*e443631dSVishnu Patekar }, 334*e443631dSVishnu Patekar }; 335*e443631dSVishnu Patekar module_platform_driver(sun4i_ps2_driver); 336*e443631dSVishnu Patekar 337*e443631dSVishnu Patekar MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>"); 338*e443631dSVishnu Patekar MODULE_AUTHOR("Aaron.maoye <leafy.myeh@newbietech.com>"); 339*e443631dSVishnu Patekar MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver"); 340*e443631dSVishnu Patekar MODULE_LICENSE("GPL v2"); 341