Merge tag 'v3.10.23' into develop-3.10
[firefly-linux-kernel-4.4.55.git] / drivers / input / misc / ricoh619-pwrkey.c
1 /*\r
2 * driver/input/misc/ricoh619-pwrkey.c\r
3 *\r
4 * Power Key driver for RICOH RC5T619 power management chip.\r
5 *\r
6 * Copyright (C) 2012-2013 RICOH COMPANY,LTD\r
7 *\r
8 *\r
9 * This program is free software; you can redistribute it and/or modify\r
10 * it under the terms of the GNU General Public License as published by\r
11 * the Free Software Foundation; either version 2 of the License, or\r
12 * (at your option) any later version.\r
13 *\r
14 * This program is distributed in the hope that it will be useful, but WITHOUT\r
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
17 * more details.\r
18 *\r
19 * You should have received a copy of the GNU General Public License\r
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
21 *\r
22 */\r
23 #include <linux/module.h>\r
24 #include <linux/init.h>\r
25 #include <linux/kernel.h>\r
26 #include <linux/errno.h>\r
27 #include <linux/input.h>\r
28 #include <linux/interrupt.h>\r
29 #include <linux/platform_device.h>\r
30 #include <linux/mfd/ricoh619.h>\r
31 #include <linux/spinlock.h>\r
32 #include <linux/timer.h>\r
33 #include <linux/pm.h>\r
34 #include <linux/slab.h>\r
35 #include <linux/pm_runtime.h>\r
36 #include <linux/workqueue.h>\r
37 #include <linux/gpio.h>\r
38 \r
39 #include <linux/mfd/ricoh619.h>\r
40 \r
41 #define RICOH619_ONKEY_TRIGGER_LEVEL    0\r
42 #define RICOH619_ONKEY_OFF_IRQ          0\r
43 \r
44 struct ricoh619_pwrkey {\r
45         struct device *dev;\r
46         struct input_dev *pwr;\r
47         #if RICOH619_ONKEY_TRIGGER_LEVEL\r
48                 struct timer_list timer;\r
49         #endif\r
50         struct workqueue_struct *workqueue;\r
51         struct work_struct work;\r
52         unsigned long delay;\r
53         int key_irq;\r
54         bool pressed_first;\r
55         struct ricoh619_pwrkey_platform_data *pdata;\r
56         spinlock_t lock;\r
57 };\r
58 \r
59 struct ricoh619_pwrkey *g_pwrkey;\r
60 \r
61 #if RICOH619_ONKEY_TRIGGER_LEVEL\r
62 void ricoh619_pwrkey_timer(unsigned long t)\r
63 {\r
64         queue_work(g_pwrkey->workqueue, &g_pwrkey->work);\r
65 }\r
66 #endif\r
67 \r
68 static void ricoh619_irq_work(struct work_struct *work)\r
69 {\r
70         /* unsigned long flags; */\r
71         uint8_t val;\r
72 \r
73 //      printk("PMU: %s: \n",__func__);\r
74         //spin_lock_irqsave(&g_pwrkey->lock, flags);\r
75 \r
76         if(pwrkey_wakeup){\r
77 //              printk("PMU: %s: pwrkey_wakeup\n",__func__);\r
78                 pwrkey_wakeup = 0;\r
79                 input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 1);\r
80                 input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
81                 input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 0);\r
82                 input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
83                 \r
84                 return;\r
85         }\r
86         ricoh619_read(g_pwrkey->dev->parent, RICOH619_INT_MON_SYS, &val);\r
87         dev_dbg(g_pwrkey->dev, "pwrkey is pressed?(0x%x): 0x%x\n",\r
88                                                 RICOH619_INT_MON_SYS, val);\r
89 //      printk(KERN_INFO "PMU: %s: val=0x%x\n", __func__, val);\r
90         val &= 0x1;\r
91         if(val){\r
92                 #if (RICOH619_ONKEY_TRIGGER_LEVEL)\r
93                 g_pwrkey->timer.expires = jiffies + g_pwrkey->delay;\r
94                 dd_timer(&g_pwrkey->timer);\r
95                 #endif\r
96                 if (!g_pwrkey->pressed_first){\r
97                         g_pwrkey->pressed_first = true;\r
98 //                      printk("PMU1: %s: Power Key!!!\n",__func__);\r
99                         //input_report_key(g_pwrkey->pwr, KEY_POWER, 1);\r
100                         //input_sync(g_pwrkey->pwr);\r
101                         input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 1);\r
102                         input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
103                 }\r
104         } else {\r
105                 if (g_pwrkey->pressed_first) {\r
106 //                      printk(KERN_INFO "PMU2: %s: Power Key!!!\n", __func__);\r
107                         /* input_report_key(g_pwrkey->pwr, KEY_POWER, 0); */\r
108                         /* input_sync(g_pwrkey->pwr); */\r
109                         input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 0);\r
110                         input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
111                 }\r
112                 g_pwrkey->pressed_first = false;\r
113         }\r
114 \r
115         /* spin_unlock_irqrestore(&g_pwrkey->lock, flags); */\r
116 }\r
117 \r
118 static irqreturn_t pwrkey_irq(int irq, void *_pwrkey)\r
119 {\r
120 //      printk(KERN_INFO "PMU: %s:\n", __func__);\r
121 \r
122         #if (RICOH619_ONKEY_TRIGGER_LEVEL)\r
123         g_pwrkey->timer.expires = jiffies + g_pwrkey->delay;\r
124         add_timer(&g_pwrkey->timer);\r
125         #else\r
126         queue_work(g_pwrkey->workqueue, &g_pwrkey->work);\r
127         #endif\r
128         return IRQ_HANDLED;\r
129 }\r
130 \r
131 #if RICOH619_ONKEY_OFF_IRQ\r
132 static irqreturn_t pwrkey_irq_off(int irq, void *_pwrkey)\r
133 {\r
134         dev_warn(g_pwrkey->dev, "ONKEY is pressed long time!\n");\r
135         return IRQ_HANDLED;\r
136 }\r
137 #endif\r
138 \r
139 static int __devinit ricoh619_pwrkey_probe(struct platform_device *pdev)\r
140 {\r
141         struct input_dev *pwr;\r
142         int key_irq;\r
143         int err;\r
144         struct ricoh619_pwrkey *pwrkey;\r
145         struct ricoh619_pwrkey_platform_data *pdata = pdev->dev.platform_data;\r
146         uint8_t val;\r
147 \r
148 //      printk("PMU: %s: \n",__func__);\r
149 \r
150         if (!pdata) {\r
151                 dev_err(&pdev->dev, "power key platform data not supplied\n");\r
152                 return -EINVAL;\r
153         }\r
154         key_irq = (pdata->irq + RICOH619_IRQ_POWER_ON);\r
155         printk(KERN_INFO "PMU1: %s: key_irq=%d\n", __func__, key_irq);\r
156         pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);\r
157         if (!pwrkey)\r
158                 return -ENOMEM;\r
159 \r
160         pwrkey->dev = &pdev->dev;\r
161         pwrkey->pdata = pdata;\r
162         pwrkey->pressed_first = false;\r
163         pwrkey->delay = HZ / 1000 * pdata->delay_ms;\r
164         g_pwrkey = pwrkey;\r
165         pwr = input_allocate_device();\r
166         if (!pwr) {\r
167                 dev_dbg(&pdev->dev, "Can't allocate power button\n");\r
168                 err = -ENOMEM;\r
169                 goto free_pwrkey;\r
170         }\r
171         input_set_capability(pwr, EV_KEY, KEY_POWER);\r
172         pwr->name = "ricoh619_pwrkey";\r
173         pwr->phys = "ricoh619_pwrkey/input0";\r
174         pwr->dev.parent = &pdev->dev;\r
175 \r
176         #if RICOH619_ONKEY_TRIGGER_LEVEL\r
177         init_timer(&pwrkey->timer);\r
178         pwrkey->timer.function = ricoh619_pwrkey_timer;\r
179         #endif\r
180 \r
181         spin_lock_init(&pwrkey->lock);\r
182         err = input_register_device(pwr);\r
183         if (err) {\r
184                 dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);\r
185                 goto free_input_dev;\r
186         }\r
187         pwrkey->key_irq = key_irq;\r
188         pwrkey->pwr = pwr;\r
189         platform_set_drvdata(pdev, pwrkey);\r
190 \r
191         /* Check if power-key is pressed at boot up */\r
192         err = ricoh619_read(pwrkey->dev->parent, RICOH619_INT_MON_SYS, &val);\r
193         if (err < 0) {\r
194                 dev_err(&pdev->dev, "Key-press status at boot failed rc=%d\n",\r
195                                                                          err);\r
196                 goto unreg_input_dev;\r
197         }\r
198         val &= 0x1;\r
199         if (val) {\r
200                 input_report_key(pwrkey->pwr, KEY_POWER, 1);\r
201 //              printk(KERN_INFO "******KEY_POWER:1\n");\r
202                 input_sync(pwrkey->pwr);\r
203                 pwrkey->pressed_first = true;\r
204         }\r
205 \r
206         #if !(RICOH619_ONKEY_TRIGGER_LEVEL)\r
207                 /* trigger both edge */\r
208                 ricoh619_set_bits(pwrkey->dev->parent, RICOH619_PWR_IRSEL, 0x1);\r
209         #endif\r
210 \r
211         err = request_threaded_irq(key_irq, NULL, pwrkey_irq,\r
212                 IRQF_ONESHOT, "ricoh619_pwrkey", pwrkey);\r
213         if (err < 0) {\r
214                 dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",\r
215                                                                 key_irq, err);\r
216                 goto unreg_input_dev;\r
217         }\r
218 \r
219         #if RICOH619_ONKEY_OFF_IRQ\r
220         err = request_threaded_irq(key_irq + RICOH619_IRQ_ONKEY_OFF, NULL,\r
221                                                 pwrkey_irq_off, IRQF_ONESHOT,\r
222                                                 "ricoh619_pwrkey_off", pwrkey);\r
223         if (err < 0) {\r
224                 dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",\r
225                         key_irq + RICOH619_IRQ_ONKEY_OFF, err);\r
226                 free_irq(key_irq, pwrkey);\r
227                 goto unreg_input_dev;\r
228         }\r
229         #endif\r
230 \r
231         pwrkey->workqueue = create_singlethread_workqueue("ricoh619_pwrkey");\r
232         INIT_WORK(&pwrkey->work, ricoh619_irq_work);\r
233 \r
234         /* Enable power key IRQ */\r
235         /* trigger both edge */\r
236         ricoh619_set_bits(pwrkey->dev->parent, RICOH619_PWR_IRSEL, 0x1);\r
237         /* Enable system interrupt */\r
238         ricoh619_set_bits(pwrkey->dev->parent, RICOH619_INTC_INTEN, 0x1);\r
239         /* Enable power-on interrupt */\r
240         ricoh619_set_bits(pwrkey->dev->parent, RICOH619_INT_EN_SYS, 0x1);\r
241 //      printk(KERN_INFO "PMU: %s is OK!\n", __func__);\r
242         return 0;\r
243 \r
244 unreg_input_dev:\r
245         input_unregister_device(pwr);\r
246         pwr = NULL;\r
247 \r
248 free_input_dev:\r
249         input_free_device(pwr);\r
250         free_pwrkey:\r
251         kfree(pwrkey);\r
252 \r
253         return err;\r
254 }\r
255 \r
256 static int __devexit ricoh619_pwrkey_remove(struct platform_device *pdev)\r
257 {\r
258         struct ricoh619_pwrkey *pwrkey = platform_get_drvdata(pdev);\r
259 \r
260         flush_workqueue(pwrkey->workqueue);\r
261         destroy_workqueue(pwrkey->workqueue);\r
262         free_irq(pwrkey->key_irq, pwrkey);\r
263         input_unregister_device(pwrkey->pwr);\r
264         kfree(pwrkey);\r
265 \r
266         return 0;\r
267 }\r
268 \r
269 #ifdef CONFIG_PM\r
270 static int ricoh619_pwrkey_suspend(struct device *dev)\r
271 {\r
272         struct ricoh619_pwrkey *info = dev_get_drvdata(dev);\r
273 \r
274 //      printk(KERN_INFO "PMU: %s\n", __func__);\r
275 \r
276         if (info->key_irq)\r
277                 disable_irq(info->key_irq);\r
278         cancel_work_sync(&info->work);\r
279         flush_workqueue(info->workqueue);\r
280 \r
281         return 0;\r
282 }\r
283 \r
284 static int ricoh619_pwrkey_resume(struct device *dev)\r
285 {\r
286         struct ricoh619_pwrkey *info = dev_get_drvdata(dev);\r
287 \r
288 //      printk(KERN_INFO "PMU: %s\n", __func__);\r
289         queue_work(info->workqueue, &info->work);\r
290         if (info->key_irq)\r
291                 enable_irq(info->key_irq);\r
292 \r
293         return 0;\r
294 }\r
295 \r
296 static const struct dev_pm_ops ricoh619_pwrkey_pm_ops = {\r
297         .suspend        = ricoh619_pwrkey_suspend,\r
298         .resume         = ricoh619_pwrkey_resume,\r
299 };\r
300 #endif\r
301 \r
302 static struct platform_driver ricoh619_pwrkey_driver = {\r
303         .probe = ricoh619_pwrkey_probe,\r
304         .remove = __devexit_p(ricoh619_pwrkey_remove),\r
305         .driver = {\r
306                 .name = "ricoh619-pwrkey",\r
307                 .owner = THIS_MODULE,\r
308 #ifdef CONFIG_PM\r
309                 .pm     = &ricoh619_pwrkey_pm_ops,\r
310 #endif\r
311         },\r
312 };\r
313 \r
314 static int __init ricoh619_pwrkey_init(void)\r
315 {\r
316         return platform_driver_register(&ricoh619_pwrkey_driver);\r
317 }\r
318 subsys_initcall_sync(ricoh619_pwrkey_init);\r
319 \r
320 static void __exit ricoh619_pwrkey_exit(void)\r
321 {\r
322         platform_driver_unregister(&ricoh619_pwrkey_driver);\r
323 }\r
324 module_exit(ricoh619_pwrkey_exit);\r
325 \r
326 \r
327 MODULE_ALIAS("platform:ricoh619-pwrkey");\r
328 MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");\r
329 MODULE_DESCRIPTION("ricoh619 Power Key");\r
330 MODULE_LICENSE("GPL v2");