Merge 3.10-rc6 into staging-next
[sfrench/cifs-2.6.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      (0x49000000 + 0x30000)
29 #define INT_34XX_WDT3_IRQ       (36 + NR_IRQS)
30
31 static struct dsp_wdt_setting dsp_wdt;
32
33 void dsp_wdt_dpc(unsigned long data)
34 {
35         struct deh_mgr *deh_mgr;
36         dev_get_deh_mgr(dev_get_first(), &deh_mgr);
37         if (deh_mgr)
38                 bridge_deh_notify(deh_mgr, DSP_WDTOVERFLOW, 0);
39 }
40
41 irqreturn_t dsp_wdt_isr(int irq, void *data)
42 {
43         u32 value;
44         /* ack wdt3 interrupt */
45         value = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
46         __raw_writel(value, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
47
48         tasklet_schedule(&dsp_wdt.wdt3_tasklet);
49         return IRQ_HANDLED;
50 }
51
52 int dsp_wdt_init(void)
53 {
54         int ret = 0;
55
56         dsp_wdt.sm_wdt = NULL;
57         dsp_wdt.reg_base = ioremap(OMAP34XX_WDT3_BASE, SZ_4K);
58         if (!dsp_wdt.reg_base)
59                 return -ENOMEM;
60
61         tasklet_init(&dsp_wdt.wdt3_tasklet, dsp_wdt_dpc, 0);
62
63         dsp_wdt.fclk = clk_get(NULL, "wdt3_fck");
64
65         if (!IS_ERR(dsp_wdt.fclk)) {
66                 clk_prepare(dsp_wdt.fclk);
67
68                 dsp_wdt.iclk = clk_get(NULL, "wdt3_ick");
69                 if (IS_ERR(dsp_wdt.iclk)) {
70                         clk_put(dsp_wdt.fclk);
71                         dsp_wdt.fclk = NULL;
72                         ret = -EFAULT;
73                 } else {
74                         clk_prepare(dsp_wdt.iclk);
75                 }
76         } else
77                 ret = -EFAULT;
78
79         if (!ret)
80                 ret = request_irq(INT_34XX_WDT3_IRQ, dsp_wdt_isr, 0,
81                                                         "dsp_wdt", &dsp_wdt);
82
83         /* Disable at this moment, it will be enabled when DSP starts */
84         if (!ret)
85                 disable_irq(INT_34XX_WDT3_IRQ);
86
87         return ret;
88 }
89
90 void dsp_wdt_sm_set(void *data)
91 {
92         dsp_wdt.sm_wdt = data;
93         dsp_wdt.sm_wdt->wdt_overflow = 5;       /* in seconds */
94 }
95
96
97 void dsp_wdt_exit(void)
98 {
99         free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt);
100         tasklet_kill(&dsp_wdt.wdt3_tasklet);
101
102         if (dsp_wdt.fclk) {
103                 clk_unprepare(dsp_wdt.fclk);
104                 clk_put(dsp_wdt.fclk);
105         }
106         if (dsp_wdt.iclk) {
107                 clk_unprepare(dsp_wdt.iclk);
108                 clk_put(dsp_wdt.iclk);
109         }
110
111         dsp_wdt.fclk = NULL;
112         dsp_wdt.iclk = NULL;
113         dsp_wdt.sm_wdt = NULL;
114
115         if (dsp_wdt.reg_base)
116                 iounmap(dsp_wdt.reg_base);
117         dsp_wdt.reg_base = NULL;
118 }
119
120 void dsp_wdt_enable(bool enable)
121 {
122         u32 tmp;
123         static bool wdt_enable;
124
125         if (wdt_enable == enable || !dsp_wdt.fclk || !dsp_wdt.iclk)
126                 return;
127
128         wdt_enable = enable;
129
130         if (enable) {
131                 clk_enable(dsp_wdt.fclk);
132                 clk_enable(dsp_wdt.iclk);
133                 dsp_wdt.sm_wdt->wdt_setclocks = 1;
134                 tmp = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
135                 __raw_writel(tmp, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
136                 enable_irq(INT_34XX_WDT3_IRQ);
137         } else {
138                 disable_irq(INT_34XX_WDT3_IRQ);
139                 dsp_wdt.sm_wdt->wdt_setclocks = 0;
140                 clk_disable(dsp_wdt.iclk);
141                 clk_disable(dsp_wdt.fclk);
142         }
143 }