Merge tag 'pm-for-3.4-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-flexiantxendom0-3.2.10.git] / drivers / staging / tidspbridge / core / wdt.c
1 /*
2  * wdt.c
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * IO dispatcher for a shared memory channel driver.
7  *
8  * Copyright (C) 2010 Texas Instruments, Inc.
9  *
10  * This package is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17  */
18 #include <linux/types.h>
19
20 #include <dspbridge/dbdefs.h>
21 #include <dspbridge/dspdeh.h>
22 #include <dspbridge/dev.h>
23 #include <dspbridge/_chnl_sm.h>
24 #include <dspbridge/wdt.h>
25 #include <dspbridge/host_os.h>
26
27
28 #define OMAP34XX_WDT3_BASE              (L4_PER_34XX_BASE + 0x30000)
29
30 static struct dsp_wdt_setting dsp_wdt;
31
32 void dsp_wdt_dpc(unsigned long data)
33 {
34         struct deh_mgr *deh_mgr;
35         dev_get_deh_mgr(dev_get_first(), &deh_mgr);
36         if (deh_mgr)
37                 bridge_deh_notify(deh_mgr, DSP_WDTOVERFLOW, 0);
38 }
39
40 irqreturn_t dsp_wdt_isr(int irq, void *data)
41 {
42         u32 value;
43         /* ack wdt3 interrupt */
44         value = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
45         __raw_writel(value, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
46
47         tasklet_schedule(&dsp_wdt.wdt3_tasklet);
48         return IRQ_HANDLED;
49 }
50
51 int dsp_wdt_init(void)
52 {
53         int ret = 0;
54
55         dsp_wdt.sm_wdt = NULL;
56         dsp_wdt.reg_base = ioremap(OMAP34XX_WDT3_BASE, SZ_4K);
57         if (!dsp_wdt.reg_base)
58                 return -ENOMEM;
59
60         tasklet_init(&dsp_wdt.wdt3_tasklet, dsp_wdt_dpc, 0);
61
62         dsp_wdt.fclk = clk_get(NULL, "wdt3_fck");
63
64         if (dsp_wdt.fclk) {
65                 dsp_wdt.iclk = clk_get(NULL, "wdt3_ick");
66                 if (!dsp_wdt.iclk) {
67                         clk_put(dsp_wdt.fclk);
68                         dsp_wdt.fclk = NULL;
69                         ret = -EFAULT;
70                 }
71         } else
72                 ret = -EFAULT;
73
74         if (!ret)
75                 ret = request_irq(INT_34XX_WDT3_IRQ, dsp_wdt_isr, 0,
76                                                         "dsp_wdt", &dsp_wdt);
77
78         /* Disable at this moment, it will be enabled when DSP starts */
79         if (!ret)
80                 disable_irq(INT_34XX_WDT3_IRQ);
81
82         return ret;
83 }
84
85 void dsp_wdt_sm_set(void *data)
86 {
87         dsp_wdt.sm_wdt = data;
88         dsp_wdt.sm_wdt->wdt_overflow = 5;       /* in seconds */
89 }
90
91
92 void dsp_wdt_exit(void)
93 {
94         free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt);
95         tasklet_kill(&dsp_wdt.wdt3_tasklet);
96
97         if (dsp_wdt.fclk)
98                 clk_put(dsp_wdt.fclk);
99         if (dsp_wdt.iclk)
100                 clk_put(dsp_wdt.iclk);
101
102         dsp_wdt.fclk = NULL;
103         dsp_wdt.iclk = NULL;
104         dsp_wdt.sm_wdt = NULL;
105
106         if (dsp_wdt.reg_base)
107                 iounmap(dsp_wdt.reg_base);
108         dsp_wdt.reg_base = NULL;
109 }
110
111 void dsp_wdt_enable(bool enable)
112 {
113         u32 tmp;
114         static bool wdt_enable;
115
116         if (wdt_enable == enable || !dsp_wdt.fclk || !dsp_wdt.iclk)
117                 return;
118
119         wdt_enable = enable;
120
121         if (enable) {
122                 clk_enable(dsp_wdt.fclk);
123                 clk_enable(dsp_wdt.iclk);
124                 dsp_wdt.sm_wdt->wdt_setclocks = 1;
125                 tmp = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
126                 __raw_writel(tmp, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
127                 enable_irq(INT_34XX_WDT3_IRQ);
128         } else {
129                 disable_irq(INT_34XX_WDT3_IRQ);
130                 dsp_wdt.sm_wdt->wdt_setclocks = 0;
131                 clk_disable(dsp_wdt.iclk);
132                 clk_disable(dsp_wdt.fclk);
133         }
134 }