Commit 88c5544a authored by Nicolas Ferre's avatar Nicolas Ferre

Merge tag 'at91-cleanup3' into at91-4.1-multiplatform

Third batch of cleanup for 4.1:
- System Timer (ST) for at91rm9200 re-work (syscon/regmap):
  - watchdog
  - restart handler
  - timer as a proper clocksource
  => remove mach dependency + cleanup
parents 2197cf70 8590ca65
...@@ -46,10 +46,12 @@ PIT Timer required properties: ...@@ -46,10 +46,12 @@ PIT Timer required properties:
shared across all System Controller members. shared across all System Controller members.
System Timer (ST) required properties: System Timer (ST) required properties:
- compatible: Should be "atmel,at91rm9200-st" - compatible: Should be "atmel,at91rm9200-st", "syscon", "simple-mfd"
- reg: Should contain registers location and length - reg: Should contain registers location and length
- interrupts: Should contain interrupt for the ST which is the IRQ line - interrupts: Should contain interrupt for the ST which is the IRQ line
shared across all System Controller members. shared across all System Controller members.
Its subnodes can be:
- watchdog: compatible should be "atmel,at91rm9200-wdt"
TC/TCLIB Timer required properties: TC/TCLIB Timer required properties:
- compatible: Should be "atmel,<chip>-tcb". - compatible: Should be "atmel,<chip>-tcb".
......
...@@ -356,9 +356,13 @@ macb0_clk: macb0_clk { ...@@ -356,9 +356,13 @@ macb0_clk: macb0_clk {
}; };
st: timer@fffffd00 { st: timer@fffffd00 {
compatible = "atmel,at91rm9200-st"; compatible = "atmel,at91rm9200-st", "syscon", "simple-mfd";
reg = <0xfffffd00 0x100>; reg = <0xfffffd00 0x100>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
watchdog {
compatible = "atmel,at91rm9200-wdt";
};
}; };
rtc: rtc@fffffe00 { rtc: rtc@fffffe00 {
......
...@@ -77,6 +77,7 @@ if SOC_SAM_V4_V5 ...@@ -77,6 +77,7 @@ if SOC_SAM_V4_V5
config SOC_AT91RM9200 config SOC_AT91RM9200
bool "AT91RM9200" bool "AT91RM9200"
select ATMEL_AIC_IRQ select ATMEL_AIC_IRQ
select ATMEL_ST
select COMMON_CLK_AT91 select COMMON_CLK_AT91
select CPU_ARM920T select CPU_ARM920T
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
......
...@@ -7,7 +7,7 @@ obj-y := soc.o ...@@ -7,7 +7,7 @@ obj-y := soc.o
obj-$(CONFIG_SOC_AT91SAM9) += sam9_smc.o obj-$(CONFIG_SOC_AT91SAM9) += sam9_smc.o
# CPU-specific support # CPU-specific support
obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o at91rm9200_time.o obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9.o obj-$(CONFIG_SOC_AT91SAM9) += at91sam9.o
obj-$(CONFIG_SOC_SAMA5) += sama5.o obj-$(CONFIG_SOC_SAMA5) += sama5.o
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/system_misc.h> #include <asm/system_misc.h>
#include <mach/at91_st.h>
#include "generic.h" #include "generic.h"
#include "soc.h" #include "soc.h"
...@@ -25,21 +23,6 @@ static const struct at91_soc rm9200_socs[] = { ...@@ -25,21 +23,6 @@ static const struct at91_soc rm9200_socs[] = {
{ /* sentinel */ }, { /* sentinel */ },
}; };
static void at91rm9200_restart(enum reboot_mode reboot_mode, const char *cmd)
{
/*
* Perform a hardware reset with the use of the Watchdog timer.
*/
at91_st_write(AT91_ST_WDMR, AT91_ST_RSTEN | AT91_ST_EXTEN | 1);
at91_st_write(AT91_ST_CR, AT91_ST_WDRST);
}
static void __init at91rm9200_dt_timer_init(void)
{
of_clk_init(NULL);
at91rm9200_timer_init();
}
static void __init at91rm9200_dt_device_init(void) static void __init at91rm9200_dt_device_init(void)
{ {
struct soc_device *soc; struct soc_device *soc;
...@@ -52,7 +35,6 @@ static void __init at91rm9200_dt_device_init(void) ...@@ -52,7 +35,6 @@ static void __init at91rm9200_dt_device_init(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev); of_platform_populate(NULL, of_default_bus_match_table, NULL, soc_dev);
arm_pm_idle = at91rm9200_idle; arm_pm_idle = at91rm9200_idle;
arm_pm_restart = at91rm9200_restart;
at91rm9200_pm_init(); at91rm9200_pm_init();
} }
...@@ -62,7 +44,6 @@ static const char *at91rm9200_dt_board_compat[] __initconst = { ...@@ -62,7 +44,6 @@ static const char *at91rm9200_dt_board_compat[] __initconst = {
}; };
DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200") DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200")
.init_time = at91rm9200_dt_timer_init,
.init_machine = at91rm9200_dt_device_init, .init_machine = at91rm9200_dt_device_init,
.dt_compat = at91rm9200_dt_board_compat, .dt_compat = at91rm9200_dt_board_compat,
MACHINE_END MACHINE_END
...@@ -18,9 +18,6 @@ ...@@ -18,9 +18,6 @@
extern void __init at91_map_io(void); extern void __init at91_map_io(void);
extern void __init at91_alt_map_io(void); extern void __init at91_alt_map_io(void);
/* Timer */
extern void at91rm9200_timer_init(void);
/* idle */ /* idle */
extern void at91rm9200_idle(void); extern void at91rm9200_idle(void);
extern void at91sam9_idle(void); extern void at91sam9_idle(void);
......
/*
* arch/arm/mach-at91/include/mach/at91_st.h
*
* Copyright (C) 2005 Ivan Kokshaysky
* Copyright (C) SAN People
*
* System Timer (ST) - System peripherals registers.
* Based on AT91RM9200 datasheet revision E.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef AT91_ST_H
#define AT91_ST_H
#ifndef __ASSEMBLY__
extern void __iomem *at91_st_base;
#define at91_st_read(field) \
__raw_readl(at91_st_base + field)
#define at91_st_write(field, value) \
__raw_writel(value, at91_st_base + field)
#else
.extern at91_st_base
#endif
#define AT91_ST_CR 0x00 /* Control Register */
#define AT91_ST_WDRST (1 << 0) /* Watchdog Timer Restart */
#define AT91_ST_PIMR 0x04 /* Period Interval Mode Register */
#define AT91_ST_PIV (0xffff << 0) /* Period Interval Value */
#define AT91_ST_WDMR 0x08 /* Watchdog Mode Register */
#define AT91_ST_WDV (0xffff << 0) /* Watchdog Counter Value */
#define AT91_ST_RSTEN (1 << 16) /* Reset Enable */
#define AT91_ST_EXTEN (1 << 17) /* External Signal Assertion Enable */
#define AT91_ST_RTMR 0x0c /* Real-time Mode Register */
#define AT91_ST_RTPRES (0xffff << 0) /* Real-time Prescalar Value */
#define AT91_ST_SR 0x10 /* Status Register */
#define AT91_ST_PITS (1 << 0) /* Period Interval Timer Status */
#define AT91_ST_WDOVF (1 << 1) /* Watchdog Overflow */
#define AT91_ST_RTTINC (1 << 2) /* Real-time Timer Increment */
#define AT91_ST_ALMS (1 << 3) /* Alarm Status */
#define AT91_ST_IER 0x14 /* Interrupt Enable Register */
#define AT91_ST_IDR 0x18 /* Interrupt Disable Register */
#define AT91_ST_IMR 0x1c /* Interrupt Mask Register */
#define AT91_ST_RTAR 0x20 /* Real-time Alarm Register */
#define AT91_ST_ALMV (0xfffff << 0) /* Alarm Value */
#define AT91_ST_CRTR 0x24 /* Current Real-time Register */
#define AT91_ST_CRTV (0xfffff << 0) /* Current Real-Time Value */
#endif
...@@ -143,6 +143,10 @@ config ATMEL_PIT ...@@ -143,6 +143,10 @@ config ATMEL_PIT
select CLKSRC_OF if OF select CLKSRC_OF if OF
def_bool SOC_AT91SAM9 || SOC_SAMA5 def_bool SOC_AT91SAM9 || SOC_SAMA5
config ATMEL_ST
bool
select CLKSRC_OF
config CLKSRC_METAG_GENERIC config CLKSRC_METAG_GENERIC
def_bool y if METAG def_bool y if METAG
help help
......
obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o
obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o
obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o
obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
......
...@@ -24,19 +24,17 @@ ...@@ -24,19 +24,17 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/of.h> #include <linux/mfd/syscon.h>
#include <linux/of_address.h> #include <linux/mfd/syscon/atmel-st.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/regmap.h>
#include <asm/mach/time.h>
#include <mach/at91_st.h>
#include <mach/hardware.h>
static unsigned long last_crtr; static unsigned long last_crtr;
static u32 irqmask; static u32 irqmask;
static struct clock_event_device clkevt; static struct clock_event_device clkevt;
static struct regmap *regmap_st;
#define AT91_SLOW_CLOCK 32768
#define RM9200_TIMER_LATCH ((AT91_SLOW_CLOCK + HZ/2) / HZ) #define RM9200_TIMER_LATCH ((AT91_SLOW_CLOCK + HZ/2) / HZ)
/* /*
...@@ -46,11 +44,11 @@ static struct clock_event_device clkevt; ...@@ -46,11 +44,11 @@ static struct clock_event_device clkevt;
*/ */
static inline unsigned long read_CRTR(void) static inline unsigned long read_CRTR(void)
{ {
unsigned long x1, x2; unsigned int x1, x2;
x1 = at91_st_read(AT91_ST_CRTR); regmap_read(regmap_st, AT91_ST_CRTR, &x1);
do { do {
x2 = at91_st_read(AT91_ST_CRTR); regmap_read(regmap_st, AT91_ST_CRTR, &x2);
if (x1 == x2) if (x1 == x2)
break; break;
x1 = x2; x1 = x2;
...@@ -63,7 +61,10 @@ static inline unsigned long read_CRTR(void) ...@@ -63,7 +61,10 @@ static inline unsigned long read_CRTR(void)
*/ */
static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id) static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
{ {
u32 sr = at91_st_read(AT91_ST_SR) & irqmask; u32 sr;
regmap_read(regmap_st, AT91_ST_SR, &sr);
sr &= irqmask;
/* /*
* irqs should be disabled here, but as the irq is shared they are only * irqs should be disabled here, but as the irq is shared they are only
...@@ -92,13 +93,6 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id) ...@@ -92,13 +93,6 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
return IRQ_NONE; return IRQ_NONE;
} }
static struct irqaction at91rm9200_timer_irq = {
.name = "at91_tick",
.flags = IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = at91rm9200_timer_interrupt,
.irq = NR_IRQS_LEGACY + AT91_ID_SYS,
};
static cycle_t read_clk32k(struct clocksource *cs) static cycle_t read_clk32k(struct clocksource *cs)
{ {
return read_CRTR(); return read_CRTR();
...@@ -115,23 +109,25 @@ static struct clocksource clk32k = { ...@@ -115,23 +109,25 @@ static struct clocksource clk32k = {
static void static void
clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev) clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{ {
unsigned int val;
/* Disable and flush pending timer interrupts */ /* Disable and flush pending timer interrupts */
at91_st_write(AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS); regmap_write(regmap_st, AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
at91_st_read(AT91_ST_SR); regmap_read(regmap_st, AT91_ST_SR, &val);
last_crtr = read_CRTR(); last_crtr = read_CRTR();
switch (mode) { switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: case CLOCK_EVT_MODE_PERIODIC:
/* PIT for periodic irqs; fixed rate of 1/HZ */ /* PIT for periodic irqs; fixed rate of 1/HZ */
irqmask = AT91_ST_PITS; irqmask = AT91_ST_PITS;
at91_st_write(AT91_ST_PIMR, RM9200_TIMER_LATCH); regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH);
break; break;
case CLOCK_EVT_MODE_ONESHOT: case CLOCK_EVT_MODE_ONESHOT:
/* ALM for oneshot irqs, set by next_event() /* ALM for oneshot irqs, set by next_event()
* before 32 seconds have passed * before 32 seconds have passed
*/ */
irqmask = AT91_ST_ALMS; irqmask = AT91_ST_ALMS;
at91_st_write(AT91_ST_RTAR, last_crtr); regmap_write(regmap_st, AT91_ST_RTAR, last_crtr);
break; break;
case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_UNUSED:
...@@ -139,7 +135,7 @@ clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev) ...@@ -139,7 +135,7 @@ clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev)
irqmask = 0; irqmask = 0;
break; break;
} }
at91_st_write(AT91_ST_IER, irqmask); regmap_write(regmap_st, AT91_ST_IER, irqmask);
} }
static int static int
...@@ -147,6 +143,7 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev) ...@@ -147,6 +143,7 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
{ {
u32 alm; u32 alm;
int status = 0; int status = 0;
unsigned int val;
BUG_ON(delta < 2); BUG_ON(delta < 2);
...@@ -162,12 +159,12 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev) ...@@ -162,12 +159,12 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
alm = read_CRTR(); alm = read_CRTR();
/* Cancel any pending alarm; flush any pending IRQ */ /* Cancel any pending alarm; flush any pending IRQ */
at91_st_write(AT91_ST_RTAR, alm); regmap_write(regmap_st, AT91_ST_RTAR, alm);
at91_st_read(AT91_ST_SR); regmap_read(regmap_st, AT91_ST_SR, &val);
/* Schedule alarm by writing RTAR. */ /* Schedule alarm by writing RTAR. */
alm += delta; alm += delta;
at91_st_write(AT91_ST_RTAR, alm); regmap_write(regmap_st, AT91_ST_RTAR, alm);
return status; return status;
} }
...@@ -180,66 +177,40 @@ static struct clock_event_device clkevt = { ...@@ -180,66 +177,40 @@ static struct clock_event_device clkevt = {
.set_mode = clkevt32k_mode, .set_mode = clkevt32k_mode,
}; };
void __iomem *at91_st_base;
EXPORT_SYMBOL_GPL(at91_st_base);
static const struct of_device_id at91rm9200_st_timer_ids[] = {
{ .compatible = "atmel,at91rm9200-st" },
{ /* sentinel */ }
};
static int __init of_at91rm9200_st_init(void)
{
struct device_node *np;
int ret;
np = of_find_matching_node(NULL, at91rm9200_st_timer_ids);
if (!np)
goto err;
at91_st_base = of_iomap(np, 0);
if (!at91_st_base)
goto node_err;
/* Get the interrupts property */
ret = irq_of_parse_and_map(np, 0);
if (!ret)
goto ioremap_err;
at91rm9200_timer_irq.irq = ret;
of_node_put(np);
return 0;
ioremap_err:
iounmap(at91_st_base);
node_err:
of_node_put(np);
err:
return -EINVAL;
}
/* /*
* ST (system timer) module supports both clockevents and clocksource. * ST (system timer) module supports both clockevents and clocksource.
*/ */
void __init at91rm9200_timer_init(void) static void __init atmel_st_timer_init(struct device_node *node)
{ {
/* For device tree enabled device: initialize here */ unsigned int val;
of_at91rm9200_st_init(); int irq, ret;
regmap_st = syscon_node_to_regmap(node);
if (IS_ERR(regmap_st))
panic(pr_fmt("Unable to get regmap\n"));
/* Disable all timer interrupts, and clear any pending ones */ /* Disable all timer interrupts, and clear any pending ones */
at91_st_write(AT91_ST_IDR, regmap_write(regmap_st, AT91_ST_IDR,
AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS); AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
at91_st_read(AT91_ST_SR); regmap_read(regmap_st, AT91_ST_SR, &val);
/* Get the interrupts property */
irq = irq_of_parse_and_map(node, 0);
if (!irq)
panic(pr_fmt("Unable to get IRQ from DT\n"));
/* Make IRQs happen for the system timer */ /* Make IRQs happen for the system timer */
setup_irq(at91rm9200_timer_irq.irq, &at91rm9200_timer_irq); ret = request_irq(irq, at91rm9200_timer_interrupt,
IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
"at91_tick", regmap_st);
if (ret)
panic(pr_fmt("Unable to setup IRQ\n"));
/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used /* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
* directly for the clocksource and all clockevents, after adjusting * directly for the clocksource and all clockevents, after adjusting
* its prescaler from the 1 Hz default. * its prescaler from the 1 Hz default.
*/ */
at91_st_write(AT91_ST_RTMR, 1); regmap_write(regmap_st, AT91_ST_RTMR, 1);
/* Setup timer clockevent, with minimum of two ticks (important!!) */ /* Setup timer clockevent, with minimum of two ticks (important!!) */
clkevt.cpumask = cpumask_of(0); clkevt.cpumask = cpumask_of(0);
...@@ -249,3 +220,5 @@ void __init at91rm9200_timer_init(void) ...@@ -249,3 +220,5 @@ void __init at91rm9200_timer_init(void)
/* register clocksource */ /* register clocksource */
clocksource_register_hz(&clk32k, AT91_SLOW_CLOCK); clocksource_register_hz(&clk32k, AT91_SLOW_CLOCK);
} }
CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st",
atmel_st_timer_init);
...@@ -154,7 +154,7 @@ config ARM_SP805_WATCHDOG ...@@ -154,7 +154,7 @@ config ARM_SP805_WATCHDOG
config AT91RM9200_WATCHDOG config AT91RM9200_WATCHDOG
tristate "AT91RM9200 watchdog" tristate "AT91RM9200 watchdog"
depends on SOC_AT91RM9200 depends on SOC_AT91RM9200 && MFD_SYSCON
help help
Watchdog timer embedded into AT91RM9200 chips. This will reboot your Watchdog timer embedded into AT91RM9200 chips. This will reboot your
system when the timeout is reached. system when the timeout is reached.
......
...@@ -12,27 +12,32 @@ ...@@ -12,27 +12,32 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/atmel-st.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <mach/at91_st.h>
#define WDT_DEFAULT_TIME 5 /* seconds */ #define WDT_DEFAULT_TIME 5 /* seconds */
#define WDT_MAX_TIME 256 /* seconds */ #define WDT_MAX_TIME 256 /* seconds */
static int wdt_time = WDT_DEFAULT_TIME; static int wdt_time = WDT_DEFAULT_TIME;
static bool nowayout = WATCHDOG_NOWAYOUT; static bool nowayout = WATCHDOG_NOWAYOUT;
static struct regmap *regmap_st;
module_param(wdt_time, int, 0); module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default=" MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
...@@ -50,12 +55,33 @@ static unsigned long at91wdt_busy; ...@@ -50,12 +55,33 @@ static unsigned long at91wdt_busy;
/* ......................................................................... */ /* ......................................................................... */
static int at91rm9200_restart(struct notifier_block *this,
unsigned long mode, void *cmd)
{
/*
* Perform a hardware reset with the use of the Watchdog timer.
*/
regmap_write(regmap_st, AT91_ST_WDMR,
AT91_ST_RSTEN | AT91_ST_EXTEN | 1);
regmap_write(regmap_st, AT91_ST_CR, AT91_ST_WDRST);
mdelay(2000);
pr_emerg("Unable to restart system\n");
return NOTIFY_DONE;
}
static struct notifier_block at91rm9200_restart_nb = {
.notifier_call = at91rm9200_restart,
.priority = 192,
};
/* /*
* Disable the watchdog. * Disable the watchdog.
*/ */
static inline void at91_wdt_stop(void) static inline void at91_wdt_stop(void)
{ {
at91_st_write(AT91_ST_WDMR, AT91_ST_EXTEN); regmap_write(regmap_st, AT91_ST_WDMR, AT91_ST_EXTEN);
} }
/* /*
...@@ -63,9 +89,9 @@ static inline void at91_wdt_stop(void) ...@@ -63,9 +89,9 @@ static inline void at91_wdt_stop(void)
*/ */
static inline void at91_wdt_start(void) static inline void at91_wdt_start(void)
{ {
at91_st_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | regmap_write(regmap_st, AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN |
(((65536 * wdt_time) >> 8) & AT91_ST_WDV)); (((65536 * wdt_time) >> 8) & AT91_ST_WDV));
at91_st_write(AT91_ST_CR, AT91_ST_WDRST); regmap_write(regmap_st, AT91_ST_CR, AT91_ST_WDRST);
} }
/* /*
...@@ -73,7 +99,7 @@ static inline void at91_wdt_start(void) ...@@ -73,7 +99,7 @@ static inline void at91_wdt_start(void)
*/ */
static inline void at91_wdt_reload(void) static inline void at91_wdt_reload(void)
{ {
at91_st_write(AT91_ST_CR, AT91_ST_WDRST); regmap_write(regmap_st, AT91_ST_CR, AT91_ST_WDRST);
} }
/* ......................................................................... */ /* ......................................................................... */
...@@ -203,16 +229,32 @@ static struct miscdevice at91wdt_miscdev = { ...@@ -203,16 +229,32 @@ static struct miscdevice at91wdt_miscdev = {
static int at91wdt_probe(struct platform_device *pdev) static int at91wdt_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev;
struct device *parent;
int res; int res;
if (at91wdt_miscdev.parent) if (at91wdt_miscdev.parent)
return -EBUSY; return -EBUSY;
at91wdt_miscdev.parent = &pdev->dev; at91wdt_miscdev.parent = &pdev->dev;
parent = dev->parent;
if (!parent) {
dev_err(dev, "no parent\n");
return -ENODEV;
}
regmap_st = syscon_node_to_regmap(parent->of_node);
if (!regmap_st)
return -ENODEV;
res = misc_register(&at91wdt_miscdev); res = misc_register(&at91wdt_miscdev);
if (res) if (res)
return res; return res;
res = register_restart_handler(&at91rm9200_restart_nb);
if (res)
dev_warn(dev, "failed to register restart handler\n");
pr_info("AT91 Watchdog Timer enabled (%d seconds%s)\n", pr_info("AT91 Watchdog Timer enabled (%d seconds%s)\n",
wdt_time, nowayout ? ", nowayout" : ""); wdt_time, nowayout ? ", nowayout" : "");
return 0; return 0;
...@@ -220,8 +262,13 @@ static int at91wdt_probe(struct platform_device *pdev) ...@@ -220,8 +262,13 @@ static int at91wdt_probe(struct platform_device *pdev)
static int at91wdt_remove(struct platform_device *pdev) static int at91wdt_remove(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev;
int res; int res;
res = unregister_restart_handler(&at91rm9200_restart_nb);
if (res)
dev_warn(dev, "failed to unregister restart handler\n");
res = misc_deregister(&at91wdt_miscdev); res = misc_deregister(&at91wdt_miscdev);
if (!res) if (!res)
at91wdt_miscdev.parent = NULL; at91wdt_miscdev.parent = NULL;
...@@ -267,7 +314,7 @@ static struct platform_driver at91wdt_driver = { ...@@ -267,7 +314,7 @@ static struct platform_driver at91wdt_driver = {
.suspend = at91wdt_suspend, .suspend = at91wdt_suspend,
.resume = at91wdt_resume, .resume = at91wdt_resume,
.driver = { .driver = {
.name = "at91_wdt", .name = "atmel_st_watchdog",
.of_match_table = at91_wdt_dt_ids, .of_match_table = at91_wdt_dt_ids,
}, },
}; };
...@@ -296,4 +343,4 @@ module_exit(at91_wdt_exit); ...@@ -296,4 +343,4 @@ module_exit(at91_wdt_exit);
MODULE_AUTHOR("Andrew Victor"); MODULE_AUTHOR("Andrew Victor");
MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200"); MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:at91_wdt"); MODULE_ALIAS("platform:atmel_st_watchdog");
/*
* Copyright (C) 2005 Ivan Kokshaysky
* Copyright (C) SAN People
*
* System Timer (ST) - System peripherals registers.
* Based on AT91RM9200 datasheet revision E.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef _LINUX_MFD_SYSCON_ATMEL_ST_H
#define _LINUX_MFD_SYSCON_ATMEL_ST_H
#include <linux/bitops.h>
#define AT91_ST_CR 0x00 /* Control Register */
#define AT91_ST_WDRST BIT(0) /* Watchdog Timer Restart */
#define AT91_ST_PIMR 0x04 /* Period Interval Mode Register */
#define AT91_ST_PIV 0xffff /* Period Interval Value */
#define AT91_ST_WDMR 0x08 /* Watchdog Mode Register */
#define AT91_ST_WDV 0xffff /* Watchdog Counter Value */
#define AT91_ST_RSTEN BIT(16) /* Reset Enable */
#define AT91_ST_EXTEN BIT(17) /* External Signal Assertion Enable */
#define AT91_ST_RTMR 0x0c /* Real-time Mode Register */
#define AT91_ST_RTPRES 0xffff /* Real-time Prescalar Value */
#define AT91_ST_SR 0x10 /* Status Register */
#define AT91_ST_PITS BIT(0) /* Period Interval Timer Status */
#define AT91_ST_WDOVF BIT(1) /* Watchdog Overflow */
#define AT91_ST_RTTINC BIT(2) /* Real-time Timer Increment */
#define AT91_ST_ALMS BIT(3) /* Alarm Status */
#define AT91_ST_IER 0x14 /* Interrupt Enable Register */
#define AT91_ST_IDR 0x18 /* Interrupt Disable Register */
#define AT91_ST_IMR 0x1c /* Interrupt Mask Register */
#define AT91_ST_RTAR 0x20 /* Real-time Alarm Register */
#define AT91_ST_ALMV 0xfffff /* Alarm Value */
#define AT91_ST_CRTR 0x24 /* Current Real-time Register */
#define AT91_ST_CRTV 0xfffff /* Current Real-Time Value */
#endif /* _LINUX_MFD_SYSCON_ATMEL_ST_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment