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 42f3219817SPeter 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 55c81e5926SSebastian Reichel static int 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 617f9ce649SSebastian Reichel pwr = devm_input_allocate_device(&pdev->dev); 6268d8bf04SFelipe Balbi if (!pwr) { 630330f93aSSebastian Reichel dev_err(&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 737f9ce649SSebastian Reichel err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq, 7468d8bf04SFelipe Balbi IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 7568d8bf04SFelipe Balbi "twl4030_pwrbutton", pwr); 7668d8bf04SFelipe Balbi if (err < 0) { 770330f93aSSebastian Reichel dev_err(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); 787f9ce649SSebastian Reichel return err; 7968d8bf04SFelipe Balbi } 8068d8bf04SFelipe Balbi 8168d8bf04SFelipe Balbi err = input_register_device(pwr); 8268d8bf04SFelipe Balbi if (err) { 830330f93aSSebastian Reichel dev_err(&pdev->dev, "Can't register power button: %d\n", err); 8468d8bf04SFelipe Balbi return err; 8568d8bf04SFelipe Balbi } 8668d8bf04SFelipe Balbi 877f9ce649SSebastian Reichel platform_set_drvdata(pdev, pwr); 88*c42bfd7fSNeilBrown device_init_wakeup(&pdev->dev, true); 8968d8bf04SFelipe Balbi 9068d8bf04SFelipe Balbi return 0; 9168d8bf04SFelipe Balbi } 9268d8bf04SFelipe Balbi 93c81e5926SSebastian Reichel #ifdef CONFIG_OF 94c81e5926SSebastian Reichel static const struct of_device_id twl4030_pwrbutton_dt_match_table[] = { 95c81e5926SSebastian Reichel { .compatible = "ti,twl4030-pwrbutton" }, 96c81e5926SSebastian Reichel {}, 97c81e5926SSebastian Reichel }; 98c81e5926SSebastian Reichel MODULE_DEVICE_TABLE(of, twl4030_pwrbutton_dt_match_table); 99c81e5926SSebastian Reichel #endif 100c81e5926SSebastian Reichel 101dda7b73cSMarkus Lehtonen static struct platform_driver twl4030_pwrbutton_driver = { 102c81e5926SSebastian Reichel .probe = twl4030_pwrbutton_probe, 10368d8bf04SFelipe Balbi .driver = { 10468d8bf04SFelipe Balbi .name = "twl4030_pwrbutton", 10568d8bf04SFelipe Balbi .owner = THIS_MODULE, 106c81e5926SSebastian Reichel .of_match_table = of_match_ptr(twl4030_pwrbutton_dt_match_table), 10768d8bf04SFelipe Balbi }, 10868d8bf04SFelipe Balbi }; 109c81e5926SSebastian Reichel module_platform_driver(twl4030_pwrbutton_driver); 11068d8bf04SFelipe Balbi 11168d8bf04SFelipe Balbi MODULE_ALIAS("platform:twl4030_pwrbutton"); 11268d8bf04SFelipe Balbi MODULE_DESCRIPTION("Triton2 Power Button"); 11368d8bf04SFelipe Balbi MODULE_LICENSE("GPL"); 11468d8bf04SFelipe Balbi MODULE_AUTHOR("Peter De Schrijver <peter.de-schrijver@nokia.com>"); 11568d8bf04SFelipe Balbi MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); 11668d8bf04SFelipe Balbi 117