linux/drivers/input/keyboard/spear-keyboard.c
<<
>>
Prefs
   1/*
   2 * SPEAr Keyboard Driver
   3 * Based on omap-keypad driver
   4 *
   5 * Copyright (C) 2010 ST Microelectronics
   6 * Rajeev Kumar<rajeev-dlh.kumar@st.com>
   7 *
   8 * This file is licensed under the terms of the GNU General Public
   9 * License version 2. This program is licensed "as is" without any
  10 * warranty of any kind, whether express or implied.
  11 */
  12
  13#include <linux/clk.h>
  14#include <linux/errno.h>
  15#include <linux/init.h>
  16#include <linux/interrupt.h>
  17#include <linux/input.h>
  18#include <linux/io.h>
  19#include <linux/irq.h>
  20#include <linux/kernel.h>
  21#include <linux/module.h>
  22#include <linux/platform_device.h>
  23#include <linux/pm_wakeup.h>
  24#include <linux/slab.h>
  25#include <linux/types.h>
  26#include <plat/keyboard.h>
  27
  28/* Keyboard Registers */
  29#define MODE_REG        0x00    /* 16 bit reg */
  30#define STATUS_REG      0x0C    /* 2 bit reg */
  31#define DATA_REG        0x10    /* 8 bit reg */
  32#define INTR_MASK       0x54
  33
  34/* Register Values */
  35/*
  36 * pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode
  37 * control register as 1010010(82MHZ)
  38 */
  39#define PCLK_FREQ_MSK   0xA400  /* 82 MHz */
  40#define START_SCAN      0x0100
  41#define SCAN_RATE_10    0x0000
  42#define SCAN_RATE_20    0x0004
  43#define SCAN_RATE_40    0x0008
  44#define SCAN_RATE_80    0x000C
  45#define MODE_KEYBOARD   0x0002
  46#define DATA_AVAIL      0x2
  47
  48#define KEY_MASK        0xFF000000
  49#define KEY_VALUE       0x00FFFFFF
  50#define ROW_MASK        0xF0
  51#define COLUMN_MASK     0x0F
  52#define ROW_SHIFT       4
  53
  54struct spear_kbd {
  55        struct input_dev *input;
  56        struct resource *res;
  57        void __iomem *io_base;
  58        struct clk *clk;
  59        unsigned int irq;
  60        unsigned short last_key;
  61        unsigned short keycodes[256];
  62};
  63
  64static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
  65{
  66        struct spear_kbd *kbd = dev_id;
  67        struct input_dev *input = kbd->input;
  68        unsigned int key;
  69        u8 sts, val;
  70
  71        sts = readb(kbd->io_base + STATUS_REG);
  72        if (sts & DATA_AVAIL)
  73                return IRQ_NONE;
  74
  75        if (kbd->last_key != KEY_RESERVED) {
  76                input_report_key(input, kbd->last_key, 0);
  77                kbd->last_key = KEY_RESERVED;
  78        }
  79
  80        /* following reads active (row, col) pair */
  81        val = readb(kbd->io_base + DATA_REG);
  82        key = kbd->keycodes[val];
  83
  84        input_event(input, EV_MSC, MSC_SCAN, val);
  85        input_report_key(input, key, 1);
  86        input_sync(input);
  87
  88        kbd->last_key = key;
  89
  90        /* clear interrupt */
  91        writeb(0, kbd->io_base + STATUS_REG);
  92
  93        return IRQ_HANDLED;
  94}
  95
  96static int spear_kbd_open(struct input_dev *dev)
  97{
  98        struct spear_kbd *kbd = input_get_drvdata(dev);
  99        int error;
 100        u16 val;
 101
 102        kbd->last_key = KEY_RESERVED;
 103
 104        error = clk_enable(kbd->clk);
 105        if (error)
 106                return error;
 107
 108        /* program keyboard */
 109        val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK;
 110        writew(val, kbd->io_base + MODE_REG);
 111        writeb(1, kbd->io_base + STATUS_REG);
 112
 113        /* start key scan */
 114        val = readw(kbd->io_base + MODE_REG);
 115        val |= START_SCAN;
 116        writew(val, kbd->io_base + MODE_REG);
 117
 118        return 0;
 119}
 120
 121static void spear_kbd_close(struct input_dev *dev)
 122{
 123        struct spear_kbd *kbd = input_get_drvdata(dev);
 124        u16 val;
 125
 126        /* stop key scan */
 127        val = readw(kbd->io_base + MODE_REG);
 128        val &= ~START_SCAN;
 129        writew(val, kbd->io_base + MODE_REG);
 130
 131        clk_disable(kbd->clk);
 132
 133        kbd->last_key = KEY_RESERVED;
 134}
 135
 136static int __devinit spear_kbd_probe(struct platform_device *pdev)
 137{
 138        const struct kbd_platform_data *pdata = pdev->dev.platform_data;
 139        const struct matrix_keymap_data *keymap;
 140        struct spear_kbd *kbd;
 141        struct input_dev *input_dev;
 142        struct resource *res;
 143        int irq;
 144        int error;
 145
 146        if (!pdata) {
 147                dev_err(&pdev->dev, "Invalid platform data\n");
 148                return -EINVAL;
 149        }
 150
 151        keymap = pdata->keymap;
 152        if (!keymap) {
 153                dev_err(&pdev->dev, "no keymap defined\n");
 154                return -EINVAL;
 155        }
 156
 157        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 158        if (!res) {
 159                dev_err(&pdev->dev, "no keyboard resource defined\n");
 160                return -EBUSY;
 161        }
 162
 163        irq = platform_get_irq(pdev, 0);
 164        if (irq < 0) {
 165                dev_err(&pdev->dev, "not able to get irq for the device\n");
 166                return irq;
 167        }
 168
 169        kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
 170        input_dev = input_allocate_device();
 171        if (!kbd || !input_dev) {
 172                dev_err(&pdev->dev, "out of memory\n");
 173                error = -ENOMEM;
 174                goto err_free_mem;
 175        }
 176
 177        kbd->input = input_dev;
 178        kbd->irq = irq;
 179        kbd->res = request_mem_region(res->start, resource_size(res),
 180                                      pdev->name);
 181        if (!kbd->res) {
 182                dev_err(&pdev->dev, "keyboard region already claimed\n");
 183                error = -EBUSY;
 184                goto err_free_mem;
 185        }
 186
 187        kbd->io_base = ioremap(res->start, resource_size(res));
 188        if (!kbd->io_base) {
 189                dev_err(&pdev->dev, "ioremap failed for kbd_region\n");
 190                error = -ENOMEM;
 191                goto err_release_mem_region;
 192        }
 193
 194        kbd->clk = clk_get(&pdev->dev, NULL);
 195        if (IS_ERR(kbd->clk)) {
 196                error = PTR_ERR(kbd->clk);
 197                goto err_iounmap;
 198        }
 199
 200        input_dev->name = "Spear Keyboard";
 201        input_dev->phys = "keyboard/input0";
 202        input_dev->dev.parent = &pdev->dev;
 203        input_dev->id.bustype = BUS_HOST;
 204        input_dev->id.vendor = 0x0001;
 205        input_dev->id.product = 0x0001;
 206        input_dev->id.version = 0x0100;
 207        input_dev->open = spear_kbd_open;
 208        input_dev->close = spear_kbd_close;
 209
 210        __set_bit(EV_KEY, input_dev->evbit);
 211        if (pdata->rep)
 212                __set_bit(EV_REP, input_dev->evbit);
 213        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 214
 215        input_dev->keycode = kbd->keycodes;
 216        input_dev->keycodesize = sizeof(kbd->keycodes[0]);
 217        input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes);
 218
 219        matrix_keypad_build_keymap(keymap, ROW_SHIFT,
 220                        input_dev->keycode, input_dev->keybit);
 221
 222        input_set_drvdata(input_dev, kbd);
 223
 224        error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd);
 225        if (error) {
 226                dev_err(&pdev->dev, "request_irq fail\n");
 227                goto err_put_clk;
 228        }
 229
 230        error = input_register_device(input_dev);
 231        if (error) {
 232                dev_err(&pdev->dev, "Unable to register keyboard device\n");
 233                goto err_free_irq;
 234        }
 235
 236        device_init_wakeup(&pdev->dev, 1);
 237        platform_set_drvdata(pdev, kbd);
 238
 239        return 0;
 240
 241err_free_irq:
 242        free_irq(kbd->irq, kbd);
 243err_put_clk:
 244        clk_put(kbd->clk);
 245err_iounmap:
 246        iounmap(kbd->io_base);
 247err_release_mem_region:
 248        release_mem_region(res->start, resource_size(res));
 249err_free_mem:
 250        input_free_device(input_dev);
 251        kfree(kbd);
 252
 253        return error;
 254}
 255
 256static int __devexit spear_kbd_remove(struct platform_device *pdev)
 257{
 258        struct spear_kbd *kbd = platform_get_drvdata(pdev);
 259
 260        free_irq(kbd->irq, kbd);
 261        input_unregister_device(kbd->input);
 262        clk_put(kbd->clk);
 263        iounmap(kbd->io_base);
 264        release_mem_region(kbd->res->start, resource_size(kbd->res));
 265        kfree(kbd);
 266
 267        device_init_wakeup(&pdev->dev, 1);
 268        platform_set_drvdata(pdev, NULL);
 269
 270        return 0;
 271}
 272
 273#ifdef CONFIG_PM
 274static int spear_kbd_suspend(struct device *dev)
 275{
 276        struct platform_device *pdev = to_platform_device(dev);
 277        struct spear_kbd *kbd = platform_get_drvdata(pdev);
 278        struct input_dev *input_dev = kbd->input;
 279
 280        mutex_lock(&input_dev->mutex);
 281
 282        if (input_dev->users)
 283                clk_enable(kbd->clk);
 284
 285        if (device_may_wakeup(&pdev->dev))
 286                enable_irq_wake(kbd->irq);
 287
 288        mutex_unlock(&input_dev->mutex);
 289
 290        return 0;
 291}
 292
 293static int spear_kbd_resume(struct device *dev)
 294{
 295        struct platform_device *pdev = to_platform_device(dev);
 296        struct spear_kbd *kbd = platform_get_drvdata(pdev);
 297        struct input_dev *input_dev = kbd->input;
 298
 299        mutex_lock(&input_dev->mutex);
 300
 301        if (device_may_wakeup(&pdev->dev))
 302                disable_irq_wake(kbd->irq);
 303
 304        if (input_dev->users)
 305                clk_enable(kbd->clk);
 306
 307        mutex_unlock(&input_dev->mutex);
 308
 309        return 0;
 310}
 311
 312static const struct dev_pm_ops spear_kbd_pm_ops = {
 313        .suspend        = spear_kbd_suspend,
 314        .resume         = spear_kbd_resume,
 315};
 316#endif
 317
 318static struct platform_driver spear_kbd_driver = {
 319        .probe          = spear_kbd_probe,
 320        .remove         = __devexit_p(spear_kbd_remove),
 321        .driver         = {
 322                .name   = "keyboard",
 323                .owner  = THIS_MODULE,
 324#ifdef CONFIG_PM
 325                .pm     = &spear_kbd_pm_ops,
 326#endif
 327        },
 328};
 329
 330static int __init spear_kbd_init(void)
 331{
 332        return platform_driver_register(&spear_kbd_driver);
 333}
 334module_init(spear_kbd_init);
 335
 336static void __exit spear_kbd_exit(void)
 337{
 338        platform_driver_unregister(&spear_kbd_driver);
 339}
 340module_exit(spear_kbd_exit);
 341
 342MODULE_AUTHOR("Rajeev Kumar");
 343MODULE_DESCRIPTION("SPEAr Keyboard Driver");
 344MODULE_LICENSE("GPL");
 345