aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/tidspbridge/core/wdt.c
blob: 70055c8111ed2d208162dbcd7f93f3b6c52c70c7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * wdt.c
 *
 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
 *
 * IO dispatcher for a shared memory channel driver.
 *
 * Copyright (C) 2010 Texas Instruments, Inc.
 *
 * This package is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
#include <linux/types.h>

#include <dspbridge/dbdefs.h>
#include <dspbridge/dspdeh.h>
#include <dspbridge/dev.h>
#include <dspbridge/_chnl_sm.h>
#include <dspbridge/wdt.h>
#include <dspbridge/host_os.h>


#define OMAP34XX_WDT3_BASE 		(L4_PER_34XX_BASE + 0x30000)

static struct dsp_wdt_setting dsp_wdt;

void dsp_wdt_dpc(unsigned long data)
{
	struct deh_mgr *deh_mgr;
	dev_get_deh_mgr(dev_get_first(), &deh_mgr);
	if (deh_mgr)
		bridge_deh_notify(deh_mgr, DSP_WDTOVERFLOW, 0);
}

irqreturn_t dsp_wdt_isr(int irq, void *data)
{
	u32 value;
	/* ack wdt3 interrupt */
	value = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
	__raw_writel(value, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);

	tasklet_schedule(&dsp_wdt.wdt3_tasklet);
	return IRQ_HANDLED;
}

int dsp_wdt_init(void)
{
	int ret = 0;

	dsp_wdt.sm_wdt = NULL;
	dsp_wdt.reg_base = OMAP2_L4_IO_ADDRESS(OMAP34XX_WDT3_BASE);
	tasklet_init(&dsp_wdt.wdt3_tasklet, dsp_wdt_dpc, 0);

	dsp_wdt.fclk = clk_get(NULL, "wdt3_fck");

	if (dsp_wdt.fclk) {
		dsp_wdt.iclk = clk_get(NULL, "wdt3_ick");
		if (!dsp_wdt.iclk) {
			clk_put(dsp_wdt.fclk);
			dsp_wdt.fclk = NULL;
			ret = -EFAULT;
		}
	} else
		ret = -EFAULT;

	if (!ret)
		ret = request_irq(INT_34XX_WDT3_IRQ, dsp_wdt_isr, 0,
							"dsp_wdt", &dsp_wdt);

	/* Disable at this moment, it will be enabled when DSP starts */
	if (!ret)
		disable_irq(INT_34XX_WDT3_IRQ);

	return ret;
}

void dsp_wdt_sm_set(void *data)
{
	dsp_wdt.sm_wdt = data;
	dsp_wdt.sm_wdt->wdt_overflow = 5;	/* in seconds */
}


void dsp_wdt_exit(void)
{
	free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt);
	tasklet_kill(&dsp_wdt.wdt3_tasklet);

	if (dsp_wdt.fclk)
		clk_put(dsp_wdt.fclk);
	if (dsp_wdt.iclk)
		clk_put(dsp_wdt.iclk);

	dsp_wdt.fclk = NULL;
	dsp_wdt.iclk = NULL;
	dsp_wdt.sm_wdt = NULL;
	dsp_wdt.reg_base = NULL;
}

void dsp_wdt_enable(bool enable)
{
	u32 tmp;
	static bool wdt_enable;

	if (wdt_enable == enable || !dsp_wdt.fclk || !dsp_wdt.iclk)
		return;

	wdt_enable = enable;

	if (enable) {
		clk_enable(dsp_wdt.fclk);
		clk_enable(dsp_wdt.iclk);
		dsp_wdt.sm_wdt->wdt_setclocks = 1;
		tmp = __raw_readl(dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
		__raw_writel(tmp, dsp_wdt.reg_base + OMAP3_WDT3_ISR_OFFSET);
		enable_irq(INT_34XX_WDT3_IRQ);
	} else {
		disable_irq(INT_34XX_WDT3_IRQ);
		dsp_wdt.sm_wdt->wdt_setclocks = 0;
		clk_disable(dsp_wdt.iclk);
		clk_disable(dsp_wdt.fclk);
	}
}