linux/drivers/input/misc/ab8500-ponkey.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) ST-Ericsson SA 2010
   3 *
   4 * License Terms: GNU General Public License v2
   5 * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
   6 *
   7 * AB8500 Power-On Key handler
   8 */
   9
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/platform_device.h>
  13#include <linux/input.h>
  14#include <linux/interrupt.h>
  15#include <linux/mfd/ab8500.h>
  16#include <linux/slab.h>
  17
  18/**
  19 * struct ab8500_ponkey - ab8500 ponkey information
  20 * @input_dev: pointer to input device
  21 * @ab8500: ab8500 parent
  22 * @irq_dbf: irq number for falling transition
  23 * @irq_dbr: irq number for rising transition
  24 */
  25struct ab8500_ponkey {
  26        struct input_dev        *idev;
  27        struct ab8500           *ab8500;
  28        int                     irq_dbf;
  29        int                     irq_dbr;
  30};
  31
  32/* AB8500 gives us an interrupt when ONKEY is held */
  33static irqreturn_t ab8500_ponkey_handler(int irq, void *data)
  34{
  35        struct ab8500_ponkey *ponkey = data;
  36
  37        if (irq == ponkey->irq_dbf)
  38                input_report_key(ponkey->idev, KEY_POWER, true);
  39        else if (irq == ponkey->irq_dbr)
  40                input_report_key(ponkey->idev, KEY_POWER, false);
  41
  42        input_sync(ponkey->idev);
  43
  44        return IRQ_HANDLED;
  45}
  46
  47static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
  48{
  49        struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
  50        struct ab8500_ponkey *ponkey;
  51        struct input_dev *input;
  52        int irq_dbf, irq_dbr;
  53        int error;
  54
  55        irq_dbf = platform_get_irq_byname(pdev, "ONKEY_DBF");
  56        if (irq_dbf < 0) {
  57                dev_err(&pdev->dev, "No IRQ for ONKEY_DBF, error=%d\n", irq_dbf);
  58                return irq_dbf;
  59        }
  60
  61        irq_dbr = platform_get_irq_byname(pdev, "ONKEY_DBR");
  62        if (irq_dbr < 0) {
  63                dev_err(&pdev->dev, "No IRQ for ONKEY_DBR, error=%d\n", irq_dbr);
  64                return irq_dbr;
  65        }
  66
  67        ponkey = kzalloc(sizeof(struct ab8500_ponkey), GFP_KERNEL);
  68        input = input_allocate_device();
  69        if (!ponkey || !input) {
  70                error = -ENOMEM;
  71                goto err_free_mem;
  72        }
  73
  74        ponkey->idev = input;
  75        ponkey->ab8500 = ab8500;
  76        ponkey->irq_dbf = irq_dbf;
  77        ponkey->irq_dbr = irq_dbr;
  78
  79        input->name = "AB8500 POn(PowerOn) Key";
  80        input->dev.parent = &pdev->dev;
  81
  82        input_set_capability(input, EV_KEY, KEY_POWER);
  83
  84        error = request_any_context_irq(ponkey->irq_dbf, ab8500_ponkey_handler,
  85                                        0, "ab8500-ponkey-dbf", ponkey);
  86        if (error < 0) {
  87                dev_err(ab8500->dev, "Failed to request dbf IRQ#%d: %d\n",
  88                        ponkey->irq_dbf, error);
  89                goto err_free_mem;
  90        }
  91
  92        error = request_any_context_irq(ponkey->irq_dbr, ab8500_ponkey_handler,
  93                                        0, "ab8500-ponkey-dbr", ponkey);
  94        if (error < 0) {
  95                dev_err(ab8500->dev, "Failed to request dbr IRQ#%d: %d\n",
  96                        ponkey->irq_dbr, error);
  97                goto err_free_dbf_irq;
  98        }
  99
 100        error = input_register_device(ponkey->idev);
 101        if (error) {
 102                dev_err(ab8500->dev, "Can't register input device: %d\n", error);
 103                goto err_free_dbr_irq;
 104        }
 105
 106        platform_set_drvdata(pdev, ponkey);
 107        return 0;
 108
 109err_free_dbr_irq:
 110        free_irq(ponkey->irq_dbr, ponkey);
 111err_free_dbf_irq:
 112        free_irq(ponkey->irq_dbf, ponkey);
 113err_free_mem:
 114        input_free_device(input);
 115        kfree(ponkey);
 116
 117        return error;
 118}
 119
 120static int __devexit ab8500_ponkey_remove(struct platform_device *pdev)
 121{
 122        struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev);
 123
 124        free_irq(ponkey->irq_dbf, ponkey);
 125        free_irq(ponkey->irq_dbr, ponkey);
 126        input_unregister_device(ponkey->idev);
 127        kfree(ponkey);
 128
 129        platform_set_drvdata(pdev, NULL);
 130
 131        return 0;
 132}
 133
 134static struct platform_driver ab8500_ponkey_driver = {
 135        .driver         = {
 136                .name   = "ab8500-poweron-key",
 137                .owner  = THIS_MODULE,
 138        },
 139        .probe          = ab8500_ponkey_probe,
 140        .remove         = __devexit_p(ab8500_ponkey_remove),
 141};
 142
 143static int __init ab8500_ponkey_init(void)
 144{
 145        return platform_driver_register(&ab8500_ponkey_driver);
 146}
 147module_init(ab8500_ponkey_init);
 148
 149static void __exit ab8500_ponkey_exit(void)
 150{
 151        platform_driver_unregister(&ab8500_ponkey_driver);
 152}
 153module_exit(ab8500_ponkey_exit);
 154
 155MODULE_LICENSE("GPL v2");
 156MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
 157MODULE_DESCRIPTION("ST-Ericsson AB8500 Power-ON(Pon) Key driver");
 158