Path: blob/master/drivers/input/misc/max8925_onkey.c
15109 views
/**1* max8925_onkey.c - MAX8925 ONKEY driver2*3* Copyright (C) 2009 Marvell International Ltd.4* Haojian Zhuang <[email protected]>5*6* This file is subject to the terms and conditions of the GNU General7* Public License. See the file "COPYING" in the main directory of this8* archive for more details.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/1920#include <linux/kernel.h>21#include <linux/module.h>22#include <linux/platform_device.h>23#include <linux/i2c.h>24#include <linux/input.h>25#include <linux/interrupt.h>26#include <linux/mfd/max8925.h>27#include <linux/slab.h>2829#define SW_INPUT (1 << 7) /* 0/1 -- up/down */30#define HARDRESET_EN (1 << 7)31#define PWREN_EN (1 << 7)3233struct max8925_onkey_info {34struct input_dev *idev;35struct i2c_client *i2c;36struct device *dev;37int irq[2];38};3940/*41* MAX8925 gives us an interrupt when ONKEY is pressed or released.42* max8925_set_bits() operates I2C bus and may sleep. So implement43* it in thread IRQ handler.44*/45static irqreturn_t max8925_onkey_handler(int irq, void *data)46{47struct max8925_onkey_info *info = data;48int ret, event;4950ret = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);51if (ret & SW_INPUT)52event = 1;53else54event = 0;55input_report_key(info->idev, KEY_POWER, event);56input_sync(info->idev);5758dev_dbg(info->dev, "onkey event:%d\n", event);5960/* Enable hardreset to halt if system isn't shutdown on time */61max8925_set_bits(info->i2c, MAX8925_SYSENSEL,62HARDRESET_EN, HARDRESET_EN);6364return IRQ_HANDLED;65}6667static int __devinit max8925_onkey_probe(struct platform_device *pdev)68{69struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);70struct max8925_onkey_info *info;71int irq[2], error;7273irq[0] = platform_get_irq(pdev, 0);74if (irq[0] < 0) {75dev_err(&pdev->dev, "No IRQ resource!\n");76return -EINVAL;77}78irq[1] = platform_get_irq(pdev, 1);79if (irq[1] < 0) {80dev_err(&pdev->dev, "No IRQ resource!\n");81return -EINVAL;82}8384info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);85if (!info)86return -ENOMEM;8788info->i2c = chip->i2c;89info->dev = &pdev->dev;90irq[0] += chip->irq_base;91irq[1] += chip->irq_base;9293error = request_threaded_irq(irq[0], NULL, max8925_onkey_handler,94IRQF_ONESHOT, "onkey-down", info);95if (error < 0) {96dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",97irq[0], error);98goto out;99}100error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler,101IRQF_ONESHOT, "onkey-up", info);102if (error < 0) {103dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",104irq[1], error);105goto out_irq;106}107108info->idev = input_allocate_device();109if (!info->idev) {110dev_err(chip->dev, "Failed to allocate input dev\n");111error = -ENOMEM;112goto out_input;113}114115info->idev->name = "max8925_on";116info->idev->phys = "max8925_on/input0";117info->idev->id.bustype = BUS_I2C;118info->idev->dev.parent = &pdev->dev;119info->irq[0] = irq[0];120info->irq[1] = irq[1];121info->idev->evbit[0] = BIT_MASK(EV_KEY);122info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);123124125error = input_register_device(info->idev);126if (error) {127dev_err(chip->dev, "Can't register input device: %d\n", error);128goto out_reg;129}130131platform_set_drvdata(pdev, info);132133return 0;134135out_reg:136input_free_device(info->idev);137out_input:138free_irq(info->irq[1], info);139out_irq:140free_irq(info->irq[0], info);141out:142kfree(info);143return error;144}145146static int __devexit max8925_onkey_remove(struct platform_device *pdev)147{148struct max8925_onkey_info *info = platform_get_drvdata(pdev);149150free_irq(info->irq[0], info);151free_irq(info->irq[1], info);152input_unregister_device(info->idev);153kfree(info);154155platform_set_drvdata(pdev, NULL);156157return 0;158}159160static struct platform_driver max8925_onkey_driver = {161.driver = {162.name = "max8925-onkey",163.owner = THIS_MODULE,164},165.probe = max8925_onkey_probe,166.remove = __devexit_p(max8925_onkey_remove),167};168169static int __init max8925_onkey_init(void)170{171return platform_driver_register(&max8925_onkey_driver);172}173module_init(max8925_onkey_init);174175static void __exit max8925_onkey_exit(void)176{177platform_driver_unregister(&max8925_onkey_driver);178}179module_exit(max8925_onkey_exit);180181MODULE_DESCRIPTION("Maxim MAX8925 ONKEY driver");182MODULE_AUTHOR("Haojian Zhuang <[email protected]>");183MODULE_LICENSE("GPL");184185186