ricoh619:support pmic ricoh619
[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 //static int test_set = 0;\r
61 \r
62 #if RICOH619_ONKEY_TRIGGER_LEVEL\r
63 void ricoh619_pwrkey_timer(unsigned long t)\r
64 {\r
65         queue_work(g_pwrkey->workqueue, &g_pwrkey->work);\r
66 }\r
67 #endif\r
68 \r
69 extern int pwrkey_wakeup;\r
70 static void ricoh619_irq_work(struct work_struct * work)\r
71 {\r
72         unsigned long flags;\r
73         uint8_t val;\r
74 \r
75 //      printk("PMU: %s: \n",__func__);\r
76         //spin_lock_irqsave(&g_pwrkey->lock, flags);\r
77 \r
78         if(pwrkey_wakeup){\r
79 //              printk("PMU: %s: pwrkey_wakeup\n",__func__);\r
80                 pwrkey_wakeup = 0;\r
81                 input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 1);\r
82                 input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
83                 input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 0);\r
84                 input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
85                 \r
86                 return;\r
87         }\r
88         ricoh619_read(g_pwrkey->dev->parent, RICOH619_INT_MON_SYS, &val);\r
89         dev_dbg(g_pwrkey->dev, "pwrkey is pressed?(0x%x): 0x%x\n", RICOH619_INT_MON_SYS, val);\r
90 //      printk("PMU: %s: val=0x%x\n",__func__,val);\r
91         val &= 0x1;\r
92         if(val){\r
93                 #if (RICOH619_ONKEY_TRIGGER_LEVEL)\r
94                 g_pwrkey->timer.expires = jiffies + g_pwrkey->delay;\r
95                 dd_timer(&g_pwrkey->timer);\r
96                 #endif\r
97                 if (!g_pwrkey->pressed_first){\r
98                         g_pwrkey->pressed_first = true;\r
99 //                      printk("PMU1: %s: Power Key!!!\n",__func__);\r
100                         //input_report_key(g_pwrkey->pwr, KEY_POWER, 1);\r
101                         //input_sync(g_pwrkey->pwr);\r
102                         input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 1);\r
103                         input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
104                 }\r
105         }\r
106         else{\r
107         if (g_pwrkey->pressed_first){\r
108 //                      printk("PMU2: %s: Power Key!!!\n",__func__);\r
109                         //input_report_key(g_pwrkey->pwr, KEY_POWER, 0);\r
110                         //input_sync(g_pwrkey->pwr);\r
111                         input_event(g_pwrkey->pwr, EV_KEY, KEY_POWER, 0);\r
112                         input_event(g_pwrkey->pwr, EV_SYN, 0, 0);\r
113                 }\r
114                 g_pwrkey->pressed_first = false;\r
115         }\r
116 \r
117         //spin_unlock_irqrestore(&g_pwrkey->lock, flags);\r
118 }\r
119 extern struct ricoh619 *g_ricoh619;\r
120 static irqreturn_t pwrkey_irq(int irq, void *_pwrkey)\r
121 {\r
122 //      printk("PMU: %s: \n",__func__);\r
123         struct ricoh619 *ricoh619 = g_ricoh619;\r
124         #if (RICOH619_ONKEY_TRIGGER_LEVEL)\r
125         g_pwrkey->timer.expires = jiffies + g_pwrkey->delay;\r
126         add_timer(&g_pwrkey->timer);\r
127         #else\r
128         queue_work(g_pwrkey->workqueue, &g_pwrkey->work);\r
129         #endif\r
130         ricoh619_clr_bits(g_ricoh619->dev, RICOH619_INT_IR_SYS, 0x1); //clr power-on interrupt\r
131         return IRQ_HANDLED;\r
132 }\r
133 \r
134 #if RICOH619_ONKEY_OFF_IRQ\r
135 static irqreturn_t pwrkey_irq_off(int irq, void *_pwrkey)\r
136 {\r
137         dev_warn(g_pwrkey->dev, "ONKEY is pressed long time!\n");\r
138         return IRQ_HANDLED;\r
139 }\r
140 #endif\r
141 \r
142 static int __devinit ricoh619_pwrkey_probe(struct platform_device *pdev)\r
143 {\r
144         struct input_dev *pwr;\r
145         int key_irq;\r
146         int err;\r
147         struct ricoh619_pwrkey *pwrkey;\r
148         struct ricoh619_pwrkey_platform_data *pdata = pdev->dev.platform_data;\r
149         uint8_t val;\r
150 \r
151 //      printk("PMU: %s: \n",__func__);\r
152 \r
153         if (!pdata) {\r
154                 dev_err(&pdev->dev, "power key platform data not supplied\n");\r
155                 return -EINVAL;\r
156         }\r
157         key_irq = (pdata->irq + RICOH619_IRQ_POWER_ON);\r
158         printk(KERN_INFO "PMU1: %s: key_irq=%d\n", __func__, key_irq);\r
159         pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);\r
160         if (!pwrkey)\r
161                 return -ENOMEM;\r
162 \r
163         pwrkey->dev = &pdev->dev;\r
164         pwrkey->pdata = pdata;\r
165         pwrkey->pressed_first = false;\r
166         pwrkey->delay = HZ / 1000 * pdata->delay_ms;\r
167         g_pwrkey = pwrkey;\r
168         pwr = input_allocate_device();\r
169         if (!pwr) {\r
170                 dev_dbg(&pdev->dev, "Can't allocate power button\n");\r
171                 err = -ENOMEM;\r
172                 goto free_pwrkey;\r
173         }\r
174         input_set_capability(pwr, EV_KEY, KEY_POWER);\r
175         pwr->name = "ricoh619_pwrkey";\r
176         pwr->phys = "ricoh619_pwrkey/input0";\r
177         pwr->dev.parent = &pdev->dev;\r
178 \r
179         #if RICOH619_ONKEY_TRIGGER_LEVEL\r
180         init_timer(&pwrkey->timer);\r
181         pwrkey->timer.function = ricoh619_pwrkey_timer;\r
182         #endif\r
183 \r
184         spin_lock_init(&pwrkey->lock);\r
185         err = input_register_device(pwr);\r
186         if (err) {\r
187                 dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);\r
188                 goto free_input_dev;\r
189         }\r
190         pwrkey->key_irq = key_irq;\r
191         pwrkey->pwr = pwr;\r
192         platform_set_drvdata(pdev, pwrkey);\r
193 \r
194         // Check if power-key is pressed at boot up\r
195         err = ricoh619_read(pwrkey->dev->parent, RICOH619_INT_MON_SYS, &val);\r
196         if (err < 0) {\r
197                 dev_err(&pdev->dev, "Key-press status at boot failed rc=%d\n",\r
198                                                                          err);\r
199                 goto unreg_input_dev;\r
200         }\r
201         val &= 0x1;\r
202         if (val) {\r
203                 input_report_key(pwrkey->pwr, KEY_POWER, 1);\r
204 //              printk(KERN_INFO "******KEY_POWER:1\n");\r
205                 input_sync(pwrkey->pwr);\r
206                 pwrkey->pressed_first = true;\r
207         }\r
208 \r
209         #if !(RICOH619_ONKEY_TRIGGER_LEVEL)\r
210                 ricoh619_set_bits(pwrkey->dev->parent, RICOH619_PWR_IRSEL, 0x1); //trigger both edge\r
211         #endif\r
212 \r
213         err = request_threaded_irq(key_irq, NULL, pwrkey_irq,\r
214                 IRQF_ONESHOT, "ricoh619_pwrkey", pwrkey);\r
215         if (err < 0) {\r
216                 dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",\r
217                                                                 key_irq, err);\r
218                 goto unreg_input_dev;\r
219         }\r
220 \r
221         #if RICOH619_ONKEY_OFF_IRQ\r
222         err = request_threaded_irq(key_irq + RICOH619_IRQ_ONKEY_OFF, NULL,\r
223                                                 pwrkey_irq_off, IRQF_ONESHOT,\r
224                                                 "ricoh619_pwrkey_off", pwrkey);\r
225         if (err < 0) {\r
226                 dev_err(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",\r
227                         key_irq + RICOH619_IRQ_ONKEY_OFF, err);\r
228                 free_irq(key_irq, pwrkey);\r
229                 goto unreg_input_dev;\r
230         }\r
231         #endif\r
232 \r
233         pwrkey->workqueue = create_singlethread_workqueue("ricoh619_pwrkey");\r
234         INIT_WORK(&pwrkey->work, ricoh619_irq_work);\r
235 \r
236         /* Enable power key IRQ */\r
237         /* trigger both edge */\r
238         ricoh619_set_bits(pwrkey->dev->parent, RICOH619_PWR_IRSEL, 0x1);\r
239         /* Enable system interrupt */\r
240         ricoh619_set_bits(pwrkey->dev->parent, RICOH619_INTC_INTEN, 0x1);\r
241         /* Enable power-on interrupt */\r
242         ricoh619_set_bits(pwrkey->dev->parent, RICOH619_INT_EN_SYS, 0x1);\r
243 //      printk(KERN_INFO "PMU: %s is OK!\n", __func__);\r
244         return 0;\r
245 \r
246 unreg_input_dev:\r
247         input_unregister_device(pwr);\r
248         pwr = NULL;\r
249 \r
250 free_input_dev:\r
251         input_free_device(pwr);\r
252         free_pwrkey:\r
253         kfree(pwrkey);\r
254 \r
255         return err;\r
256 }\r
257 \r
258 static int __devexit ricoh619_pwrkey_remove(struct platform_device *pdev)\r
259 {\r
260         struct ricoh619_pwrkey *pwrkey = platform_get_drvdata(pdev);\r
261 \r
262         flush_workqueue(pwrkey->workqueue);\r
263         destroy_workqueue(pwrkey->workqueue);\r
264         free_irq(pwrkey->key_irq, pwrkey);\r
265         input_unregister_device(pwrkey->pwr);\r
266         kfree(pwrkey);\r
267 \r
268         return 0;\r
269 }\r
270 \r
271 #ifdef CONFIG_PM\r
272 static int ricoh619_pwrkey_suspend(struct device *dev)\r
273 {\r
274         struct ricoh619_pwrkey *info = dev_get_drvdata(dev);\r
275 \r
276 //      printk(KERN_INFO "PMU: %s\n", __func__);\r
277 \r
278         if (info->key_irq)\r
279                 disable_irq(info->key_irq);\r
280         cancel_work_sync(&info->work);\r
281         flush_workqueue(info->workqueue);\r
282 \r
283         return 0;\r
284 }\r
285 \r
286 static int ricoh619_pwrkey_resume(struct device *dev)\r
287 {\r
288         struct ricoh619_pwrkey *info = dev_get_drvdata(dev);\r
289 \r
290 //      printk(KERN_INFO "PMU: %s\n", __func__);\r
291         queue_work(info->workqueue, &info->work);\r
292         if (info->key_irq)\r
293                 enable_irq(info->key_irq);\r
294 \r
295         return 0;\r
296 }\r
297 \r
298 static const struct dev_pm_ops ricoh619_pwrkey_pm_ops = {\r
299         .suspend        = ricoh619_pwrkey_suspend,\r
300         .resume         = ricoh619_pwrkey_resume,\r
301 };\r
302 #endif\r
303 \r
304 static struct platform_driver ricoh619_pwrkey_driver = {\r
305         .probe = ricoh619_pwrkey_probe,\r
306         .remove = __devexit_p(ricoh619_pwrkey_remove),\r
307         .driver = {\r
308                 .name = "ricoh619-pwrkey",\r
309                 .owner = THIS_MODULE,\r
310 #ifdef CONFIG_PM\r
311                 .pm     = &ricoh619_pwrkey_pm_ops,\r
312 #endif\r
313         },\r
314 };\r
315 \r
316 static int __init ricoh619_pwrkey_init(void)\r
317 {\r
318         return platform_driver_register(&ricoh619_pwrkey_driver);\r
319 }\r
320 subsys_initcall_sync(ricoh619_pwrkey_init);\r
321 \r
322 static void __exit ricoh619_pwrkey_exit(void)\r
323 {\r
324         platform_driver_unregister(&ricoh619_pwrkey_driver);\r
325 }\r
326 module_exit(ricoh619_pwrkey_exit);\r
327 \r
328 \r
329 MODULE_ALIAS("platform:ricoh619-pwrkey");\r
330 MODULE_AUTHOR("zhangqing <zhangqing@rock-chips.com>");\r
331 MODULE_DESCRIPTION("ricoh619 Power Key");\r
332 MODULE_LICENSE("GPL v2");