linux/drivers/input/keyboard/sh_keysc.c
<<
>>
Prefs
   1/*
   2 * SuperH KEYSC Keypad Driver
   3 *
   4 * Copyright (C) 2008 Magnus Damm
   5 *
   6 * Based on gpio_keys.c, Copyright 2005 Phil Blundell
   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
  13#include <linux/kernel.h>
  14#include <linux/module.h>
  15#include <linux/init.h>
  16#include <linux/interrupt.h>
  17#include <linux/irq.h>
  18#include <linux/delay.h>
  19#include <linux/platform_device.h>
  20#include <linux/input.h>
  21#include <linux/clk.h>
  22#include <linux/io.h>
  23#include <asm/sh_keysc.h>
  24
  25#define KYCR1_OFFS   0x00
  26#define KYCR2_OFFS   0x04
  27#define KYINDR_OFFS  0x08
  28#define KYOUTDR_OFFS 0x0c
  29
  30#define KYCR2_IRQ_LEVEL    0x10
  31#define KYCR2_IRQ_DISABLED 0x00
  32
  33static const struct {
  34        unsigned char kymd, keyout, keyin;
  35} sh_keysc_mode[] = {
  36        [SH_KEYSC_MODE_1] = { 0, 6, 5 },
  37        [SH_KEYSC_MODE_2] = { 1, 5, 6 },
  38        [SH_KEYSC_MODE_3] = { 2, 4, 7 },
  39};
  40
  41struct sh_keysc_priv {
  42        void __iomem *iomem_base;
  43        struct clk *clk;
  44        unsigned long last_keys;
  45        struct input_dev *input;
  46        struct sh_keysc_info pdata;
  47};
  48
  49static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
  50{
  51        struct platform_device *pdev = dev_id;
  52        struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
  53        struct sh_keysc_info *pdata = &priv->pdata;
  54        unsigned long keys, keys1, keys0, mask;
  55        unsigned char keyin_set, tmp;
  56        int i, k;
  57
  58        dev_dbg(&pdev->dev, "isr!\n");
  59
  60        keys1 = ~0;
  61        keys0 = 0;
  62
  63        do {
  64                keys = 0;
  65                keyin_set = 0;
  66
  67                iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
  68
  69                for (i = 0; i < sh_keysc_mode[pdata->mode].keyout; i++) {
  70                        iowrite16(0xfff ^ (3 << (i * 2)),
  71                                  priv->iomem_base + KYOUTDR_OFFS);
  72                        udelay(pdata->delay);
  73                        tmp = ioread16(priv->iomem_base + KYINDR_OFFS);
  74                        keys |= tmp << (sh_keysc_mode[pdata->mode].keyin * i);
  75                        tmp ^= (1 << sh_keysc_mode[pdata->mode].keyin) - 1;
  76                        keyin_set |= tmp;
  77                }
  78
  79                iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
  80                iowrite16(KYCR2_IRQ_LEVEL | (keyin_set << 8),
  81                          priv->iomem_base + KYCR2_OFFS);
  82
  83                keys ^= ~0;
  84                keys &= (1 << (sh_keysc_mode[pdata->mode].keyin *
  85                               sh_keysc_mode[pdata->mode].keyout)) - 1;
  86                keys1 &= keys;
  87                keys0 |= keys;
  88
  89                dev_dbg(&pdev->dev, "keys 0x%08lx\n", keys);
  90
  91        } while (ioread16(priv->iomem_base + KYCR2_OFFS) & 0x01);
  92
  93        dev_dbg(&pdev->dev, "last_keys 0x%08lx keys0 0x%08lx keys1 0x%08lx\n",
  94                priv->last_keys, keys0, keys1);
  95
  96        for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
  97                k = pdata->keycodes[i];
  98                if (!k)
  99                        continue;
 100
 101                mask = 1 << i;
 102
 103                if (!((priv->last_keys ^ keys0) & mask))
 104                        continue;
 105
 106                if ((keys1 | keys0) & mask) {
 107                        input_event(priv->input, EV_KEY, k, 1);
 108                        priv->last_keys |= mask;
 109                }
 110
 111                if (!(keys1 & mask)) {
 112                        input_event(priv->input, EV_KEY, k, 0);
 113                        priv->last_keys &= ~mask;
 114                }
 115
 116        }
 117        input_sync(priv->input);
 118
 119        return IRQ_HANDLED;
 120}
 121
 122#define res_size(res) ((res)->end - (res)->start + 1)
 123
 124static int __devinit sh_keysc_probe(struct platform_device *pdev)
 125{
 126        struct sh_keysc_priv *priv;
 127        struct sh_keysc_info *pdata;
 128        struct resource *res;
 129        struct input_dev *input;
 130        char clk_name[8];
 131        int i, k;
 132        int irq, error;
 133
 134        if (!pdev->dev.platform_data) {
 135                dev_err(&pdev->dev, "no platform data defined\n");
 136                error = -EINVAL;
 137                goto err0;
 138        }
 139
 140        error = -ENXIO;
 141        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 142        if (res == NULL) {
 143                dev_err(&pdev->dev, "failed to get I/O memory\n");
 144                goto err0;
 145        }
 146
 147        irq = platform_get_irq(pdev, 0);
 148        if (irq < 0) {
 149                dev_err(&pdev->dev, "failed to get irq\n");
 150                goto err0;
 151        }
 152
 153        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 154        if (priv == NULL) {
 155                dev_err(&pdev->dev, "failed to allocate driver data\n");
 156                error = -ENOMEM;
 157                goto err0;
 158        }
 159
 160        platform_set_drvdata(pdev, priv);
 161        memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata));
 162        pdata = &priv->pdata;
 163
 164        priv->iomem_base = ioremap_nocache(res->start, res_size(res));
 165        if (priv->iomem_base == NULL) {
 166                dev_err(&pdev->dev, "failed to remap I/O memory\n");
 167                error = -ENXIO;
 168                goto err1;
 169        }
 170
 171        snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id);
 172        priv->clk = clk_get(&pdev->dev, clk_name);
 173        if (IS_ERR(priv->clk)) {
 174                dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
 175                error = PTR_ERR(priv->clk);
 176                goto err2;
 177        }
 178
 179        priv->input = input_allocate_device();
 180        if (!priv->input) {
 181                dev_err(&pdev->dev, "failed to allocate input device\n");
 182                error = -ENOMEM;
 183                goto err3;
 184        }
 185
 186        input = priv->input;
 187        input->evbit[0] = BIT_MASK(EV_KEY);
 188
 189        input->name = pdev->name;
 190        input->phys = "sh-keysc-keys/input0";
 191        input->dev.parent = &pdev->dev;
 192
 193        input->id.bustype = BUS_HOST;
 194        input->id.vendor = 0x0001;
 195        input->id.product = 0x0001;
 196        input->id.version = 0x0100;
 197
 198        error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
 199        if (error) {
 200                dev_err(&pdev->dev, "failed to request IRQ\n");
 201                goto err4;
 202        }
 203
 204        for (i = 0; i < SH_KEYSC_MAXKEYS; i++) {
 205                k = pdata->keycodes[i];
 206                if (k)
 207                        input_set_capability(input, EV_KEY, k);
 208        }
 209
 210        error = input_register_device(input);
 211        if (error) {
 212                dev_err(&pdev->dev, "failed to register input device\n");
 213                goto err5;
 214        }
 215
 216        clk_enable(priv->clk);
 217
 218        iowrite16((sh_keysc_mode[pdata->mode].kymd << 8) |
 219                  pdata->scan_timing, priv->iomem_base + KYCR1_OFFS);
 220        iowrite16(0, priv->iomem_base + KYOUTDR_OFFS);
 221        iowrite16(KYCR2_IRQ_LEVEL, priv->iomem_base + KYCR2_OFFS);
 222
 223        device_init_wakeup(&pdev->dev, 1);
 224        return 0;
 225 err5:
 226        free_irq(irq, pdev);
 227 err4:
 228        input_free_device(input);
 229 err3:
 230        clk_put(priv->clk);
 231 err2:
 232        iounmap(priv->iomem_base);
 233 err1:
 234        platform_set_drvdata(pdev, NULL);
 235        kfree(priv);
 236 err0:
 237        return error;
 238}
 239
 240static int __devexit sh_keysc_remove(struct platform_device *pdev)
 241{
 242        struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
 243
 244        iowrite16(KYCR2_IRQ_DISABLED, priv->iomem_base + KYCR2_OFFS);
 245
 246        input_unregister_device(priv->input);
 247        free_irq(platform_get_irq(pdev, 0), pdev);
 248        iounmap(priv->iomem_base);
 249
 250        clk_disable(priv->clk);
 251        clk_put(priv->clk);
 252
 253        platform_set_drvdata(pdev, NULL);
 254        kfree(priv);
 255        return 0;
 256}
 257
 258static int sh_keysc_suspend(struct device *dev)
 259{
 260        struct platform_device *pdev = to_platform_device(dev);
 261        struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
 262        int irq = platform_get_irq(pdev, 0);
 263        unsigned short value;
 264
 265        value = ioread16(priv->iomem_base + KYCR1_OFFS);
 266
 267        if (device_may_wakeup(dev)) {
 268                value |= 0x80;
 269                enable_irq_wake(irq);
 270        }
 271        else
 272                value &= ~0x80;
 273
 274        iowrite16(value, priv->iomem_base + KYCR1_OFFS);
 275        return 0;
 276}
 277
 278static int sh_keysc_resume(struct device *dev)
 279{
 280        struct platform_device *pdev = to_platform_device(dev);
 281        int irq = platform_get_irq(pdev, 0);
 282
 283        if (device_may_wakeup(dev))
 284                disable_irq_wake(irq);
 285
 286        return 0;
 287}
 288
 289static struct dev_pm_ops sh_keysc_dev_pm_ops = {
 290        .suspend = sh_keysc_suspend,
 291        .resume = sh_keysc_resume,
 292};
 293
 294struct platform_driver sh_keysc_device_driver = {
 295        .probe          = sh_keysc_probe,
 296        .remove         = __devexit_p(sh_keysc_remove),
 297        .driver         = {
 298                .name   = "sh_keysc",
 299                .pm     = &sh_keysc_dev_pm_ops,
 300        }
 301};
 302
 303static int __init sh_keysc_init(void)
 304{
 305        return platform_driver_register(&sh_keysc_device_driver);
 306}
 307
 308static void __exit sh_keysc_exit(void)
 309{
 310        platform_driver_unregister(&sh_keysc_device_driver);
 311}
 312
 313module_init(sh_keysc_init);
 314module_exit(sh_keysc_exit);
 315
 316MODULE_AUTHOR("Magnus Damm");
 317MODULE_DESCRIPTION("SuperH KEYSC Keypad Driver");
 318MODULE_LICENSE("GPL");
 319