linux/drivers/input/keyboard/ep93xx_keypad.c
<<
>>
Prefs
   1/*
   2 * Driver for the Cirrus EP93xx matrix keypad controller.
   3 *
   4 * Copyright (c) 2008 H Hartley Sweeten <hsweeten@visionengravers.com>
   5 *
   6 * Based on the pxa27x matrix keypad controller by Rodolfo Giometti.
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 * NOTE:
  13 *
  14 * The 3-key reset is triggered by pressing the 3 keys in
  15 * Row 0, Columns 2, 4, and 7 at the same time.  This action can
  16 * be disabled by setting the EP93XX_KEYPAD_DISABLE_3_KEY flag.
  17 *
  18 * Normal operation for the matrix does not autorepeat the key press.
  19 * This action can be enabled by setting the EP93XX_KEYPAD_AUTOREPEAT
  20 * flag.
  21 */
  22
  23#include <linux/module.h>
  24#include <linux/platform_device.h>
  25#include <linux/interrupt.h>
  26#include <linux/clk.h>
  27#include <linux/io.h>
  28#include <linux/input/matrix_keypad.h>
  29#include <linux/slab.h>
  30
  31#include <mach/hardware.h>
  32#include <mach/ep93xx_keypad.h>
  33
  34/*
  35 * Keypad Interface Register offsets
  36 */
  37#define KEY_INIT                0x00    /* Key Scan Initialization register */
  38#define KEY_DIAG                0x04    /* Key Scan Diagnostic register */
  39#define KEY_REG                 0x08    /* Key Value Capture register */
  40
  41/* Key Scan Initialization Register bit defines */
  42#define KEY_INIT_DBNC_MASK      (0x00ff0000)
  43#define KEY_INIT_DBNC_SHIFT     (16)
  44#define KEY_INIT_DIS3KY         (1<<15)
  45#define KEY_INIT_DIAG           (1<<14)
  46#define KEY_INIT_BACK           (1<<13)
  47#define KEY_INIT_T2             (1<<12)
  48#define KEY_INIT_PRSCL_MASK     (0x000003ff)
  49#define KEY_INIT_PRSCL_SHIFT    (0)
  50
  51/* Key Scan Diagnostic Register bit defines */
  52#define KEY_DIAG_MASK           (0x0000003f)
  53#define KEY_DIAG_SHIFT          (0)
  54
  55/* Key Value Capture Register bit defines */
  56#define KEY_REG_K               (1<<15)
  57#define KEY_REG_INT             (1<<14)
  58#define KEY_REG_2KEYS           (1<<13)
  59#define KEY_REG_1KEY            (1<<12)
  60#define KEY_REG_KEY2_MASK       (0x00000fc0)
  61#define KEY_REG_KEY2_SHIFT      (6)
  62#define KEY_REG_KEY1_MASK       (0x0000003f)
  63#define KEY_REG_KEY1_SHIFT      (0)
  64
  65#define EP93XX_MATRIX_SIZE      (EP93XX_MATRIX_ROWS * EP93XX_MATRIX_COLS)
  66
  67struct ep93xx_keypad {
  68        struct ep93xx_keypad_platform_data *pdata;
  69        struct input_dev *input_dev;
  70        struct clk *clk;
  71
  72        void __iomem *mmio_base;
  73
  74        unsigned short keycodes[EP93XX_MATRIX_SIZE];
  75
  76        int key1;
  77        int key2;
  78
  79        int irq;
  80
  81        bool enabled;
  82};
  83
  84static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
  85{
  86        struct ep93xx_keypad *keypad = dev_id;
  87        struct input_dev *input_dev = keypad->input_dev;
  88        unsigned int status;
  89        int keycode, key1, key2;
  90
  91        status = __raw_readl(keypad->mmio_base + KEY_REG);
  92
  93        keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT;
  94        key1 = keypad->keycodes[keycode];
  95
  96        keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT;
  97        key2 = keypad->keycodes[keycode];
  98
  99        if (status & KEY_REG_2KEYS) {
 100                if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1)
 101                        input_report_key(input_dev, keypad->key1, 0);
 102
 103                if (keypad->key2 && key1 != keypad->key2 && key2 != keypad->key2)
 104                        input_report_key(input_dev, keypad->key2, 0);
 105
 106                input_report_key(input_dev, key1, 1);
 107                input_report_key(input_dev, key2, 1);
 108
 109                keypad->key1 = key1;
 110                keypad->key2 = key2;
 111
 112        } else if (status & KEY_REG_1KEY) {
 113                if (keypad->key1 && key1 != keypad->key1)
 114                        input_report_key(input_dev, keypad->key1, 0);
 115
 116                if (keypad->key2 && key1 != keypad->key2)
 117                        input_report_key(input_dev, keypad->key2, 0);
 118
 119                input_report_key(input_dev, key1, 1);
 120
 121                keypad->key1 = key1;
 122                keypad->key2 = 0;
 123
 124        } else {
 125                input_report_key(input_dev, keypad->key1, 0);
 126                input_report_key(input_dev, keypad->key2, 0);
 127
 128                keypad->key1 = keypad->key2 = 0;
 129        }
 130        input_sync(input_dev);
 131
 132        return IRQ_HANDLED;
 133}
 134
 135static void ep93xx_keypad_config(struct ep93xx_keypad *keypad)
 136{
 137        struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
 138        unsigned int val = 0;
 139
 140        if (pdata->flags & EP93XX_KEYPAD_KDIV)
 141                clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV4);
 142        else
 143                clk_set_rate(keypad->clk, EP93XX_KEYTCHCLK_DIV16);
 144
 145        if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY)
 146                val |= KEY_INIT_DIS3KY;
 147        if (pdata->flags & EP93XX_KEYPAD_DIAG_MODE)
 148                val |= KEY_INIT_DIAG;
 149        if (pdata->flags & EP93XX_KEYPAD_BACK_DRIVE)
 150                val |= KEY_INIT_BACK;
 151        if (pdata->flags & EP93XX_KEYPAD_TEST_MODE)
 152                val |= KEY_INIT_T2;
 153
 154        val |= ((pdata->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK);
 155
 156        val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK);
 157
 158        __raw_writel(val, keypad->mmio_base + KEY_INIT);
 159}
 160
 161static int ep93xx_keypad_open(struct input_dev *pdev)
 162{
 163        struct ep93xx_keypad *keypad = input_get_drvdata(pdev);
 164
 165        if (!keypad->enabled) {
 166                ep93xx_keypad_config(keypad);
 167                clk_enable(keypad->clk);
 168                keypad->enabled = true;
 169        }
 170
 171        return 0;
 172}
 173
 174static void ep93xx_keypad_close(struct input_dev *pdev)
 175{
 176        struct ep93xx_keypad *keypad = input_get_drvdata(pdev);
 177
 178        if (keypad->enabled) {
 179                clk_disable(keypad->clk);
 180                keypad->enabled = false;
 181        }
 182}
 183
 184
 185#ifdef CONFIG_PM
 186/*
 187 * NOTE: I don't know if this is correct, or will work on the ep93xx.
 188 *
 189 * None of the existing ep93xx drivers have power management support.
 190 * But, this is basically what the pxa27x_keypad driver does.
 191 */
 192static int ep93xx_keypad_suspend(struct platform_device *pdev,
 193                                 pm_message_t state)
 194{
 195        struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
 196        struct input_dev *input_dev = keypad->input_dev;
 197
 198        mutex_lock(&input_dev->mutex);
 199
 200        if (keypad->enabled) {
 201                clk_disable(keypad->clk);
 202                keypad->enabled = false;
 203        }
 204
 205        mutex_unlock(&input_dev->mutex);
 206
 207        if (device_may_wakeup(&pdev->dev))
 208                enable_irq_wake(keypad->irq);
 209
 210        return 0;
 211}
 212
 213static int ep93xx_keypad_resume(struct platform_device *pdev)
 214{
 215        struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
 216        struct input_dev *input_dev = keypad->input_dev;
 217
 218        if (device_may_wakeup(&pdev->dev))
 219                disable_irq_wake(keypad->irq);
 220
 221        mutex_lock(&input_dev->mutex);
 222
 223        if (input_dev->users) {
 224                if (!keypad->enabled) {
 225                        ep93xx_keypad_config(keypad);
 226                        clk_enable(keypad->clk);
 227                        keypad->enabled = true;
 228                }
 229        }
 230
 231        mutex_unlock(&input_dev->mutex);
 232
 233        return 0;
 234}
 235#else   /* !CONFIG_PM */
 236#define ep93xx_keypad_suspend   NULL
 237#define ep93xx_keypad_resume    NULL
 238#endif  /* !CONFIG_PM */
 239
 240static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
 241{
 242        struct ep93xx_keypad *keypad;
 243        const struct matrix_keymap_data *keymap_data;
 244        struct input_dev *input_dev;
 245        struct resource *res;
 246        int err;
 247
 248        keypad = kzalloc(sizeof(struct ep93xx_keypad), GFP_KERNEL);
 249        if (!keypad)
 250                return -ENOMEM;
 251
 252        keypad->pdata = pdev->dev.platform_data;
 253        if (!keypad->pdata) {
 254                err = -EINVAL;
 255                goto failed_free;
 256        }
 257
 258        keymap_data = keypad->pdata->keymap_data;
 259        if (!keymap_data) {
 260                err = -EINVAL;
 261                goto failed_free;
 262        }
 263
 264        keypad->irq = platform_get_irq(pdev, 0);
 265        if (!keypad->irq) {
 266                err = -ENXIO;
 267                goto failed_free;
 268        }
 269
 270        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 271        if (!res) {
 272                err = -ENXIO;
 273                goto failed_free;
 274        }
 275
 276        res = request_mem_region(res->start, resource_size(res), pdev->name);
 277        if (!res) {
 278                err = -EBUSY;
 279                goto failed_free;
 280        }
 281
 282        keypad->mmio_base = ioremap(res->start, resource_size(res));
 283        if (keypad->mmio_base == NULL) {
 284                err = -ENXIO;
 285                goto failed_free_mem;
 286        }
 287
 288        err = ep93xx_keypad_acquire_gpio(pdev);
 289        if (err)
 290                goto failed_free_io;
 291
 292        keypad->clk = clk_get(&pdev->dev, NULL);
 293        if (IS_ERR(keypad->clk)) {
 294                err = PTR_ERR(keypad->clk);
 295                goto failed_free_gpio;
 296        }
 297
 298        input_dev = input_allocate_device();
 299        if (!input_dev) {
 300                err = -ENOMEM;
 301                goto failed_put_clk;
 302        }
 303
 304        keypad->input_dev = input_dev;
 305
 306        input_dev->name = pdev->name;
 307        input_dev->id.bustype = BUS_HOST;
 308        input_dev->open = ep93xx_keypad_open;
 309        input_dev->close = ep93xx_keypad_close;
 310        input_dev->dev.parent = &pdev->dev;
 311        input_dev->keycode = keypad->keycodes;
 312        input_dev->keycodesize = sizeof(keypad->keycodes[0]);
 313        input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
 314
 315        input_set_drvdata(input_dev, keypad);
 316
 317        input_dev->evbit[0] = BIT_MASK(EV_KEY);
 318        if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
 319                input_dev->evbit[0] |= BIT_MASK(EV_REP);
 320
 321        matrix_keypad_build_keymap(keymap_data, 3,
 322                                   input_dev->keycode, input_dev->keybit);
 323        platform_set_drvdata(pdev, keypad);
 324
 325        err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
 326                          0, pdev->name, keypad);
 327        if (err)
 328                goto failed_free_dev;
 329
 330        err = input_register_device(input_dev);
 331        if (err)
 332                goto failed_free_irq;
 333
 334        device_init_wakeup(&pdev->dev, 1);
 335
 336        return 0;
 337
 338failed_free_irq:
 339        free_irq(keypad->irq, pdev);
 340        platform_set_drvdata(pdev, NULL);
 341failed_free_dev:
 342        input_free_device(input_dev);
 343failed_put_clk:
 344        clk_put(keypad->clk);
 345failed_free_gpio:
 346        ep93xx_keypad_release_gpio(pdev);
 347failed_free_io:
 348        iounmap(keypad->mmio_base);
 349failed_free_mem:
 350        release_mem_region(res->start, resource_size(res));
 351failed_free:
 352        kfree(keypad);
 353        return err;
 354}
 355
 356static int __devexit ep93xx_keypad_remove(struct platform_device *pdev)
 357{
 358        struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
 359        struct resource *res;
 360
 361        free_irq(keypad->irq, pdev);
 362
 363        platform_set_drvdata(pdev, NULL);
 364
 365        if (keypad->enabled)
 366                clk_disable(keypad->clk);
 367        clk_put(keypad->clk);
 368
 369        input_unregister_device(keypad->input_dev);
 370
 371        ep93xx_keypad_release_gpio(pdev);
 372
 373        iounmap(keypad->mmio_base);
 374
 375        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 376        release_mem_region(res->start, resource_size(res));
 377
 378        kfree(keypad);
 379
 380        return 0;
 381}
 382
 383static struct platform_driver ep93xx_keypad_driver = {
 384        .driver         = {
 385                .name   = "ep93xx-keypad",
 386                .owner  = THIS_MODULE,
 387        },
 388        .probe          = ep93xx_keypad_probe,
 389        .remove         = __devexit_p(ep93xx_keypad_remove),
 390        .suspend        = ep93xx_keypad_suspend,
 391        .resume         = ep93xx_keypad_resume,
 392};
 393
 394static int __init ep93xx_keypad_init(void)
 395{
 396        return platform_driver_register(&ep93xx_keypad_driver);
 397}
 398
 399static void __exit ep93xx_keypad_exit(void)
 400{
 401        platform_driver_unregister(&ep93xx_keypad_driver);
 402}
 403
 404module_init(ep93xx_keypad_init);
 405module_exit(ep93xx_keypad_exit);
 406
 407MODULE_LICENSE("GPL");
 408MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
 409MODULE_DESCRIPTION("EP93xx Matrix Keypad Controller");
 410MODULE_ALIAS("platform:ep93xx-keypad");
 411
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.