1 /** 2 * twl4030-pwrbutton.c - TWL4030 Power Button Input Driver 3 * 4 * Copyright (C) 2008-2009 Nokia Corporation 5 * 6 * Written by Peter De Schrijver <peter.de-schrijver@nokia.com> 7 * Several fixes by Felipe Balbi <felipe.balbi@nokia.com> 8 * 9 * This file is subject to the terms and conditions of the GNU General 10 * Public License. See the file "COPYING" in the main directory of this 11 * archive for more details. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23 #include <linux/module.h> 24 #include <linux/init.h> 25 #include <linux/kernel.h> 26 #include <linux/errno.h> 27 #include <linux/input.h> 28 #include <linux/interrupt.h> 29 #include <linux/platform_device.h> 30 #include <linux/i2c/twl4030.h> 31 32 #define PWR_PWRON_IRQ (1 << 0) 33 34 #define STS_HW_CONDITIONS 0xf 35 36 static irqreturn_t powerbutton_irq(int irq, void *_pwr) 37 { 38 struct input_dev *pwr = _pwr; 39 int err; 40 u8 value; 41 42 #ifdef CONFIG_LOCKDEP 43 /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which 44 * we don't want and can't tolerate since this is a threaded 45 * IRQ and can sleep due to the i2c reads it has to issue. 46 * Although it might be friendlier not to borrow this thread 47 * context... 48 */ 49 local_irq_enable(); 50 #endif 51 52 err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, 53 STS_HW_CONDITIONS); 54 if (!err) { 55 input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); 56 input_sync(pwr); 57 } else { 58 dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading" 59 " TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err); 60 } 61 62 return IRQ_HANDLED; 63 } 64 65 static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev) 66 { 67 struct input_dev *pwr; 68 int irq = platform_get_irq(pdev, 0); 69 int err; 70 71 pwr = input_allocate_device(); 72 if (!pwr) { 73 dev_dbg(&pdev->dev, "Can't allocate power button\n"); 74 return -ENOMEM; 75 } 76 77 pwr->evbit[0] = BIT_MASK(EV_KEY); 78 pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); 79 pwr->name = "twl4030_pwrbutton"; 80 pwr->phys = "twl4030_pwrbutton/input0"; 81 pwr->dev.parent = &pdev->dev; 82 83 err = request_irq(irq, powerbutton_irq, 84 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 85 "twl4030_pwrbutton", pwr); 86 if (err < 0) { 87 dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); 88 goto free_input_dev; 89 } 90 91 err = input_register_device(pwr); 92 if (err) { 93 dev_dbg(&pdev->dev, "Can't register power button: %d\n", err); 94 goto free_irq; 95 } 96 97 platform_set_drvdata(pdev, pwr); 98 99 return 0; 100 101 free_irq: 102 free_irq(irq, NULL); 103 free_input_dev: 104 input_free_device(pwr); 105 return err; 106 } 107 108 static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev) 109 { 110 struct input_dev *pwr = platform_get_drvdata(pdev); 111 int irq = platform_get_irq(pdev, 0); 112 113 free_irq(irq, pwr); 114 input_unregister_device(pwr); 115 116 return 0; 117 } 118 119 struct platform_driver twl4030_pwrbutton_driver = { 120 .probe = twl4030_pwrbutton_probe, 121 .remove = __devexit_p(twl4030_pwrbutton_remove), 122 .driver = { 123 .name = "twl4030_pwrbutton", 124 .owner = THIS_MODULE, 125 }, 126 }; 127 128 static int __init twl4030_pwrbutton_init(void) 129 { 130 return platform_driver_register(&twl4030_pwrbutton_driver); 131 } 132 module_init(twl4030_pwrbutton_init); 133 134 static void __exit twl4030_pwrbutton_exit(void) 135 { 136 platform_driver_unregister(&twl4030_pwrbutton_driver); 137 } 138 module_exit(twl4030_pwrbutton_exit); 139 140 MODULE_ALIAS("platform:twl4030_pwrbutton"); 141 MODULE_DESCRIPTION("Triton2 Power Button"); 142 MODULE_LICENSE("GPL"); 143 MODULE_AUTHOR("Peter De Schrijver <peter.de-schrijver@nokia.com>"); 144 MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); 145 146