1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
31static struct dsp_wdt_setting dsp_wdt;
32
33void 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
41irqreturn_t dsp_wdt_isr(int irq, void *data)
42{
43 u32 value;
44
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
52int 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
84 if (!ret)
85 disable_irq(INT_34XX_WDT3_IRQ);
86
87 return ret;
88}
89
90void dsp_wdt_sm_set(void *data)
91{
92 dsp_wdt.sm_wdt = data;
93 dsp_wdt.sm_wdt->wdt_overflow = 5;
94}
95
96
97void 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
120void 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}
144