brcmsmac: rework of mac80211 .flush() callback operation
[pandora-kernel.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                 dsp_wdt.iclk = clk_get(NULL, "wdt3_ick");
67                 if (IS_ERR(dsp_wdt.iclk)) {
68                         clk_put(dsp_wdt.fclk);
69                         dsp_wdt.fclk = NULL;
70                         ret = -EFAULT;
71                 }
72         } else
73                 ret = -EFAULT;
74
75         if (!ret)
76                 ret = request_irq(INT_34XX_WDT3_IRQ, dsp_wdt_isr, 0,
77                                                         "dsp_wdt", &dsp_wdt);
78
79         /* Disable at this moment, it will be enabled when DSP starts */
80         if (!ret)
81                 disable_irq(INT_34XX_WDT3_IRQ);
82
83         return ret;
84 }
85
86 void dsp_wdt_sm_set(void *data)
87 {
88         dsp_wdt.sm_wdt = data;
89         dsp_wdt.sm_wdt->wdt_overflow = 5;       /* in seconds */
90 }
91
92
93 void dsp_wdt_exit(void)
94 {
95         free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt);
96         tasklet_kill(&dsp_wdt.wdt3_tasklet);
97
98         if (dsp_wdt.fclk)
99                 clk_put(dsp_wdt.fclk);
100         if (dsp_wdt.iclk)
101                 clk_put(dsp_wdt.iclk);
102
103         dsp_wdt.fclk = NULL;
104         dsp_wdt.iclk = NULL;
105         dsp_wdt.sm_wdt = NULL;
106
107         if (dsp_wdt.reg_base)
108                 iounmap(dsp_wdt.reg_base);
109         dsp_wdt.reg_base = NULL;
110 }
111
112 void dsp_wdt_enable(bool enable)
113 {
114         u32 tmp;
115         static bool wdt_enable;
116
117         if (wdt_enable == enable || !dsp_wdt.fclk || !dsp_wdt.iclk)
118                 return;
119
120         wdt_enable = enable;
121
122         if (enable) {
123                 clk_enable(dsp_wdt.fclk);
124                 clk_enable(dsp_wdt.iclk);
125                 dsp_wdt.sm_wdt->wdt_setclocks = 1;
126                 tmp = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
127                 __raw_writel(tmp, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
128                 enable_irq(INT_34XX_WDT3_IRQ);
129         } else {
130                 disable_irq(INT_34XX_WDT3_IRQ);
131                 dsp_wdt.sm_wdt->wdt_setclocks = 0;
132                 clk_disable(dsp_wdt.iclk);
133                 clk_disable(dsp_wdt.fclk);
134         }
135 }