Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * 88pm860x_onkey.c - Marvell 88PM860x ONKEY driver
0003  *
0004  * Copyright (C) 2009-2010 Marvell International Ltd.
0005  *      Haojian Zhuang <haojian.zhuang@marvell.com>
0006  *
0007  * This file is subject to the terms and conditions of the GNU General
0008  * Public License. See the file "COPYING" in the main directory of this
0009  * archive for more details.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program; if not, write to the Free Software
0018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0019  */
0020 
0021 #include <linux/kernel.h>
0022 #include <linux/module.h>
0023 #include <linux/platform_device.h>
0024 #include <linux/i2c.h>
0025 #include <linux/input.h>
0026 #include <linux/interrupt.h>
0027 #include <linux/mfd/88pm860x.h>
0028 #include <linux/slab.h>
0029 #include <linux/device.h>
0030 
0031 #define PM8607_WAKEUP       0x0b
0032 
0033 #define LONG_ONKEY_EN       (1 << 1)
0034 #define ONKEY_STATUS        (1 << 0)
0035 
0036 struct pm860x_onkey_info {
0037     struct input_dev    *idev;
0038     struct pm860x_chip  *chip;
0039     struct i2c_client   *i2c;
0040     struct device       *dev;
0041     int         irq;
0042 };
0043 
0044 /* 88PM860x gives us an interrupt when ONKEY is held */
0045 static irqreturn_t pm860x_onkey_handler(int irq, void *data)
0046 {
0047     struct pm860x_onkey_info *info = data;
0048     int ret;
0049 
0050     ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2);
0051     ret &= ONKEY_STATUS;
0052     input_report_key(info->idev, KEY_POWER, ret);
0053     input_sync(info->idev);
0054 
0055     /* Enable 8-second long onkey detection */
0056     pm860x_set_bits(info->i2c, PM8607_WAKEUP, 3, LONG_ONKEY_EN);
0057     return IRQ_HANDLED;
0058 }
0059 
0060 static int pm860x_onkey_probe(struct platform_device *pdev)
0061 {
0062     struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
0063     struct pm860x_onkey_info *info;
0064     int irq, ret;
0065 
0066     irq = platform_get_irq(pdev, 0);
0067     if (irq < 0)
0068         return -EINVAL;
0069 
0070     info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_onkey_info),
0071                 GFP_KERNEL);
0072     if (!info)
0073         return -ENOMEM;
0074     info->chip = chip;
0075     info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
0076     info->dev = &pdev->dev;
0077     info->irq = irq;
0078 
0079     info->idev = devm_input_allocate_device(&pdev->dev);
0080     if (!info->idev) {
0081         dev_err(chip->dev, "Failed to allocate input dev\n");
0082         return -ENOMEM;
0083     }
0084 
0085     info->idev->name = "88pm860x_on";
0086     info->idev->phys = "88pm860x_on/input0";
0087     info->idev->id.bustype = BUS_I2C;
0088     info->idev->dev.parent = &pdev->dev;
0089     info->idev->evbit[0] = BIT_MASK(EV_KEY);
0090     info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
0091 
0092     ret = input_register_device(info->idev);
0093     if (ret) {
0094         dev_err(chip->dev, "Can't register input device: %d\n", ret);
0095         return ret;
0096     }
0097 
0098     ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
0099                     pm860x_onkey_handler, IRQF_ONESHOT,
0100                     "onkey", info);
0101     if (ret < 0) {
0102         dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
0103             info->irq, ret);
0104         return ret;
0105     }
0106 
0107     platform_set_drvdata(pdev, info);
0108     device_init_wakeup(&pdev->dev, 1);
0109 
0110     return 0;
0111 }
0112 
0113 static int __maybe_unused pm860x_onkey_suspend(struct device *dev)
0114 {
0115     struct platform_device *pdev = to_platform_device(dev);
0116     struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
0117 
0118     if (device_may_wakeup(dev))
0119         chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
0120     return 0;
0121 }
0122 static int __maybe_unused pm860x_onkey_resume(struct device *dev)
0123 {
0124     struct platform_device *pdev = to_platform_device(dev);
0125     struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
0126 
0127     if (device_may_wakeup(dev))
0128         chip->wakeup_flag &= ~(1 << PM8607_IRQ_ONKEY);
0129     return 0;
0130 }
0131 
0132 static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
0133 
0134 static struct platform_driver pm860x_onkey_driver = {
0135     .driver     = {
0136         .name   = "88pm860x-onkey",
0137         .pm = &pm860x_onkey_pm_ops,
0138     },
0139     .probe      = pm860x_onkey_probe,
0140 };
0141 module_platform_driver(pm860x_onkey_driver);
0142 
0143 MODULE_DESCRIPTION("Marvell 88PM860x ONKEY driver");
0144 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
0145 MODULE_LICENSE("GPL");