Blame view

drivers/watchdog/davinci_wdt.c 6.34 KB
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
1
2
3
4
5
  /*
   * drivers/char/watchdog/davinci_wdt.c
   *
   * Watchdog driver for DaVinci DM644x/DM646x processors
   *
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
6
   * Copyright (C) 2006-2013 Texas Instruments.
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
7
8
9
10
11
12
13
14
15
16
17
   *
   * 2007 (c) MontaVista Software, Inc. This file is licensed under
   * the terms of the GNU General Public License version 2. This program
   * is licensed "as is" without any warranty of any kind, whether express
   * or implied.
   */
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
18
  #include <linux/watchdog.h>
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
19
  #include <linux/platform_device.h>
f78b0a8f2   Alan Cox   [WATCHDOG 08/57] ...
20
  #include <linux/io.h>
371d3525e   Kevin Hilman   [WATCHDOG] davinc...
21
  #include <linux/device.h>
9fd868f44   Kevin Hilman   [WATCHDOG] davinc...
22
  #include <linux/clk.h>
6330c7070   Sachin Kamat   watchdog: Convert...
23
  #include <linux/err.h>
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
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
  
  #define MODULE_NAME "DAVINCI-WDT: "
  
  #define DEFAULT_HEARTBEAT 60
  #define MAX_HEARTBEAT     600	/* really the max margin is 264/27MHz*/
  
  /* Timer register set definition */
  #define PID12	(0x0)
  #define EMUMGT	(0x4)
  #define TIM12	(0x10)
  #define TIM34	(0x14)
  #define PRD12	(0x18)
  #define PRD34	(0x1C)
  #define TCR	(0x20)
  #define TGCR	(0x24)
  #define WDTCR	(0x28)
  
  /* TCR bit definitions */
  #define ENAMODE12_DISABLED	(0 << 6)
  #define ENAMODE12_ONESHOT	(1 << 6)
  #define ENAMODE12_PERIODIC	(2 << 6)
  
  /* TGCR bit definitions */
  #define TIM12RS_UNRESET		(1 << 0)
  #define TIM34RS_UNRESET		(1 << 1)
  #define TIMMODE_64BIT_WDOG      (2 << 2)
  
  /* WDTCR bit definitions */
  #define WDEN			(1 << 14)
  #define WDFLAG			(1 << 15)
  #define WDKEY_SEQ0		(0xa5c6 << 16)
  #define WDKEY_SEQ1		(0xda7e << 16)
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
56
  static int heartbeat;
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
57
58
59
60
61
62
63
64
65
66
67
68
  
  /*
   * struct to hold data for each WDT device
   * @base - base io address of WD device
   * @clk - source clock of WDT
   * @wdd - hold watchdog device as is in WDT core
   */
  struct davinci_wdt_device {
  	void __iomem		*base;
  	struct clk		*clk;
  	struct watchdog_device	wdd;
  };
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
69

