rk fb: if lcdc is suspend ignore set par and display
[firefly-linux-kernel-4.4.55.git] / drivers / watchdog / rk29_wdt.c
1 /* linux/drivers/watchdog/rk29_wdt.c
2  *
3  * Copyright (C) 2011 ROCKCHIP, Inc.
4  *      hhb@rock-chips.com
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21
22 #include <linux/module.h>
23 #include <linux/moduleparam.h>
24 #include <linux/types.h>
25 #include <linux/timer.h>
26 #include <linux/miscdevice.h>
27 #include <linux/watchdog.h>
28 #include <linux/fs.h>
29 #include <linux/init.h>
30 #include <linux/platform_device.h>
31 #include <linux/interrupt.h>
32 #include <linux/clk.h>
33 #include <linux/uaccess.h>
34 #include <linux/io.h>
35 #include <asm/mach/map.h>
36 #ifdef CONFIG_OF
37 #include <linux/of.h>
38 #endif
39
40
41 /* RK29 registers define */
42 #define RK29_WDT_CR     0X00
43 #define RK29_WDT_TORR   0X04
44 #define RK29_WDT_CCVR   0X08
45 #define RK29_WDT_CRR    0X0C
46 #define RK29_WDT_STAT   0X10
47 #define RK29_WDT_EOI    0X14
48
49 #define RK29_WDT_EN     1
50 #define RK29_RESPONSE_MODE      1
51 #define RK29_RESET_PULSE    4
52
53 //THAT wdt's clock is 24MHZ
54 #define RK29_WDT_2730US         0
55 #define RK29_WDT_5460US         1
56 #define RK29_WDT_10920US        2
57 #define RK29_WDT_21840US        3
58 #define RK29_WDT_43680US        4
59 #define RK29_WDT_87360US        5
60 #define RK29_WDT_174720US       6
61 #define RK29_WDT_349440US       7
62 #define RK29_WDT_698880US       8
63 #define RK29_WDT_1397760US      9
64 #define RK29_WDT_2795520US      10
65 #define RK29_WDT_5591040US      11
66 #define RK29_WDT_11182080US     12
67 #define RK29_WDT_22364160US     13
68 #define RK29_WDT_44728320US     14
69 #define RK29_WDT_89456640US     15
70
71 /*
72 #define CONFIG_RK29_WATCHDOG_ATBOOT             (1)
73 #define CONFIG_RK29_WATCHDOG_DEFAULT_TIME       10      //unit second
74 #define CONFIG_RK29_WATCHDOG_DEBUG      1
75 */
76
77 static int nowayout     = WATCHDOG_NOWAYOUT;
78 static int tmr_margin   = 100;//CONFIG_RK29_WATCHDOG_DEFAULT_TIME;
79 #ifdef CONFIG_RK29_WATCHDOG_ATBOOT
80 static int tmr_atboot   = 1;
81 #else
82 static int tmr_atboot   = 0;
83 #endif
84
85 static int soft_noboot;
86
87 #ifdef CONFIG_RK29_WATCHDOG_DEBUG
88 static int debug        = 1;
89 #else
90 static int debug        = 0;
91 #endif
92
93 module_param(tmr_margin,  int, 0);
94 module_param(tmr_atboot,  int, 0);
95 module_param(nowayout,    int, 0);
96 module_param(soft_noboot, int, 0);
97 module_param(debug,       int, 0);
98
99 MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default="
100                 __MODULE_STRING(CONFIG_RK29_WATCHDOG_DEFAULT_TIME) ")");
101 MODULE_PARM_DESC(tmr_atboot,
102                 "Watchdog is started at boot time if set to 1, default="
103                         __MODULE_STRING(CONFIG_RK29_WATCHDOG_ATBOOT));
104 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
105                         __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
106 MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
107                         "0 to reboot (default depends on ONLY_TESTING)");
108 MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");
109
110
111 static unsigned long open_lock;
112 static struct device    *wdt_dev;       /* platform device attached to */
113 static struct resource  *wdt_mem;
114 static struct resource  *wdt_irq;
115 static struct clk       *wdt_clock;
116 static void __iomem     *wdt_base;
117 static char              expect_close;
118
119
120 /* watchdog control routines */
121
122 #define DBG(msg...) do { \
123         if (debug) \
124                 printk(KERN_INFO msg); \
125         } while (0)
126
127 #define wdt_writel(v, offset) do { writel_relaxed(v, wdt_base + offset); dsb(); } while (0)
128
129 /* functions */
130 void rk29_wdt_keepalive(void)
131 {
132         if (wdt_base)
133                 wdt_writel(0x76, RK29_WDT_CRR);
134 }
135
136 static void __rk29_wdt_stop(void)
137 {
138         rk29_wdt_keepalive();    //feed dog
139         wdt_writel(0x0a, RK29_WDT_CR);
140 }
141
142 void rk29_wdt_stop(void)
143 {
144         __rk29_wdt_stop();
145         clk_disable_unprepare(wdt_clock);
146 }
147
148 /* timeout unit second */
149 int rk29_wdt_set_heartbeat(int timeout)
150 {
151         unsigned int count = 0;
152         unsigned int torr = 0, acc = 1, maxtime = 0;    
153         unsigned int freq = clk_get_rate(wdt_clock);
154
155         if (timeout < 1)
156                 return -EINVAL;
157         //0x80000000 is the max count of watch dog
158         maxtime = 0x80000000 / freq + 1;
159         if(timeout > maxtime)
160                 timeout = maxtime;
161                 
162         count = timeout * freq;
163         count /= 0x10000;
164
165         while(acc < count){
166                 acc *= 2;
167                 torr++;
168         }
169         if(torr > 15){
170                 torr = 15;
171         }
172         DBG("%s:torr:%d, count:%d, maxtime:%d s\n", __func__, torr, count, maxtime);
173         wdt_writel(torr, RK29_WDT_TORR);
174         return 0;
175 }
176
177 void rk29_wdt_start(void)
178 {
179         unsigned long wtcon;
180         clk_prepare_enable(wdt_clock);
181         rk29_wdt_set_heartbeat(tmr_margin);
182         wtcon = (RK29_WDT_EN << 0) | (RK29_RESPONSE_MODE << 1) | (RK29_RESET_PULSE << 2);
183         wdt_writel(wtcon, RK29_WDT_CR);
184 }
185
186 /*
187  *      /dev/watchdog handling
188  */
189
190 static int rk29_wdt_open(struct inode *inode, struct file *file)
191 {
192         DBG("%s\n", __func__);
193         if (test_and_set_bit(0, &open_lock))
194                 return -EBUSY;
195
196         if (nowayout)
197                 __module_get(THIS_MODULE);
198
199         expect_close = 0;
200
201         /* start the timer */
202         rk29_wdt_start();
203         return nonseekable_open(inode, file);
204 }
205
206 static int rk29_wdt_release(struct inode *inode, struct file *file)
207 {
208         /*
209          *      Shut off the timer.
210          *      Lock it in if it's a module and we set nowayout
211          */
212         DBG("%s\n", __func__);
213         if (expect_close == 42)
214                 rk29_wdt_stop();
215         else {
216                 dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");
217                 rk29_wdt_keepalive();
218         }
219         expect_close = 0;
220         clear_bit(0, &open_lock);
221         return 0;
222 }
223
224 static ssize_t rk29_wdt_write(struct file *file, const char __user *data,
225                                 size_t len, loff_t *ppos)
226 {
227         /*
228          *      Refresh the timer.
229          */
230         DBG("%s\n", __func__);
231         if (len) {
232                 if (!nowayout) {
233                         size_t i;
234
235                         /* In case it was set long ago */
236                         expect_close = 0;
237
238                         for (i = 0; i != len; i++) {
239                                 char c;
240
241                                 if (get_user(c, data + i))
242                                         return -EFAULT;
243                                 if (c == 'V')
244                                         expect_close = 42;
245                         }
246                 }
247                 rk29_wdt_keepalive();
248         }
249         return len;
250 }
251
252 #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
253
254 static const struct watchdog_info rk29_wdt_ident = {
255         .options          =     OPTIONS,
256         .firmware_version =     0,
257         .identity         =     "rk29 Watchdog",
258 };
259
260
261 static long rk29_wdt_ioctl(struct file *file,   unsigned int cmd,
262                                                         unsigned long arg)
263 {
264         void __user *argp = (void __user *)arg;
265         int __user *p = argp;
266         int new_margin;
267         DBG("%s\n", __func__);
268         switch (cmd) {
269         case WDIOC_GETSUPPORT:
270                 return copy_to_user(argp, &rk29_wdt_ident,
271                         sizeof(rk29_wdt_ident)) ? -EFAULT : 0;
272         case WDIOC_GETSTATUS:
273         case WDIOC_GETBOOTSTATUS:
274                 return put_user(0, p);
275         case WDIOC_KEEPALIVE:
276                 DBG("%s:rk29_wdt_keepalive\n", __func__);
277                 rk29_wdt_keepalive();
278                 return 0;
279         case WDIOC_SETTIMEOUT:
280                 if (get_user(new_margin, p))
281                         return -EFAULT;
282                 if (rk29_wdt_set_heartbeat(new_margin))
283                         return -EINVAL;
284                 rk29_wdt_keepalive();
285                 return put_user(tmr_margin, p);
286         case WDIOC_GETTIMEOUT:
287                 return put_user(tmr_margin, p);
288         default:
289                 return -ENOTTY;
290         }
291 }
292
293
294
295 /* kernel interface */
296
297 static const struct file_operations rk29_wdt_fops = {
298         .owner          = THIS_MODULE,
299         .llseek         = no_llseek,
300         .write          = rk29_wdt_write,
301         .unlocked_ioctl = rk29_wdt_ioctl,
302         .open           = rk29_wdt_open,
303         .release        = rk29_wdt_release,
304 };
305
306 static struct miscdevice rk29_wdt_miscdev = {
307         .minor          = WATCHDOG_MINOR,
308         .name           = "watchdog",
309         .fops           = &rk29_wdt_fops,
310 };
311
312
313 /* interrupt handler code */
314
315 static irqreturn_t rk29_wdt_irq_handler(int irqno, void *param)
316 {
317         DBG("RK29_wdt:watchdog timer expired (irq)\n");
318         rk29_wdt_keepalive();
319         return IRQ_HANDLED;
320 }
321
322
323 /* device interface */
324
325 static int rk29_wdt_probe(struct platform_device *pdev)
326 {
327         struct resource *res;
328         struct device *dev;
329         int started = 0;
330         int ret, val;
331
332         dev = &pdev->dev;
333         wdt_dev = &pdev->dev;
334
335         /* get the memory region for the watchdog timer */
336         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
337         if (res == NULL) {
338                 dev_err(dev, "no memory resource specified\n");
339                 return -ENOENT;
340         }
341
342         wdt_base = devm_request_and_ioremap(&pdev->dev, res);
343         if (wdt_base == NULL) {
344                 dev_err(dev, "failed to ioremap() region\n");
345                 return -EINVAL;
346         }
347         
348 #ifdef CONFIG_OF
349         if(!of_property_read_u32(pdev->dev.of_node, "rockchip,atboot", &val))
350                 tmr_atboot = val;
351         else
352                 tmr_atboot = 0;
353
354         if(!of_property_read_u32(pdev->dev.of_node, "rockchip,timeout", &val))
355                 tmr_margin = val;
356         else
357                 tmr_margin = 0;
358
359         if(!of_property_read_u32(pdev->dev.of_node, "rockchip,debug", &val))
360                 debug = val;
361         else
362                 debug = 0;
363         DBG("probe: mapped wdt_base=%p\n", wdt_base);
364
365         of_property_read_u32(pdev->dev.of_node, "rockchip,irq", &val);
366 #endif
367
368 #ifdef CONFIG_RK29_FEED_DOG_BY_INTE
369         val = 1;
370 #endif
371         //printk("atboot:%d, timeout:%ds, debug:%d, irq:%d\n", tmr_atboot, tmr_margin, debug, val);
372         
373         if(val == 1) {
374                 wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
375                 if (wdt_irq == NULL) {
376                         dev_err(dev, "no irq resource specified\n");
377                         return -ENOENT;
378                 }
379
380                 ret = request_irq(wdt_irq->start, rk29_wdt_irq_handler, 0, pdev->name, pdev);
381                 if (ret != 0) {
382                         dev_err(dev, "failed to install irq (%d)\n", ret);
383                         return ret;
384                 }
385         }
386
387         wdt_clock = devm_clk_get(&pdev->dev, "pclk_wdt");
388         if (IS_ERR(wdt_clock)) {
389                 dev_err(dev, "failed to find watchdog clock source\n");
390                 ret = PTR_ERR(wdt_clock);
391                 goto err_irq;
392         }
393
394         ret = misc_register(&rk29_wdt_miscdev);
395         if (ret) {
396                 dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
397                         WATCHDOG_MINOR, ret);
398                 goto err_irq;
399         }
400         if (tmr_atboot && started == 0) {
401                 dev_info(dev, "starting watchdog timer\n");
402                 rk29_wdt_start();
403         } else if (!tmr_atboot) {
404                 /* if we're not enabling the watchdog, then ensure it is
405                  * disabled if it has been left running from the bootloader
406                  * or other source */
407
408                 rk29_wdt_stop();
409         }
410         return 0;
411
412 err_irq:
413         free_irq(wdt_irq->start, pdev);
414         return ret;
415 }
416
417 static int rk29_wdt_remove(struct platform_device *dev)
418 {
419         wdt_mem = NULL;
420         free_irq(wdt_irq->start, dev);
421         wdt_irq = NULL;
422         clk_disable_unprepare(wdt_clock);
423         wdt_clock = NULL;
424         misc_deregister(&rk29_wdt_miscdev);
425         return 0;
426 }
427
428 static void rk29_wdt_shutdown(struct platform_device *dev)
429 {
430         rk29_wdt_stop();
431 }
432
433 #ifdef CONFIG_PM
434
435 static int rk29_wdt_suspend(struct platform_device *dev, pm_message_t state)
436 {
437         rk29_wdt_stop();
438         return 0;
439 }
440
441 static int rk29_wdt_resume(struct platform_device *dev)
442 {
443         rk29_wdt_start();
444         return 0;
445 }
446
447 #else
448 #define rk29_wdt_suspend NULL
449 #define rk29_wdt_resume  NULL
450 #endif /* CONFIG_PM */
451
452 #ifdef CONFIG_OF
453 static const struct of_device_id of_rk29_wdt_match[] = {
454         { .compatible = "rockchip,watch dog" },
455         { /* Sentinel */ }
456 };
457 #endif
458 static struct platform_driver rk29_wdt_driver = {
459         .probe          = rk29_wdt_probe,
460         .remove         = rk29_wdt_remove,
461         .shutdown       = rk29_wdt_shutdown,
462         .suspend        = rk29_wdt_suspend,
463         .resume         = rk29_wdt_resume,
464         .driver         = {
465                 .owner  = THIS_MODULE,
466 #ifdef CONFIG_OF
467                 .of_match_table = of_rk29_wdt_match,
468 #endif
469                 .name   = "rk29-wdt",
470         },
471 };
472
473
474 static char banner[] __initdata =
475         KERN_INFO "RK29 Watchdog Timer, (c) 2011 Rockchip Electronics\n";
476
477 static int __init watchdog_init(void)
478 {
479         printk(banner);
480         return platform_driver_register(&rk29_wdt_driver);
481 }
482
483 static void __exit watchdog_exit(void)
484 {
485         platform_driver_unregister(&rk29_wdt_driver);
486 }
487
488 subsys_initcall(watchdog_init);
489 module_exit(watchdog_exit);
490
491 MODULE_AUTHOR("hhb@rock-chips.com");
492 MODULE_DESCRIPTION("RK29 Watchdog Device Driver");
493 MODULE_LICENSE("GPL");
494 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
495 MODULE_ALIAS("platform:rk29-wdt");