blob: dcfe13cfc650ea0c354c00d065741d4f96f4ea8b [file] [log] [blame]
Jay Chokshia9348af2013-03-14 13:04:57 -07001/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/io.h>
18#include <linux/delay.h>
19#include <linux/workqueue.h>
20#include <linux/pm.h>
21#include <linux/mfd/pmic8058.h>
22#include <linux/jiffies.h>
23#include <linux/suspend.h>
Trilok Sonieecb28c2011-07-20 16:24:14 +010024#include <linux/percpu.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/interrupt.h>
Jay Chokshia9348af2013-03-14 13:04:57 -070026#include <linux/reboot.h>
Rohit Vaswaniead426f2012-01-05 20:24:52 -080027#include <asm/fiq.h>
28#include <asm/hardware/gic.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029#include <mach/msm_iomap.h>
30#include <asm/mach-types.h>
Rohit Vaswani9cea7ca2012-07-06 19:54:24 -070031#include <asm/cacheflush.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070032#include <mach/scm.h>
Rohit Vaswani085a9332011-09-28 18:57:24 -070033#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034#include "msm_watchdog.h"
Rohit Vaswani085a9332011-09-28 18:57:24 -070035#include "timer.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
Jeff Ohlstein7e668552011-10-06 16:17:25 -070037#define MODULE_NAME "msm_watchdog"
38
Rohit Vaswani085a9332011-09-28 18:57:24 -070039#define TCSR_WDT_CFG 0x30
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040
Rohit Vaswanic77e4a62012-08-09 18:10:28 -070041#define WDT_RST 0x0
42#define WDT_EN 0x8
43#define WDT_STS 0xC
44#define WDT_BARK_TIME 0x14
45#define WDT_BITE_TIME 0x24
Rohit Vaswani085a9332011-09-28 18:57:24 -070046
Jeff Ohlstein7e668552011-10-06 16:17:25 -070047#define WDT_HZ 32768
48
Rohit Vaswaniead426f2012-01-05 20:24:52 -080049struct msm_watchdog_dump msm_dump_cpu_ctx;
50
Rohit Vaswanic77e4a62012-08-09 18:10:28 -070051static void __iomem *msm_wdt_base;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053static unsigned long delay_time;
Jeff Ohlstein7e668552011-10-06 16:17:25 -070054static unsigned long bark_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055static unsigned long long last_pet;
Rohit Vaswanic9fdd442012-03-19 14:18:32 -070056static bool has_vic;
Rohit Vaswanic77e4a62012-08-09 18:10:28 -070057static unsigned int msm_wdog_irq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058
59/*
60 * On the kernel command line specify
61 * msm_watchdog.enable=1 to enable the watchdog
62 * By default watchdog is turned on
63 */
64static int enable = 1;
65module_param(enable, int, 0);
66
67/*
Jay Chokshia9348af2013-03-14 13:04:57 -070068 * Watchdog bark reboot timeout in seconds.
69 * Can be specified in kernel command line.
70 */
71static int reboot_bark_timeout = 22;
72module_param(reboot_bark_timeout, int, 0644);
73/*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070074 * If the watchdog is enabled at bootup (enable=1),
75 * the runtime_disable sysfs node at
76 * /sys/module/msm_watchdog/runtime_disable
77 * can be used to deactivate the watchdog.
78 * This is a one-time setting. The watchdog
79 * cannot be re-enabled once it is disabled.
80 */
81static int runtime_disable;
82static DEFINE_MUTEX(disable_lock);
83static int wdog_enable_set(const char *val, struct kernel_param *kp);
84module_param_call(runtime_disable, wdog_enable_set, param_get_int,
85 &runtime_disable, 0644);
86
87/*
88 * On the kernel command line specify msm_watchdog.appsbark=1 to handle
89 * watchdog barks in Linux. By default barks are processed by the secure side.
90 */
91static int appsbark;
92module_param(appsbark, int, 0);
93
Rohit Vaswaniead426f2012-01-05 20:24:52 -080094static int appsbark_fiq;
95
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096/*
97 * Use /sys/module/msm_watchdog/parameters/print_all_stacks
98 * to control whether stacks of all running
99 * processes are printed when a wdog bark is received.
100 */
101static int print_all_stacks = 1;
102module_param(print_all_stacks, int, S_IRUGO | S_IWUSR);
103
104/* Area for context dump in secure mode */
105static void *scm_regsave;
106
Trilok Sonieecb28c2011-07-20 16:24:14 +0100107static struct msm_watchdog_pdata __percpu **percpu_pdata;
108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109static void pet_watchdog_work(struct work_struct *work);
110static void init_watchdog_work(struct work_struct *work);
111static DECLARE_DELAYED_WORK(dogwork_struct, pet_watchdog_work);
112static DECLARE_WORK(init_dogwork_struct, init_watchdog_work);
113
Rohit Vaswaniead426f2012-01-05 20:24:52 -0800114/* Called from the FIQ bark handler */
115void msm_wdog_bark_fin(void)
116{
Rohit Vaswani9cea7ca2012-07-06 19:54:24 -0700117 flush_cache_all();
Rohit Vaswaniead426f2012-01-05 20:24:52 -0800118 pr_crit("\nApps Watchdog bark received - Calling Panic\n");
119 panic("Apps Watchdog Bark received\n");
120}
121
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700122static int msm_watchdog_suspend(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123{
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700124 if (!enable)
125 return 0;
126
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700127 __raw_writel(1, msm_wdt_base + WDT_RST);
128 __raw_writel(0, msm_wdt_base + WDT_EN);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 mb();
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700130 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131}
132
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700133static int msm_watchdog_resume(struct device *dev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134{
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700135 if (!enable)
136 return 0;
137
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700138 __raw_writel(1, msm_wdt_base + WDT_EN);
139 __raw_writel(1, msm_wdt_base + WDT_RST);
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700140 mb();
141 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142}
143
144static int panic_wdog_handler(struct notifier_block *this,
145 unsigned long event, void *ptr)
146{
147 if (panic_timeout == 0) {
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700148 __raw_writel(0, msm_wdt_base + WDT_EN);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 mb();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 } else {
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700151 __raw_writel(WDT_HZ * (panic_timeout + 4),
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700152 msm_wdt_base + WDT_BARK_TIME);
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700153 __raw_writel(WDT_HZ * (panic_timeout + 4),
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700154 msm_wdt_base + WDT_BITE_TIME);
155 __raw_writel(1, msm_wdt_base + WDT_RST);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700156 }
157 return NOTIFY_DONE;
158}
159
160static struct notifier_block panic_blk = {
161 .notifier_call = panic_wdog_handler,
162};
163
Jay Chokshia9348af2013-03-14 13:04:57 -0700164#define get_sclk_hz(t_ms) ((t_ms / 1000) * WDT_HZ)
165#define get_reboot_bark_timeout(t_s) ((t_s * MSEC_PER_SEC) < bark_time ? \
166 get_sclk_hz(bark_time) : get_sclk_hz(t_s * MSEC_PER_SEC))
167
168static int msm_watchdog_reboot_notifier(struct notifier_block *this,
169 unsigned long code, void *unused)
170{
171
172 u64 timeout = get_reboot_bark_timeout(reboot_bark_timeout);
173 __raw_writel(timeout, msm_wdt_base + WDT_BARK_TIME);
174 __raw_writel(timeout + 3 * WDT_HZ,
175 msm_wdt_base + WDT_BITE_TIME);
176 __raw_writel(1, msm_wdt_base + WDT_RST);
177
178 return NOTIFY_DONE;
179}
180
181static struct notifier_block msm_reboot_notifier = {
182 .notifier_call = msm_watchdog_reboot_notifier,
183};
184
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700185struct wdog_disable_work_data {
186 struct work_struct work;
187 struct completion complete;
188};
189
190static void wdog_disable_work(struct work_struct *work)
191{
192 struct wdog_disable_work_data *work_data =
193 container_of(work, struct wdog_disable_work_data, work);
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700194 __raw_writel(0, msm_wdt_base + WDT_EN);
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700195 mb();
196 if (has_vic) {
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700197 free_irq(msm_wdog_irq, 0);
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700198 } else {
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700199 disable_percpu_irq(msm_wdog_irq);
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700200 if (!appsbark_fiq) {
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700201 free_percpu_irq(msm_wdog_irq,
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700202 percpu_pdata);
203 free_percpu(percpu_pdata);
204 }
205 }
206 enable = 0;
207 atomic_notifier_chain_unregister(&panic_notifier_list, &panic_blk);
Jay Chokshia9348af2013-03-14 13:04:57 -0700208 unregister_reboot_notifier(&msm_reboot_notifier);
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700209 cancel_delayed_work(&dogwork_struct);
210 /* may be suspended after the first write above */
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700211 __raw_writel(0, msm_wdt_base + WDT_EN);
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700212 complete(&work_data->complete);
213 pr_info("MSM Watchdog deactivated.\n");
214}
215
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216static int wdog_enable_set(const char *val, struct kernel_param *kp)
217{
218 int ret = 0;
219 int old_val = runtime_disable;
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700220 struct wdog_disable_work_data work_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221
222 mutex_lock(&disable_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223 if (!enable) {
224 printk(KERN_INFO "MSM Watchdog is not active.\n");
225 ret = -EINVAL;
226 goto done;
227 }
228
229 ret = param_set_int(val, kp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 if (ret)
231 goto done;
232
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700233 if (runtime_disable == 1) {
234 if (old_val)
235 goto done;
236 init_completion(&work_data.complete);
237 INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work);
238 schedule_work_on(0, &work_data.work);
239 wait_for_completion(&work_data.complete);
240 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 runtime_disable = old_val;
242 ret = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244done:
245 mutex_unlock(&disable_lock);
246 return ret;
247}
248
Jeff Ohlstein535280e2011-12-09 19:34:30 -0800249unsigned min_slack_ticks = UINT_MAX;
250unsigned long long min_slack_ns = ULLONG_MAX;
251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252void pet_watchdog(void)
253{
Jeff Ohlstein535280e2011-12-09 19:34:30 -0800254 int slack;
255 unsigned long long time_ns;
256 unsigned long long slack_ns;
257 unsigned long long bark_time_ns = bark_time * 1000000ULL;
258
Vikram Mulukutla76f08e02012-05-01 19:15:19 -0700259 if (!enable)
260 return;
261
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700262 slack = __raw_readl(msm_wdt_base + WDT_STS) >> 3;
Jeff Ohlstein535280e2011-12-09 19:34:30 -0800263 slack = ((bark_time*WDT_HZ)/1000) - slack;
264 if (slack < min_slack_ticks)
265 min_slack_ticks = slack;
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700266 __raw_writel(1, msm_wdt_base + WDT_RST);
Jeff Ohlstein535280e2011-12-09 19:34:30 -0800267 time_ns = sched_clock();
268 slack_ns = (last_pet + bark_time_ns) - time_ns;
269 if (slack_ns < min_slack_ns)
270 min_slack_ns = slack_ns;
271 last_pet = time_ns;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272}
273
274static void pet_watchdog_work(struct work_struct *work)
275{
276 pet_watchdog();
277
278 if (enable)
279 schedule_delayed_work_on(0, &dogwork_struct, delay_time);
280}
281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282static irqreturn_t wdog_bark_handler(int irq, void *dev_id)
283{
284 unsigned long nanosec_rem;
285 unsigned long long t = sched_clock();
286 struct task_struct *tsk;
287
288 nanosec_rem = do_div(t, 1000000000);
289 printk(KERN_INFO "Watchdog bark! Now = %lu.%06lu\n", (unsigned long) t,
290 nanosec_rem / 1000);
291
292 nanosec_rem = do_div(last_pet, 1000000000);
293 printk(KERN_INFO "Watchdog last pet at %lu.%06lu\n", (unsigned long)
294 last_pet, nanosec_rem / 1000);
295
296 if (print_all_stacks) {
297
298 /* Suspend wdog until all stacks are printed */
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700299 msm_watchdog_suspend(NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300
301 printk(KERN_INFO "Stack trace dump:\n");
302
303 for_each_process(tsk) {
304 printk(KERN_INFO "\nPID: %d, Name: %s\n",
305 tsk->pid, tsk->comm);
306 show_stack(tsk, NULL);
307 }
308
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700309 msm_watchdog_resume(NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310 }
311
312 panic("Apps watchdog bark received!");
313 return IRQ_HANDLED;
314}
315
316#define SCM_SET_REGSAVE_CMD 0x2
317
Rohit Vaswani085a9332011-09-28 18:57:24 -0700318static void configure_bark_dump(void)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319{
320 int ret;
321 struct {
322 unsigned addr;
323 int len;
324 } cmd_buf;
325
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700326 if (!appsbark) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327 scm_regsave = (void *)__get_free_page(GFP_KERNEL);
328
329 if (scm_regsave) {
330 cmd_buf.addr = __pa(scm_regsave);
331 cmd_buf.len = PAGE_SIZE;
332
333 ret = scm_call(SCM_SVC_UTIL, SCM_SET_REGSAVE_CMD,
334 &cmd_buf, sizeof(cmd_buf), NULL, 0);
335 if (ret)
336 pr_err("Setting register save address failed.\n"
337 "Registers won't be dumped on a dog "
338 "bite\n");
Rohit Vaswani085a9332011-09-28 18:57:24 -0700339 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700340 pr_err("Allocating register save space failed\n"
341 "Registers won't be dumped on a dog bite\n");
342 /*
343 * No need to bail if allocation fails. Simply don't
344 * send the command, and the secure side will reset
345 * without saving registers.
346 */
Rohit Vaswani085a9332011-09-28 18:57:24 -0700347 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700348 }
Rohit Vaswani085a9332011-09-28 18:57:24 -0700349}
350
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700351struct fiq_handler wdog_fh = {
352 .name = MODULE_NAME,
353};
354
Rohit Vaswani085a9332011-09-28 18:57:24 -0700355static void init_watchdog_work(struct work_struct *work)
356{
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700357 u64 timeout = (bark_time * WDT_HZ)/1000;
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700358 void *stack;
359 int ret;
360
361 if (has_vic) {
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700362 ret = request_irq(msm_wdog_irq, wdog_bark_handler, 0,
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700363 "apps_wdog_bark", NULL);
364 if (ret)
365 return;
366 } else if (appsbark_fiq) {
367 claim_fiq(&wdog_fh);
368 set_fiq_handler(&msm_wdog_fiq_start, msm_wdog_fiq_length);
369 stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
370 if (!stack) {
371 pr_info("No free pages available - %s fails\n",
372 __func__);
373 return;
374 }
375
376 msm_wdog_fiq_setup(stack);
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700377 gic_set_irq_secure(msm_wdog_irq);
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700378 } else {
379 percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
380 if (!percpu_pdata) {
381 pr_err("%s: memory allocation failed for percpu data\n",
382 __func__);
383 return;
384 }
385
386 /* Must request irq before sending scm command */
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700387 ret = request_percpu_irq(msm_wdog_irq,
Jeff Ohlsteinb1e211e2012-05-01 18:55:05 -0700388 wdog_bark_handler, "apps_wdog_bark", percpu_pdata);
389 if (ret) {
390 free_percpu(percpu_pdata);
391 return;
392 }
393 }
Jeff Ohlstein5edb4ae2012-03-06 16:39:50 -0800394
395 configure_bark_dump();
396
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700397 __raw_writel(timeout, msm_wdt_base + WDT_BARK_TIME);
398 __raw_writel(timeout + 3*WDT_HZ, msm_wdt_base + WDT_BITE_TIME);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399
400 schedule_delayed_work_on(0, &dogwork_struct, delay_time);
401
402 atomic_notifier_chain_register(&panic_notifier_list,
403 &panic_blk);
404
Jay Chokshia9348af2013-03-14 13:04:57 -0700405 ret = register_reboot_notifier(&msm_reboot_notifier);
406 if (ret)
407 pr_err("Failed to register reboot notifier\n");
408
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700409 __raw_writel(1, msm_wdt_base + WDT_EN);
410 __raw_writel(1, msm_wdt_base + WDT_RST);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 last_pet = sched_clock();
412
Rohit Vaswaniead426f2012-01-05 20:24:52 -0800413 if (!has_vic)
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700414 enable_percpu_irq(msm_wdog_irq, IRQ_TYPE_EDGE_RISING);
Rohit Vaswaniead426f2012-01-05 20:24:52 -0800415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 printk(KERN_INFO "MSM Watchdog Initialized\n");
417
418 return;
419}
420
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700421static int msm_watchdog_probe(struct platform_device *pdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422{
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700423 struct msm_watchdog_pdata *pdata = pdev->dev.platform_data;
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700424
425 if (!enable || !pdata || !pdata->pet_time || !pdata->bark_time) {
426 printk(KERN_INFO "MSM Watchdog Not Initialized\n");
427 return -ENODEV;
428 }
429
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700430 bark_time = pdata->bark_time;
Jay Chokshia9348af2013-03-14 13:04:57 -0700431 /* reboot_bark_timeout (in seconds) might have been supplied as
432 * module parameter.
433 */
434 if ((reboot_bark_timeout * MSEC_PER_SEC) < bark_time)
435 reboot_bark_timeout = (bark_time / MSEC_PER_SEC);
Rohit Vaswanic9fdd442012-03-19 14:18:32 -0700436 has_vic = pdata->has_vic;
Rohit Vaswaniead426f2012-01-05 20:24:52 -0800437 if (!pdata->has_secure) {
438 appsbark = 1;
439 appsbark_fiq = pdata->use_kernel_fiq;
440 }
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700441
Rohit Vaswanic77e4a62012-08-09 18:10:28 -0700442 msm_wdt_base = pdata->base;
443 msm_wdog_irq = platform_get_irq(pdev, 0);
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700444
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700445 /*
446 * This is only temporary till SBLs turn on the XPUs
447 * This initialization will be done in SBLs on a later releases
448 */
449 if (cpu_is_msm9615())
450 __raw_writel(0xF, MSM_TCSR_BASE + TCSR_WDT_CFG);
451
Joel Kinge7ca6f72012-02-09 20:51:25 -0800452 if (pdata->needs_expired_enable)
453 __raw_writel(0x1, MSM_CLK_CTL_BASE + 0x3820);
454
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700455 delay_time = msecs_to_jiffies(pdata->pet_time);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700456 schedule_work_on(0, &init_dogwork_struct);
457 return 0;
458}
459
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700460static const struct dev_pm_ops msm_watchdog_dev_pm_ops = {
461 .suspend_noirq = msm_watchdog_suspend,
462 .resume_noirq = msm_watchdog_resume,
463};
464
465static struct platform_driver msm_watchdog_driver = {
466 .probe = msm_watchdog_probe,
Jeff Ohlstein7e668552011-10-06 16:17:25 -0700467 .driver = {
468 .name = MODULE_NAME,
469 .owner = THIS_MODULE,
470 .pm = &msm_watchdog_dev_pm_ops,
471 },
472};
473
474static int init_watchdog(void)
475{
476 return platform_driver_register(&msm_watchdog_driver);
477}
478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479late_initcall(init_watchdog);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480MODULE_DESCRIPTION("MSM Watchdog Driver");
481MODULE_VERSION("1.0");
482MODULE_LICENSE("GPL v2");