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
30static struct dsp_wdt_setting dsp_wdt;
31
32void 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
40irqreturn_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
51int 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
85void 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
92void 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
111void 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}
135