![Omar Ramirez Luna](/assets/img/avatar_default.png)
This solves runtime failures while trying to enable WDT3 related functionality on firmware load, however it does affect other clocks controlled by the driver. Seen on 3.8-rc1. CCF provides clk_prepare and clk_unprepare for enable and disable operations respectively, this needs to be called in the correct order while handling clocks. Code path to enable/disable dsp clocks can still be reached from an atomic context, hence we can't use clk_prepare_enable and clk_disable_unprepare yet. Signed-off-by: Omar Ramirez Luna <omar.ramirez@copitl.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
144 lines
3.2 KiB
C
144 lines
3.2 KiB
C
/*
|
|
* 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 (0x49000000 + 0x30000)
|
|
#define INT_34XX_WDT3_IRQ (36 + NR_IRQS)
|
|
|
|
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 = ioremap(OMAP34XX_WDT3_BASE, SZ_4K);
|
|
if (!dsp_wdt.reg_base)
|
|
return -ENOMEM;
|
|
|
|
tasklet_init(&dsp_wdt.wdt3_tasklet, dsp_wdt_dpc, 0);
|
|
|
|
dsp_wdt.fclk = clk_get(NULL, "wdt3_fck");
|
|
|
|
if (!IS_ERR(dsp_wdt.fclk)) {
|
|
clk_prepare(dsp_wdt.fclk);
|
|
|
|
dsp_wdt.iclk = clk_get(NULL, "wdt3_ick");
|
|
if (IS_ERR(dsp_wdt.iclk)) {
|
|
clk_put(dsp_wdt.fclk);
|
|
dsp_wdt.fclk = NULL;
|
|
ret = -EFAULT;
|
|
} else {
|
|
clk_prepare(dsp_wdt.iclk);
|
|
}
|
|
} 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_unprepare(dsp_wdt.fclk);
|
|
clk_put(dsp_wdt.fclk);
|
|
}
|
|
if (dsp_wdt.iclk) {
|
|
clk_unprepare(dsp_wdt.iclk);
|
|
clk_put(dsp_wdt.iclk);
|
|
}
|
|
|
|
dsp_wdt.fclk = NULL;
|
|
dsp_wdt.iclk = NULL;
|
|
dsp_wdt.sm_wdt = NULL;
|
|
|
|
if (dsp_wdt.reg_base)
|
|
iounmap(dsp_wdt.reg_base);
|
|
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);
|
|
}
|
|
}
|