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