linux/drivers/input/misc/pmic8xxx-pwrkey.c
<<
>>
Prefs
   1/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
   2 *
   3 * This program is free software; you can redistribute it and/or modify
   4 * it under the terms of the GNU General Public License version 2 and
   5 * only version 2 as published by the Free Software Foundation.
   6 *
   7 * This program is distributed in the hope that it will be useful,
   8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 * GNU General Public License for more details.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/init.h>
  15#include <linux/kernel.h>
  16#include <linux/errno.h>
  17#include <linux/slab.h>
  18#include <linux/input.h>
  19#include <linux/interrupt.h>
  20#include <linux/platform_device.h>
  21#include <linux/log2.h>
  22
  23#include <linux/mfd/pm8xxx/core.h>
  24#include <linux/input/pmic8xxx-pwrkey.h>
  25
  26#define PON_CNTL_1 0x1C
  27#define PON_CNTL_PULL_UP BIT(7)
  28#define PON_CNTL_TRIG_DELAY_MASK (0x7)
  29
  30/**
  31 * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information
  32 * @key_press_irq: key press irq number
  33 */
  34struct pmic8xxx_pwrkey {
  35        struct input_dev *pwr;
  36        int key_press_irq;
  37};
  38
  39static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
  40{
  41        struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
  42
  43        input_report_key(pwrkey->pwr, KEY_POWER, 1);
  44        input_sync(pwrkey->pwr);
  45
  46        return IRQ_HANDLED;
  47}
  48
  49static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
  50{
  51        struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
  52
  53        input_report_key(pwrkey->pwr, KEY_POWER, 0);
  54        input_sync(pwrkey->pwr);
  55
  56        return IRQ_HANDLED;
  57}
  58
  59#ifdef CONFIG_PM_SLEEP
  60static int pmic8xxx_pwrkey_suspend(struct device *dev)
  61{
  62        struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
  63
  64        if (device_may_wakeup(dev))
  65                enable_irq_wake(pwrkey->key_press_irq);
  66
  67        return 0;
  68}
  69
  70static int pmic8xxx_pwrkey_resume(struct device *dev)
  71{
  72        struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
  73
  74        if (device_may_wakeup(dev))
  75                disable_irq_wake(pwrkey->key_press_irq);
  76
  77        return 0;
  78}
  79#endif
  80
  81static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
  82                pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
  83
  84static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
  85{
  86        struct input_dev *pwr;
  87        int key_release_irq = platform_get_irq(pdev, 0);
  88        int key_press_irq = platform_get_irq(pdev, 1);
  89        int err;
  90        unsigned int delay;
  91        u8 pon_cntl;
  92        struct pmic8xxx_pwrkey *pwrkey;
  93        const struct pm8xxx_pwrkey_platform_data *pdata =
  94                                        dev_get_platdata(&pdev->dev);
  95
  96        if (!pdata) {
  97                dev_err(&pdev->dev, "power key platform data not supplied\n");
  98                return -EINVAL;
  99        }
 100
 101        if (pdata->kpd_trigger_delay_us > 62500) {
 102                dev_err(&pdev->dev, "invalid power key trigger delay\n");
 103                return -EINVAL;
 104        }
 105
 106        pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
 107        if (!pwrkey)
 108                return -ENOMEM;
 109
 110        pwr = input_allocate_device();
 111        if (!pwr) {
 112                dev_dbg(&pdev->dev, "Can't allocate power button\n");
 113                err = -ENOMEM;
 114                goto free_pwrkey;
 115        }
 116
 117        input_set_capability(pwr, EV_KEY, KEY_POWER);
 118
 119        pwr->name = "pmic8xxx_pwrkey";
 120        pwr->phys = "pmic8xxx_pwrkey/input0";
 121        pwr->dev.parent = &pdev->dev;
 122
 123        delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
 124        delay = 1 + ilog2(delay);
 125
 126        err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
 127        if (err < 0) {
 128                dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
 129                goto free_input_dev;
 130        }
 131
 132        pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
 133        pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
 134        if (pdata->pull_up)
 135                pon_cntl |= PON_CNTL_PULL_UP;
 136        else
 137                pon_cntl &= ~PON_CNTL_PULL_UP;
 138
 139        err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
 140        if (err < 0) {
 141                dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
 142                goto free_input_dev;
 143        }
 144
 145        err = input_register_device(pwr);
 146        if (err) {
 147                dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
 148                goto free_input_dev;
 149        }
 150
 151        pwrkey->key_press_irq = key_press_irq;
 152        pwrkey->pwr = pwr;
 153
 154        platform_set_drvdata(pdev, pwrkey);
 155
 156        err = request_irq(key_press_irq, pwrkey_press_irq,
 157                IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
 158        if (err < 0) {
 159                dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
 160                                 key_press_irq, err);
 161                goto unreg_input_dev;
 162        }
 163
 164        err = request_irq(key_release_irq, pwrkey_release_irq,
 165                 IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
 166        if (err < 0) {
 167                dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
 168                                 key_release_irq, err);
 169
 170                goto free_press_irq;
 171        }
 172
 173        device_init_wakeup(&pdev->dev, pdata->wakeup);
 174
 175        return 0;
 176
 177free_press_irq:
 178        free_irq(key_press_irq, NULL);
 179unreg_input_dev:
 180        platform_set_drvdata(pdev, NULL);
 181        input_unregister_device(pwr);
 182        pwr = NULL;
 183free_input_dev:
 184        input_free_device(pwr);
 185free_pwrkey:
 186        kfree(pwrkey);
 187        return err;
 188}
 189
 190static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev)
 191{
 192        struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev);
 193        int key_release_irq = platform_get_irq(pdev, 0);
 194        int key_press_irq = platform_get_irq(pdev, 1);
 195
 196        device_init_wakeup(&pdev->dev, 0);
 197
 198        free_irq(key_press_irq, pwrkey);
 199        free_irq(key_release_irq, pwrkey);
 200        input_unregister_device(pwrkey->pwr);
 201        platform_set_drvdata(pdev, NULL);
 202        kfree(pwrkey);
 203
 204        return 0;
 205}
 206
 207static struct platform_driver pmic8xxx_pwrkey_driver = {
 208        .probe          = pmic8xxx_pwrkey_probe,
 209        .remove         = __devexit_p(pmic8xxx_pwrkey_remove),
 210        .driver         = {
 211                .name   = PM8XXX_PWRKEY_DEV_NAME,
 212                .owner  = THIS_MODULE,
 213                .pm     = &pm8xxx_pwr_key_pm_ops,
 214        },
 215};
 216module_platform_driver(pmic8xxx_pwrkey_driver);
 217
 218MODULE_ALIAS("platform:pmic8xxx_pwrkey");
 219MODULE_DESCRIPTION("PMIC8XXX Power Key driver");
 220MODULE_LICENSE("GPL v2");
 221MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
 222