f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
70
  static int davinci_wdt_start(struct watchdog_device *wdd)
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
71
72
73
  {
  	u32 tgcr;
  	u32 timer_margin;
9fd868f44   Kevin Hilman   [WATCHDOG] davinc...
74
  	unsigned long wdt_freq;
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
75
  	struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
9fd868f44   Kevin Hilman   [WATCHDOG] davinc...
76

6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
77
  	wdt_freq = clk_get_rate(davinci_wdt->clk);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
78

7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
79
  	/* disable, internal clock source */
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
80
  	iowrite32(0, davinci_wdt->base + TCR);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
81
  	/* reset timer, set mode to 64-bit watchdog, and unreset */
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
82
  	iowrite32(0, davinci_wdt->base + TGCR);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
83
  	tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
84
  	iowrite32(tgcr, davinci_wdt->base + TGCR);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
85
  	/* clear counter regs */
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
86
87
  	iowrite32(0, davinci_wdt->base + TIM12);
  	iowrite32(0, davinci_wdt->base + TIM34);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
88
  	/* set timeout period */
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
89
  	timer_margin = (((u64)wdd->timeout * wdt_freq) & 0xffffffff);
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
90
  	iowrite32(timer_margin, davinci_wdt->base + PRD12);
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
91
  	timer_margin = (((u64)wdd->timeout * wdt_freq) >> 32);
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
92
  	iowrite32(timer_margin, davinci_wdt->base + PRD34);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
93
  	/* enable run continuously */
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
94
  	iowrite32(ENAMODE12_PERIODIC, davinci_wdt->base + TCR);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
95
96
97
98
99
  	/* Once the WDT is in pre-active state write to
  	 * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
  	 * write protected (except for the WDKEY field)
  	 */
  	/* put watchdog in pre-active state */
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
100
  	iowrite32(WDKEY_SEQ0 | WDEN, davinci_wdt->base + WDTCR);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
101
  	/* put watchdog in active state */
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
102
  	iowrite32(WDKEY_SEQ1 | WDEN, davinci_wdt->base + WDTCR);
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
103
  	return 0;
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
104
  }
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
105
  static int davinci_wdt_ping(struct watchdog_device *wdd)
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
106
  {
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
107
  	struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
108
  	/* put watchdog in service state */
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
109
  	iowrite32(WDKEY_SEQ0, davinci_wdt->base + WDTCR);
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
110
  	/* put watchdog in active state */
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
111
  	iowrite32(WDKEY_SEQ1, davinci_wdt->base + WDTCR);
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
112
  	return 0;
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
113
  }
a77199490   Ivan Khoronzhuk   watchdog: davinci...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd)
  {
  	u64 timer_counter;
  	unsigned long freq;
  	u32 val;
  	struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
  
  	/* if timeout has occured then return 0 */
  	val = ioread32(davinci_wdt->base + WDTCR);
  	if (val & WDFLAG)
  		return 0;
  
  	freq = clk_get_rate(davinci_wdt->clk);
  
  	if (!freq)
  		return 0;
  
  	timer_counter = ioread32(davinci_wdt->base + TIM12);
  	timer_counter |= ((u64)ioread32(davinci_wdt->base + TIM34) << 32);
  
  	do_div(timer_counter, freq);
  
  	return wdd->timeout - timer_counter;
  }
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
138
  static const struct watchdog_info davinci_wdt_info = {
f1a08cc9a   Wim Van Sebroeck   [WATCHDOG] davinc...
139
  	.options = WDIOF_KEEPALIVEPING,
8832b2009   Ivan Khoronzhuk   watchdog: davinci...
140
  	.identity = "DaVinci/Keystone Watchdog",
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
141
  };
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
142
143
144
145
146
  static const struct watchdog_ops davinci_wdt_ops = {
  	.owner		= THIS_MODULE,
  	.start		= davinci_wdt_start,
  	.stop		= davinci_wdt_ping,
  	.ping		= davinci_wdt_ping,
a77199490   Ivan Khoronzhuk   watchdog: davinci...
147
  	.get_timeleft	= davinci_wdt_get_timeleft,
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
148
  };
