diff mbox

[v3,14/16] Davinci: tnetv107x watchdog reset support

Message ID 1271270702-28307-15-git-send-email-cyril@ti.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Cyril Chemparathy April 14, 2010, 6:45 p.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/mach-davinci/devices-tnetv107x.c b/arch/arm/mach-davinci/devices-tnetv107x.c
index ab54c91..43cd2ea 100644
--- a/arch/arm/mach-davinci/devices-tnetv107x.c
+++ b/arch/arm/mach-davinci/devices-tnetv107x.c
@@ -26,6 +26,7 @@ 
 #define TNETV107X_TPCC_BASE			0x01c00000
 #define TNETV107X_TPTC0_BASE			0x01c10000
 #define TNETV107X_TPTC1_BASE			0x01c10400
+#define TNETV107X_WDOG_BASE			0x08086700
 
 /* TNETV107X specific EDMA3 information */
 #define EDMA_TNETV107X_NUM_DMACH	64
@@ -103,11 +104,31 @@  static struct platform_device edma_device = {
 	.dev.platform_data = edma_info,
 };
 
+static struct resource wdt_resources[] = {
+	{
+		.start	= TNETV107X_WDOG_BASE,
+		.end	= TNETV107X_WDOG_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+struct platform_device tnetv107x_wdt_device = {
+	.name		= "watchdog",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(wdt_resources),
+	.resource	= wdt_resources,
+};
+
 void __init tnetv107x_edma_init(void)
 {
 	platform_device_register(&edma_device);
 }
 
+void __init tnetv107x_watchdog_init(void)
+{
+	platform_device_register(&tnetv107x_wdt_device);
+}
+
 void __init tnetv107x_serial_init(struct plat_serial8250_port* ports)
 {
 	int i;
diff --git a/arch/arm/mach-davinci/include/mach/system.h b/arch/arm/mach-davinci/include/mach/system.h
index 90be3f6..141d910 100644
--- a/arch/arm/mach-davinci/include/mach/system.h
+++ b/arch/arm/mach-davinci/include/mach/system.h
@@ -16,8 +16,10 @@ 
 
 extern struct platform_device davinci_wdt_device;
 extern struct platform_device da8xx_wdt_device;
+extern struct platform_device tnetv107x_wdt_device;
 
 extern void davinci_watchdog_reset(struct platform_device *);
+extern void tnetv107x_watchdog_reset(struct platform_device *);
 
 static inline void arch_idle(void)
 {
@@ -31,6 +33,9 @@  static inline void arch_reset(char mode, const char *cmd)
 
 	if (cpu_class_is_da8xx())
 		davinci_watchdog_reset(&da8xx_wdt_device);
+
+	if (cpu_class_is_tnetv107x())
+		tnetv107x_watchdog_reset(&tnetv107x_wdt_device);
 }
 
 #endif /* __ASM_ARCH_SYSTEM_H */
diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h
index 5eafdb8..0ad5466 100644
--- a/arch/arm/mach-davinci/include/mach/tnetv107x.h
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
@@ -59,6 +59,7 @@ 
 extern void __init tnetv107x_init(void);
 extern void __init tnetv107x_gpio_init(void);
 extern void __init tnetv107x_edma_init(void);
+extern void __init tnetv107x_watchdog_init(void);
 extern void __init tnetv107x_irq_init(void);
 extern void __init tnetv107x_serial_init(struct plat_serial8250_port* ports);
 #endif
diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c
index a444ef7..fc5085d 100644
--- a/arch/arm/mach-davinci/tnetv107x.c
+++ b/arch/arm/mach-davinci/tnetv107x.c
@@ -81,6 +81,18 @@  struct sspll_regs {
 	u32	diag;
 };
 
+/* Watchdog Timer Registers */
+struct wdt_regs {
+	u32	kick_lock;
+	u32	kick;
+	u32	change_lock;
+	u32	change ;
+	u32	disable_lock;
+	u32	disable;
+	u32	prescale_lock;
+	u32	prescale;
+};
+
 static struct clk_ctrl_regs __iomem *clk_ctrl_regs;
 
 static struct sspll_regs __iomem *sspll_regs[N_PLLS];
@@ -1173,3 +1185,98 @@  static unsigned long clk_sspll_recalc(struct clk *clk)
 
 	return ret;
 }
+
+static int tnetv107x_wdt_set_period(struct wdt_regs __iomem *regs,
+		unsigned long msec, unsigned long refclk)
+{
+	unsigned long change;
+	unsigned long count;
+	unsigned long prescale = 1;
+
+	refclk /= 1000;
+
+	/* compute prescale and change reg values */
+	count = refclk * msec;
+
+	if (count > 0xffff) {
+		change = count / 0xffff + 1;
+		prescale = count / change;
+	}    else {
+		change =  count;
+	}
+
+	__raw_writel(0x5a5a, &regs->prescale_lock);
+	if ((__raw_readl(&regs->prescale_lock) & 0x3) != 1)
+		return -EIO;
+
+	__raw_writel(0xa5a5, &regs->prescale_lock);
+	if ((__raw_readl(&regs->prescale_lock) & 0x3) != 3)
+		return -EIO;
+
+	__raw_writel(prescale - 1, &regs->prescale);
+
+	__raw_writel(0x6666, &regs->change_lock);
+	if ((__raw_readl(&regs->change_lock) & 0x3) != 1)
+		return -EIO;
+
+	__raw_writel(0xbbbb, &regs->change_lock);
+	if ((__raw_readl(&regs->change_lock) & 0x3) != 3)
+		return -EIO;
+
+	__raw_writel(change, &regs->change);
+	return 0;
+}
+
+static int tnetv107x_wdt_ctrl(struct wdt_regs __iomem *regs, int enable)
+{
+
+	enable = enable ? 1 : 0;
+
+	__raw_writel(0x7777, &regs->disable_lock);
+	if ((__raw_readl(&regs->disable_lock) & 0x3) != 1)
+		return -EIO;
+
+	__raw_writel(0xcccc, &regs->disable_lock);
+	if ((__raw_readl(&regs->disable_lock) & 0x3) != 2)
+		return -EIO;
+
+	__raw_writel(0xdddd, &regs->disable_lock);
+	if ((__raw_readl(&regs->disable_lock) & 0x3) != 3)
+		return -EIO;
+
+	__raw_writel(enable, &regs->disable);
+	return 0;
+}
+
+static int tnetv107x_wdt_kick(struct wdt_regs __iomem *regs)
+{
+	__raw_writel(0x5555, &regs->kick_lock);
+	if ((__raw_readl(&regs->kick_lock) & 0x3) != 1)
+		return -EIO;
+
+	__raw_writel(0xaaaa, &regs->kick_lock);
+	if ((__raw_readl(&regs->kick_lock) & 0x3) != 3)
+		return -EIO;
+
+	__raw_writel(1, &regs->kick);
+	return 0;
+}
+
+void tnetv107x_watchdog_reset(struct platform_device *pdev)
+{
+	struct wdt_regs __iomem *regs;
+	struct clk		*wdt_clk;
+	unsigned long		wdt_clk_rate;
+
+	regs = ioremap(pdev->resource[0].start, SZ_4K);
+	wdt_clk = clk_get(&pdev->dev, NULL);
+	if (WARN_ON(IS_ERR(wdt_clk)))
+		return;
+	clk_enable(wdt_clk);
+	wdt_clk_rate	= clk_get_rate(wdt_clk);
+
+	tnetv107x_wdt_ctrl(regs, 0);
+	tnetv107x_wdt_set_period(regs, 1, wdt_clk_rate);
+	tnetv107x_wdt_ctrl(regs, 1);
+	tnetv107x_wdt_kick(regs);
+}