168d8bf04SFelipe Balbi /** 268d8bf04SFelipe Balbi * twl4030-pwrbutton.c - TWL4030 Power Button Input Driver 368d8bf04SFelipe Balbi * 468d8bf04SFelipe Balbi * Copyright (C) 2008-2009 Nokia Corporation 568d8bf04SFelipe Balbi * 668d8bf04SFelipe Balbi * Written by Peter De Schrijver <peter.de-schrijver@nokia.com> 768d8bf04SFelipe Balbi * Several fixes by Felipe Balbi <felipe.balbi@nokia.com> 868d8bf04SFelipe Balbi * 968d8bf04SFelipe Balbi * This file is subject to the terms and conditions of the GNU General 1068d8bf04SFelipe Balbi * Public License. See the file "COPYING" in the main directory of this 1168d8bf04SFelipe Balbi * archive for more details. 1268d8bf04SFelipe Balbi * 1368d8bf04SFelipe Balbi * This program is distributed in the hope that it will be useful, 1468d8bf04SFelipe Balbi * but WITHOUT ANY WARRANTY; without even the implied warranty of 1568d8bf04SFelipe Balbi * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1668d8bf04SFelipe Balbi * GNU General Public License for more details. 1768d8bf04SFelipe Balbi * 1868d8bf04SFelipe Balbi * You should have received a copy of the GNU General Public License 1968d8bf04SFelipe Balbi * along with this program; if not, write to the Free Software 2068d8bf04SFelipe Balbi * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2168d8bf04SFelipe Balbi */ 2268d8bf04SFelipe Balbi 2368d8bf04SFelipe Balbi #include <linux/module.h> 2468d8bf04SFelipe Balbi #include <linux/init.h> 2568d8bf04SFelipe Balbi #include <linux/kernel.h> 2668d8bf04SFelipe Balbi #include <linux/errno.h> 2768d8bf04SFelipe Balbi #include <linux/input.h> 2868d8bf04SFelipe Balbi #include <linux/interrupt.h> 2968d8bf04SFelipe Balbi #include <linux/platform_device.h> 30b07682b6SSantosh Shilimkar #include <linux/i2c/twl.h> 3168d8bf04SFelipe Balbi 3268d8bf04SFelipe Balbi #define PWR_PWRON_IRQ (1 << 0) 3368d8bf04SFelipe Balbi 3468d8bf04SFelipe Balbi #define STS_HW_CONDITIONS 0xf 3568d8bf04SFelipe Balbi 3668d8bf04SFelipe Balbi static irqreturn_t powerbutton_irq(int irq, void *_pwr) 3768d8bf04SFelipe Balbi { 3868d8bf04SFelipe Balbi struct input_dev *pwr = _pwr; 3968d8bf04SFelipe Balbi int err; 4068d8bf04SFelipe Balbi u8 value; 4168d8bf04SFelipe Balbi 4268d8bf04SFelipe Balbi #ifdef CONFIG_LOCKDEP 4368d8bf04SFelipe Balbi /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which 4468d8bf04SFelipe Balbi * we don't want and can't tolerate since this is a threaded 4568d8bf04SFelipe Balbi * IRQ and can sleep due to the i2c reads it has to issue. 4668d8bf04SFelipe Balbi * Although it might be friendlier not to borrow this thread 4768d8bf04SFelipe Balbi * context... 4868d8bf04SFelipe Balbi */ 4968d8bf04SFelipe Balbi local_irq_enable(); 5068d8bf04SFelipe Balbi #endif 5168d8bf04SFelipe Balbi 52*fc7b92fcSBalaji T K err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, 5368d8bf04SFelipe Balbi STS_HW_CONDITIONS); 5468d8bf04SFelipe Balbi if (!err) { 5568d8bf04SFelipe Balbi input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); 5668d8bf04SFelipe Balbi input_sync(pwr); 5768d8bf04SFelipe Balbi } else { 5868d8bf04SFelipe Balbi dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading" 5968d8bf04SFelipe Balbi " TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err); 6068d8bf04SFelipe Balbi } 6168d8bf04SFelipe Balbi 6268d8bf04SFelipe Balbi return IRQ_HANDLED; 6368d8bf04SFelipe Balbi } 6468d8bf04SFelipe Balbi 6568d8bf04SFelipe Balbi static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev) 6668d8bf04SFelipe Balbi { 6768d8bf04SFelipe Balbi struct input_dev *pwr; 6868d8bf04SFelipe Balbi int irq = platform_get_irq(pdev, 0); 6968d8bf04SFelipe Balbi int err; 7068d8bf04SFelipe Balbi 7168d8bf04SFelipe Balbi pwr = input_allocate_device(); 7268d8bf04SFelipe Balbi if (!pwr) { 7368d8bf04SFelipe Balbi dev_dbg(&pdev->dev, "Can't allocate power button\n"); 7468d8bf04SFelipe Balbi return -ENOMEM; 7568d8bf04SFelipe Balbi } 7668d8bf04SFelipe Balbi 7768d8bf04SFelipe Balbi pwr->evbit[0] = BIT_MASK(EV_KEY); 7868d8bf04SFelipe Balbi pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); 7968d8bf04SFelipe Balbi pwr->name = "twl4030_pwrbutton"; 8068d8bf04SFelipe Balbi pwr->phys = "twl4030_pwrbutton/input0"; 8168d8bf04SFelipe Balbi pwr->dev.parent = &pdev->dev; 8268d8bf04SFelipe Balbi 8368d8bf04SFelipe Balbi err = request_irq(irq, powerbutton_irq, 8468d8bf04SFelipe Balbi IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 8568d8bf04SFelipe Balbi "twl4030_pwrbutton", pwr); 8668d8bf04SFelipe Balbi if (err < 0) { 8768d8bf04SFelipe Balbi dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); 8868d8bf04SFelipe Balbi goto free_input_dev; 8968d8bf04SFelipe Balbi } 9068d8bf04SFelipe Balbi 9168d8bf04SFelipe Balbi err = input_register_device(pwr); 9268d8bf04SFelipe Balbi if (err) { 9368d8bf04SFelipe Balbi dev_dbg(&pdev->dev, "Can't register power button: %d\n", err); 9468d8bf04SFelipe Balbi goto free_irq; 9568d8bf04SFelipe Balbi } 9668d8bf04SFelipe Balbi 9768d8bf04SFelipe Balbi platform_set_drvdata(pdev, pwr); 9868d8bf04SFelipe Balbi 9968d8bf04SFelipe Balbi return 0; 10068d8bf04SFelipe Balbi 10168d8bf04SFelipe Balbi free_irq: 10268d8bf04SFelipe Balbi free_irq(irq, NULL); 10368d8bf04SFelipe Balbi free_input_dev: 10468d8bf04SFelipe Balbi input_free_device(pwr); 10568d8bf04SFelipe Balbi return err; 10668d8bf04SFelipe Balbi } 10768d8bf04SFelipe Balbi 10868d8bf04SFelipe Balbi static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev) 10968d8bf04SFelipe Balbi { 11068d8bf04SFelipe Balbi struct input_dev *pwr = platform_get_drvdata(pdev); 11168d8bf04SFelipe Balbi int irq = platform_get_irq(pdev, 0); 11268d8bf04SFelipe Balbi 11368d8bf04SFelipe Balbi free_irq(irq, pwr); 11468d8bf04SFelipe Balbi input_unregister_device(pwr); 11568d8bf04SFelipe Balbi 11668d8bf04SFelipe Balbi return 0; 11768d8bf04SFelipe Balbi } 11868d8bf04SFelipe Balbi 11968d8bf04SFelipe Balbi struct platform_driver twl4030_pwrbutton_driver = { 12068d8bf04SFelipe Balbi .probe = twl4030_pwrbutton_probe, 12168d8bf04SFelipe Balbi .remove = __devexit_p(twl4030_pwrbutton_remove), 12268d8bf04SFelipe Balbi .driver = { 12368d8bf04SFelipe Balbi .name = "twl4030_pwrbutton", 12468d8bf04SFelipe Balbi .owner = THIS_MODULE, 12568d8bf04SFelipe Balbi }, 12668d8bf04SFelipe Balbi }; 12768d8bf04SFelipe Balbi 12868d8bf04SFelipe Balbi static int __init twl4030_pwrbutton_init(void) 12968d8bf04SFelipe Balbi { 13068d8bf04SFelipe Balbi return platform_driver_register(&twl4030_pwrbutton_driver); 13168d8bf04SFelipe Balbi } 13268d8bf04SFelipe Balbi module_init(twl4030_pwrbutton_init); 13368d8bf04SFelipe Balbi 13468d8bf04SFelipe Balbi static void __exit twl4030_pwrbutton_exit(void) 13568d8bf04SFelipe Balbi { 13668d8bf04SFelipe Balbi platform_driver_unregister(&twl4030_pwrbutton_driver); 13768d8bf04SFelipe Balbi } 13868d8bf04SFelipe Balbi module_exit(twl4030_pwrbutton_exit); 13968d8bf04SFelipe Balbi 14068d8bf04SFelipe Balbi MODULE_ALIAS("platform:twl4030_pwrbutton"); 14168d8bf04SFelipe Balbi MODULE_DESCRIPTION("Triton2 Power Button"); 14268d8bf04SFelipe Balbi MODULE_LICENSE("GPL"); 14368d8bf04SFelipe Balbi MODULE_AUTHOR("Peter De Schrijver <peter.de-schrijver@nokia.com>"); 14468d8bf04SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); 14568d8bf04SFelipe Balbi 146