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 42*f3219817SPeter Ujfalusi err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &value, STS_HW_CONDITIONS); 4368d8bf04SFelipe Balbi if (!err) { 44112b51cfSNeilBrown pm_wakeup_event(pwr->dev.parent, 0); 4568d8bf04SFelipe Balbi input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); 4668d8bf04SFelipe Balbi input_sync(pwr); 4768d8bf04SFelipe Balbi } else { 4868d8bf04SFelipe Balbi dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading" 4968d8bf04SFelipe Balbi " TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err); 5068d8bf04SFelipe Balbi } 5168d8bf04SFelipe Balbi 5268d8bf04SFelipe Balbi return IRQ_HANDLED; 5368d8bf04SFelipe Balbi } 5468d8bf04SFelipe Balbi 55dda7b73cSMarkus Lehtonen static int __init twl4030_pwrbutton_probe(struct platform_device *pdev) 5668d8bf04SFelipe Balbi { 5768d8bf04SFelipe Balbi struct input_dev *pwr; 5868d8bf04SFelipe Balbi int irq = platform_get_irq(pdev, 0); 5968d8bf04SFelipe Balbi int err; 6068d8bf04SFelipe Balbi 6168d8bf04SFelipe Balbi pwr = input_allocate_device(); 6268d8bf04SFelipe Balbi if (!pwr) { 6368d8bf04SFelipe Balbi dev_dbg(&pdev->dev, "Can't allocate power button\n"); 6468d8bf04SFelipe Balbi return -ENOMEM; 6568d8bf04SFelipe Balbi } 6668d8bf04SFelipe Balbi 6768d8bf04SFelipe Balbi pwr->evbit[0] = BIT_MASK(EV_KEY); 6868d8bf04SFelipe Balbi pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); 6968d8bf04SFelipe Balbi pwr->name = "twl4030_pwrbutton"; 7068d8bf04SFelipe Balbi pwr->phys = "twl4030_pwrbutton/input0"; 7168d8bf04SFelipe Balbi pwr->dev.parent = &pdev->dev; 7268d8bf04SFelipe Balbi 7370f94413SFelipe Balbi err = request_threaded_irq(irq, NULL, powerbutton_irq, 7468d8bf04SFelipe Balbi IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 7568d8bf04SFelipe Balbi "twl4030_pwrbutton", pwr); 7668d8bf04SFelipe Balbi if (err < 0) { 7768d8bf04SFelipe Balbi dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); 7868d8bf04SFelipe Balbi goto free_input_dev; 7968d8bf04SFelipe Balbi } 8068d8bf04SFelipe Balbi 8168d8bf04SFelipe Balbi err = input_register_device(pwr); 8268d8bf04SFelipe Balbi if (err) { 8368d8bf04SFelipe Balbi dev_dbg(&pdev->dev, "Can't register power button: %d\n", err); 8468d8bf04SFelipe Balbi goto free_irq; 8568d8bf04SFelipe Balbi } 8668d8bf04SFelipe Balbi 8768d8bf04SFelipe Balbi platform_set_drvdata(pdev, pwr); 8868d8bf04SFelipe Balbi 8968d8bf04SFelipe Balbi return 0; 9068d8bf04SFelipe Balbi 9168d8bf04SFelipe Balbi free_irq: 925c9db648SAxel Lin free_irq(irq, pwr); 9368d8bf04SFelipe Balbi free_input_dev: 9468d8bf04SFelipe Balbi input_free_device(pwr); 9568d8bf04SFelipe Balbi return err; 9668d8bf04SFelipe Balbi } 9768d8bf04SFelipe Balbi 98dda7b73cSMarkus Lehtonen static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev) 9968d8bf04SFelipe Balbi { 10068d8bf04SFelipe Balbi struct input_dev *pwr = platform_get_drvdata(pdev); 10168d8bf04SFelipe Balbi int irq = platform_get_irq(pdev, 0); 10268d8bf04SFelipe Balbi 10368d8bf04SFelipe Balbi free_irq(irq, pwr); 10468d8bf04SFelipe Balbi input_unregister_device(pwr); 10568d8bf04SFelipe Balbi 10668d8bf04SFelipe Balbi return 0; 10768d8bf04SFelipe Balbi } 10868d8bf04SFelipe Balbi 109dda7b73cSMarkus Lehtonen static struct platform_driver twl4030_pwrbutton_driver = { 110dda7b73cSMarkus Lehtonen .remove = __exit_p(twl4030_pwrbutton_remove), 11168d8bf04SFelipe Balbi .driver = { 11268d8bf04SFelipe Balbi .name = "twl4030_pwrbutton", 11368d8bf04SFelipe Balbi .owner = THIS_MODULE, 11468d8bf04SFelipe Balbi }, 11568d8bf04SFelipe Balbi }; 116d3d25808SDmitry Torokhov 117d3d25808SDmitry Torokhov static int __init twl4030_pwrbutton_init(void) 118d3d25808SDmitry Torokhov { 119d3d25808SDmitry Torokhov return platform_driver_probe(&twl4030_pwrbutton_driver, 120d3d25808SDmitry Torokhov twl4030_pwrbutton_probe); 121d3d25808SDmitry Torokhov } 122d3d25808SDmitry Torokhov module_init(twl4030_pwrbutton_init); 123d3d25808SDmitry Torokhov 124d3d25808SDmitry Torokhov static void __exit twl4030_pwrbutton_exit(void) 125d3d25808SDmitry Torokhov { 126d3d25808SDmitry Torokhov platform_driver_unregister(&twl4030_pwrbutton_driver); 127d3d25808SDmitry Torokhov } 128d3d25808SDmitry Torokhov module_exit(twl4030_pwrbutton_exit); 12968d8bf04SFelipe Balbi 13068d8bf04SFelipe Balbi MODULE_ALIAS("platform:twl4030_pwrbutton"); 13168d8bf04SFelipe Balbi MODULE_DESCRIPTION("Triton2 Power Button"); 13268d8bf04SFelipe Balbi MODULE_LICENSE("GPL"); 13368d8bf04SFelipe Balbi MODULE_AUTHOR("Peter De Schrijver <peter.de-schrijver@nokia.com>"); 13468d8bf04SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); 13568d8bf04SFelipe Balbi 136