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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQEcBAABAgAGBQJVBwXrAAoJEAf03oE53VmQZg8H/iYemk9W0f2+ehf5qzPLnPbP J2uBqm5yHegj0fHaSNBA179Zxq8niJaVXpKBb8C8LCfjPE75K/E9bSAFquyD6NNm mpwkRtxLjCVEAn5KsmXLEX044qNV4eCz9CdskUTQYW0nkW1egu+b1h/ILBaJKYp2 kybInlyv+kXdbh/igh9mPe7psGth0yxOj6h+op8HtvHvwZ0TuFf2abcrvBCzR60n p+lyNusOMgYa4+a2tkFgypD//AY8A5sSkg0LnZv45SBfLObNu22JlR0AbtEensKJ uAkRwYD+d8A1KGC4NPA9Wlc2CiHO0yi/nQaEr/9pUjYLKUzMlQU8Rrehh+5moxw= =giqf -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
88c5544ab2
|
@ -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 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
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 @@
|
||||||
#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[] = {
|
||||||
{ /* 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)
|
||||||
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 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
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 @@
|
||||||
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);
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
||||||
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
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
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 @@
|
||||||
#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;
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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 = {
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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 = {
|
||||||
.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)
|
||||||
/* 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
|
||||||
|
|
||||||
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 @@
|
||||||
#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;
|
||||||
|
|
||||||
/* ......................................................................... */
|
/* ......................................................................... */
|
||||||
|
|
||||||
|
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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 = {
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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 = {
|
||||||
.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);
|
||||||
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");
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* 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 */
|
Loading…
Reference in New Issue