linux/drivers/input/serio/altera_ps2.c
<<
>>
Prefs
   1/*
   2 * Altera University Program PS2 controller driver
   3 *
   4 * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
   5 *
   6 * Based on sa1111ps2.c, which is:
   7 * Copyright (C) 2002 Russell King
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/input.h>
  16#include <linux/serio.h>
  17#include <linux/interrupt.h>
  18#include <linux/platform_device.h>
  19#include <linux/io.h>
  20#include <linux/slab.h>
  21#include <linux/of.h>
  22
  23#define DRV_NAME "altera_ps2"
  24
  25struct ps2if {
  26        struct serio *io;
  27        void __iomem *base;
  28};
  29
  30/*
  31 * Read all bytes waiting in the PS2 port.  There should be
  32 * at the most one, but we loop for safety.
  33 */
  34static irqreturn_t altera_ps2_rxint(int irq, void *dev_id)
  35{
  36        struct ps2if *ps2if = dev_id;
  37        unsigned int status;
  38        irqreturn_t handled = IRQ_NONE;
  39
  40        while ((status = readl(ps2if->base)) & 0xffff0000) {
  41                serio_interrupt(ps2if->io, status & 0xff, 0);
  42                handled = IRQ_HANDLED;
  43        }
  44
  45        return handled;
  46}
  47
  48/*
  49 * Write a byte to the PS2 port.
  50 */
  51static int altera_ps2_write(struct serio *io, unsigned char val)
  52{
  53        struct ps2if *ps2if = io->port_data;
  54
  55        writel(val, ps2if->base);
  56        return 0;
  57}
  58
  59static int altera_ps2_open(struct serio *io)
  60{
  61        struct ps2if *ps2if = io->port_data;
  62
  63        /* clear fifo */
  64        while (readl(ps2if->base) & 0xffff0000)
  65                /* empty */;
  66
  67        writel(1, ps2if->base + 4); /* enable rx irq */
  68        return 0;
  69}
  70
  71static void altera_ps2_close(struct serio *io)
  72{
  73        struct ps2if *ps2if = io->port_data;
  74
  75        writel(0, ps2if->base + 4); /* disable rx irq */
  76}
  77
  78/*
  79 * Add one device to this driver.
  80 */
  81static int altera_ps2_probe(struct platform_device *pdev)
  82{
  83        struct ps2if *ps2if;
  84        struct resource *res;
  85        struct serio *serio;
  86        int error, irq;
  87
  88        ps2if = devm_kzalloc(&pdev->dev, sizeof(struct ps2if), GFP_KERNEL);
  89        if (!ps2if)
  90                return -ENOMEM;
  91
  92        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  93        ps2if->base = devm_ioremap_resource(&pdev->dev, res);
  94        if (IS_ERR(ps2if->base))
  95                return PTR_ERR(ps2if->base);
  96
  97        irq = platform_get_irq(pdev, 0);
  98        if (irq < 0)
  99                return -ENXIO;
 100
 101        error = devm_request_irq(&pdev->dev, irq, altera_ps2_rxint, 0,
 102                                 pdev->name, ps2if);
 103        if (error) {
 104                dev_err(&pdev->dev, "could not request IRQ %d\n", irq);
 105                return error;
 106        }
 107
 108        serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 109        if (!serio)
 110                return -ENOMEM;
 111
 112        serio->id.type          = SERIO_8042;
 113        serio->write            = altera_ps2_write;
 114        serio->open             = altera_ps2_open;
 115        serio->close            = altera_ps2_close;
 116        strlcpy(serio->name, dev_name(&pdev->dev), sizeof(serio->name));
 117        strlcpy(serio->phys, dev_name(&pdev->dev), sizeof(serio->phys));
 118        serio->port_data        = ps2if;
 119        serio->dev.parent       = &pdev->dev;
 120        ps2if->io               = serio;
 121
 122        dev_info(&pdev->dev, "base %p, irq %d\n", ps2if->base, irq);
 123
 124        serio_register_port(ps2if->io);
 125        platform_set_drvdata(pdev, ps2if);
 126
 127        return 0;
 128}
 129
 130/*
 131 * Remove one device from this driver.
 132 */
 133static int altera_ps2_remove(struct platform_device *pdev)
 134{
 135        struct ps2if *ps2if = platform_get_drvdata(pdev);
 136
 137        serio_unregister_port(ps2if->io);
 138
 139        return 0;
 140}
 141
 142#ifdef CONFIG_OF
 143static const struct of_device_id altera_ps2_match[] = {
 144        { .compatible = "ALTR,ps2-1.0", },
 145        { .compatible = "altr,ps2-1.0", },
 146        {},
 147};
 148MODULE_DEVICE_TABLE(of, altera_ps2_match);
 149#endif /* CONFIG_OF */
 150
 151/*
 152 * Our device driver structure
 153 */
 154static struct platform_driver altera_ps2_driver = {
 155        .probe          = altera_ps2_probe,
 156        .remove         = altera_ps2_remove,
 157        .driver = {
 158                .name   = DRV_NAME,
 159                .of_match_table = of_match_ptr(altera_ps2_match),
 160        },
 161};
 162module_platform_driver(altera_ps2_driver);
 163
 164MODULE_DESCRIPTION("Altera University Program PS2 controller driver");
 165MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
 166MODULE_LICENSE("GPL");
 167MODULE_ALIAS("platform:" DRV_NAME);
 168