2d991a164   Bill Pemberton   watchdog: remove ...
149
  static int davinci_wdt_probe(struct platform_device *pdev)
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
150
  {
e20880e60   Kumar, Anil   watchdog: davinci...
151
  	int ret = 0;
371d3525e   Kevin Hilman   [WATCHDOG] davinc...
152
  	struct device *dev = &pdev->dev;
e20880e60   Kumar, Anil   watchdog: davinci...
153
  	struct resource  *wdt_mem;
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
154
  	struct watchdog_device *wdd;
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
155
156
157
158
159
  	struct davinci_wdt_device *davinci_wdt;
  
  	davinci_wdt = devm_kzalloc(dev, sizeof(*davinci_wdt), GFP_KERNEL);
  	if (!davinci_wdt)
  		return -ENOMEM;
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
160

6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
161
162
163
  	davinci_wdt->clk = devm_clk_get(dev, NULL);
  	if (WARN_ON(IS_ERR(davinci_wdt->clk)))
  		return PTR_ERR(davinci_wdt->clk);
9fd868f44   Kevin Hilman   [WATCHDOG] davinc...
164

6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
165
  	clk_prepare_enable(davinci_wdt->clk);
9fd868f44   Kevin Hilman   [WATCHDOG] davinc...
166

6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
167
168
169
  	platform_set_drvdata(pdev, davinci_wdt);
  
  	wdd			= &davinci_wdt->wdd;
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
170
171
172
173
174
  	wdd->info		= &davinci_wdt_info;
  	wdd->ops		= &davinci_wdt_ops;
  	wdd->min_timeout	= 1;
  	wdd->max_timeout	= MAX_HEARTBEAT;
  	wdd->timeout		= DEFAULT_HEARTBEAT;
6551881c8   Pratyush Anand   Watchdog: Fix par...
175
  	wdd->parent		= &pdev->dev;
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
176
177
178
179
180
  
  	watchdog_init_timeout(wdd, heartbeat, dev);
  
  	dev_info(dev, "heartbeat %d sec
  ", wdd->timeout);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
181

6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
182
  	watchdog_set_drvdata(wdd, davinci_wdt);
f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
183
  	watchdog_set_nowayout(wdd, 1);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
184

f712eacf0   Julia Lawall   watchdog: Convert...
185
  	wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
186
187
188
  	davinci_wdt->base = devm_ioremap_resource(dev, wdt_mem);
  	if (IS_ERR(davinci_wdt->base))
  		return PTR_ERR(davinci_wdt->base);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
189

f48f3ceab   Ivan Khoronzhuk   watchdog: davinci...
190
191
192
193
  	ret = watchdog_register_device(wdd);
  	if (ret < 0)
  		dev_err(dev, "cannot register watchdog device
  ");
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
194
195
196
  
  	return ret;
  }
4b12b896c   Bill Pemberton   watchdog: remove ...
197
  static int davinci_wdt_remove(struct platform_device *pdev)
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
198
  {
6d9a6cf5c   Ivan Khoronzhuk   watchdog: davinci...
199
200
201
202
  	struct davinci_wdt_device *davinci_wdt = platform_get_drvdata(pdev);
  
  	watchdog_unregister_device(&davinci_wdt->wdd);
  	clk_disable_unprepare(davinci_wdt->clk);
9fd868f44   Kevin Hilman   [WATCHDOG] davinc...
203

7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
204
205
  	return 0;
  }
902e2e7d4   Murali Karicheri   watchdog: davinci...
206
207
208
209
210
  static const struct of_device_id davinci_wdt_of_match[] = {
  	{ .compatible = "ti,davinci-wdt", },
  	{},
  };
  MODULE_DEVICE_TABLE(of, davinci_wdt_of_match);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
211
212
  static struct platform_driver platform_wdt_driver = {
  	.driver = {
843748123   Ivan Khoronzhuk   watchdog: davinci...
213
  		.name = "davinci-wdt",
902e2e7d4   Murali Karicheri   watchdog: davinci...
214
  		.of_match_table = davinci_wdt_of_match,
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
215
216
  	},
  	.probe = davinci_wdt_probe,
82268714b   Bill Pemberton   watchdog: remove ...
217
  	.remove = davinci_wdt_remove,
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
218
  };
b8ec61189   Axel Lin   watchdog: convert...
219
  module_platform_driver(platform_wdt_driver);
7d831bf59   Vladimir Barinov   [WATCHDOG] davinc...
220
221
222
223
224
225
226
227
228
229
230
  
  MODULE_AUTHOR("Texas Instruments");
  MODULE_DESCRIPTION("DaVinci Watchdog Driver");
  
  module_param(heartbeat, int, 0);
  MODULE_PARM_DESC(heartbeat,
  		 "Watchdog heartbeat period in seconds from 1 to "
  		 __MODULE_STRING(MAX_HEARTBEAT) ", default "
  		 __MODULE_STRING(DEFAULT_HEARTBEAT));
  
  MODULE_LICENSE("GPL");
843748123   Ivan Khoronzhuk   watchdog: davinci...
231
  MODULE_ALIAS("platform:davinci-wdt");