video: rockchip: hdmi: support hdr function
[firefly-linux-kernel-4.4.55.git] / drivers / input / misc / twl6030-pwrbutton.c
1 /**
2  * twl6030-pwrbutton.c - TWL6030 Power Button Input Driver
3  *
4  * Copyright (C) 2011
5  *
6  * Written by Dan Murphy <DMurphy@ti.com>
7  *
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.
11  *
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.
16  *
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
20  *
21  * Derived Work from: twl4030-pwrbutton.c from
22  * Peter De Schrijver <peter.de-schrijver@nokia.com>
23  * Felipe Balbi <felipe.balbi@nokia.com>
24  *
25  */
26
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>
37
38 #define PWR_PWRON_IRQ (1 << 0)
39 #define STS_HW_CONDITIONS 0x21
40
41 struct twl6030_pwr_button {
42         struct input_dev *input_dev;
43         struct device           *dev;
44         struct mutex            irq_lock;
45         int report_key;
46 };
47
48 static inline int twl6030_readb(struct twl6030_pwr_button *twl,
49                 u8 module, u8 address)
50 {
51         u8 data = 0;
52         int ret = 0;
53
54         ret = twl_i2c_read_u8(module, &data, address);
55         if (ret >= 0)
56                 ret = data;
57         else
58                 dev_dbg(twl->dev,
59                         "TWL6030:readb[0x%x,0x%x] Error %d\n",
60                                         module, address, ret);
61
62         return ret;
63 }
64
65 static inline int twl6030_writeb(struct twl6030_pwr_button *twl, u8 module,
66                                                 u8 data, u8 address)
67 {
68         int ret = 0;
69
70         ret = twl_i2c_write_u8(module, data, address);
71         if (ret < 0)
72                 dev_dbg(twl->dev,
73                         "TWL6030:Write[0x%x] Error %d\n", address, ret);
74         return ret;
75 }
76
77 static irqreturn_t powerbutton_irq(int irq, void *_pwr)
78 {
79         struct twl6030_pwr_button *pwr = _pwr;
80         int hw_state;
81         int pwr_val;
82         static int prev_hw_state = 0xFFFF;
83         static int push_release_flag = 0 ;
84         
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);
88
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);
98
99                         msleep(20);
100                         input_report_key(pwr->input_dev, pwr->report_key, pwr_val);
101                         input_sync(pwr->input_dev);
102                 }
103                 else    {
104                         input_report_key(pwr->input_dev, pwr->report_key, pwr_val);
105                         input_sync(pwr->input_dev);
106                 }
107         } else
108                 push_release_flag = 0;
109
110         prev_hw_state = pwr_val;
111         mutex_unlock(& pwr ->irq_lock);
112
113         return IRQ_HANDLED;
114 }
115
116 static int __devinit twl6030_pwrbutton_probe(struct platform_device *pdev)
117 {
118         struct twl6030_pwr_button *pwr_button;
119         int irq = platform_get_irq(pdev, 0);
120         int err = -ENODEV;
121
122         pr_info("%s: Enter\n", __func__);
123         pwr_button = kzalloc(sizeof(struct twl6030_pwr_button), GFP_KERNEL);
124         if (!pwr_button)
125                 return -ENOMEM;
126
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");
130                 goto input_error;
131         }
132
133         __set_bit(EV_KEY, pwr_button->input_dev->evbit);
134
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;
143
144         err = request_threaded_irq(irq, NULL, powerbutton_irq,
145                         IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
146                         "twl6030_pwrbutton", pwr_button);
147         if (err < 0) {
148                 dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
149                 goto free_input_dev;
150         }
151
152         err = input_register_device(pwr_button->input_dev);
153         if (err) {
154                 dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
155                 goto free_irq;
156         }
157         mutex_init(&pwr_button->irq_lock);
158
159         twl6030_interrupt_unmask(0x01, REG_INT_MSK_LINE_A);
160         twl6030_interrupt_unmask(0x01, REG_INT_MSK_STS_A);
161
162         platform_set_drvdata(pdev, pwr_button);
163
164         return 0;
165
166 free_irq:
167         free_irq(irq, NULL);
168 free_input_dev:
169         input_free_device(pwr_button->input_dev);
170 input_error:
171         kfree(pwr_button);
172         return err;
173 }
174
175 static int __devexit twl6030_pwrbutton_remove(struct platform_device *pdev)
176 {
177         struct input_dev *pwr = platform_get_drvdata(pdev);
178         int irq = platform_get_irq(pdev, 0);
179
180         free_irq(irq, pwr);
181         input_unregister_device(pwr);
182
183         return 0;
184 }
185
186 struct platform_driver twl6030_pwrbutton_driver = {
187         .probe          = twl6030_pwrbutton_probe,
188         .remove         = __devexit_p(twl6030_pwrbutton_remove),
189         .driver         = {
190                 .name   = "twl6030_pwrbutton",
191                 .owner  = THIS_MODULE,
192         },
193 };
194
195 static int __init twl6030_pwrbutton_init(void)
196 {
197         return platform_driver_register(&twl6030_pwrbutton_driver);
198 }
199 module_init(twl6030_pwrbutton_init);
200
201 static void __exit twl6030_pwrbutton_exit(void)
202 {
203         platform_driver_unregister(&twl6030_pwrbutton_driver);
204 }
205 module_exit(twl6030_pwrbutton_exit);
206
207 MODULE_ALIAS("platform:twl6030_pwrbutton");
208 MODULE_DESCRIPTION("Triton2 Power Button");
209 MODULE_LICENSE("GPL");
210 MODULE_AUTHOR("Dan Murphy <DMurphy@ti.com>");