2 * twl6030-pwrbutton.c - TWL6030 Power Button Input Driver
6 * Written by Dan Murphy <DMurphy@ti.com>
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file "COPYING" in the main directory of this
10 * archive for more details.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Derived Work from: twl4030-pwrbutton.c from
22 * Peter De Schrijver <peter.de-schrijver@nokia.com>
23 * Felipe Balbi <felipe.balbi@nokia.com>
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/kernel.h>
30 #include <linux/errno.h>
31 #include <linux/input.h>
32 #include <linux/interrupt.h>
33 #include <linux/platform_device.h>
34 #include <linux/slab.h>
35 #include <linux/i2c/twl.h>
36 #include <linux/delay.h>
38 #define PWR_PWRON_IRQ (1 << 0)
39 #define STS_HW_CONDITIONS 0x21
41 struct twl6030_pwr_button {
42 struct input_dev *input_dev;
44 struct mutex irq_lock;
48 static inline int twl6030_readb(struct twl6030_pwr_button *twl,
49 u8 module, u8 address)
54 ret = twl_i2c_read_u8(module, &data, address);
59 "TWL6030:readb[0x%x,0x%x] Error %d\n",
60 module, address, ret);
65 static inline int twl6030_writeb(struct twl6030_pwr_button *twl, u8 module,
70 ret = twl_i2c_write_u8(module, data, address);
73 "TWL6030:Write[0x%x] Error %d\n", address, ret);
77 static irqreturn_t powerbutton_irq(int irq, void *_pwr)
79 struct twl6030_pwr_button *pwr = _pwr;
82 static int prev_hw_state = 0xFFFF;
83 static int push_release_flag = 0 ;
85 mutex_lock(& pwr ->irq_lock);
86 hw_state = twl6030_readb(pwr, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
87 pwr_val = !(hw_state & PWR_PWRON_IRQ);
89 if ((prev_hw_state != pwr_val) && (prev_hw_state != 0xFFFF)) {
90 push_release_flag = 0;
91 input_report_key(pwr->input_dev, pwr->report_key, pwr_val);
92 input_sync(pwr->input_dev);
93 } else if (!push_release_flag) {
94 push_release_flag = 1;
95 if(prev_hw_state != 0xFFFF){
96 input_report_key(pwr->input_dev, pwr->report_key, !pwr_val);
97 input_sync(pwr->input_dev);
100 input_report_key(pwr->input_dev, pwr->report_key, pwr_val);
101 input_sync(pwr->input_dev);
104 input_report_key(pwr->input_dev, pwr->report_key, pwr_val);
105 input_sync(pwr->input_dev);
108 push_release_flag = 0;
110 prev_hw_state = pwr_val;
111 mutex_unlock(& pwr ->irq_lock);
116 static int __devinit twl6030_pwrbutton_probe(struct platform_device *pdev)
118 struct twl6030_pwr_button *pwr_button;
119 int irq = platform_get_irq(pdev, 0);
122 pr_info("%s: Enter\n", __func__);
123 pwr_button = kzalloc(sizeof(struct twl6030_pwr_button), GFP_KERNEL);
127 pwr_button->input_dev = input_allocate_device();
128 if (!pwr_button->input_dev) {
129 dev_dbg(&pdev->dev, "Can't allocate power button\n");
133 __set_bit(EV_KEY, pwr_button->input_dev->evbit);
135 pwr_button->report_key = KEY_POWER;
136 pwr_button->dev = &pdev->dev;
137 pwr_button->input_dev->evbit[0] = BIT_MASK(EV_KEY);
138 pwr_button->input_dev->keybit[BIT_WORD(pwr_button->report_key)] =
139 BIT_MASK(pwr_button->report_key);
140 pwr_button->input_dev->name = "twl6030_pwrbutton";
141 pwr_button->input_dev->phys = "twl6030_pwrbutton/input0";
142 pwr_button->input_dev->dev.parent = &pdev->dev;
144 err = request_threaded_irq(irq, NULL, powerbutton_irq,
145 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
146 "twl6030_pwrbutton", pwr_button);
148 dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
152 err = input_register_device(pwr_button->input_dev);
154 dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
157 mutex_init(&pwr_button->irq_lock);
159 twl6030_interrupt_unmask(0x01, REG_INT_MSK_LINE_A);
160 twl6030_interrupt_unmask(0x01, REG_INT_MSK_STS_A);
162 platform_set_drvdata(pdev, pwr_button);
169 input_free_device(pwr_button->input_dev);
175 static int __devexit twl6030_pwrbutton_remove(struct platform_device *pdev)
177 struct input_dev *pwr = platform_get_drvdata(pdev);
178 int irq = platform_get_irq(pdev, 0);
181 input_unregister_device(pwr);
186 struct platform_driver twl6030_pwrbutton_driver = {
187 .probe = twl6030_pwrbutton_probe,
188 .remove = __devexit_p(twl6030_pwrbutton_remove),
190 .name = "twl6030_pwrbutton",
191 .owner = THIS_MODULE,
195 static int __init twl6030_pwrbutton_init(void)
197 return platform_driver_register(&twl6030_pwrbutton_driver);
199 module_init(twl6030_pwrbutton_init);
201 static void __exit twl6030_pwrbutton_exit(void)
203 platform_driver_unregister(&twl6030_pwrbutton_driver);
205 module_exit(twl6030_pwrbutton_exit);
207 MODULE_ALIAS("platform:twl6030_pwrbutton");
208 MODULE_DESCRIPTION("Triton2 Power Button");
209 MODULE_LICENSE("GPL");
210 MODULE_AUTHOR("Dan Murphy <DMurphy@ti.com>");