mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 16:12:02 +00:00
Second drivers series for AT91/3.18:
- move of the PIT (basic timer) from mach-at91 to its proper location: drivers/clocksource - big cleanup of this driver along the way -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQEcBAABAgAGBQJUFw4gAAoJEAf03oE53VmQAdwH+gIVjFww5vGjvfZqcOofmjlA hzELgv1Jem2/OSQRkKX9ekY0hArca7POij+V9Ubz0LHag8JzEXhORq7KThx6vXbY iUtx5hXkyXded5h8WqDJT0y7YFpM57Hv6Dgp7gXJQnNULwhQnafds0ucKr0fZVZK 64Zhf6YDQnHYotEoiE2zi+yAl2BI9uoO2tP+kWPezNWLQ5v89FnWtt828N+5Be/B gujSX1ZHDtsIshdfjqhlZtm1eGDztajm/OxdWheU4qELsZ5QaSYe3klaExV93Hp4 LCFzczu54/krauAlLn01x/Kyjpi8S8Hc4Qj6AQU8LpAvoy/SMBy9xo0SIlX1ZX4= =Zxt2 -----END PGP SIGNATURE----- Merge tag 'at91-drivers2' of git://github.com/at91linux/linux-at91 into next/drivers Merge " Second drivers series for AT91/3.18" from Nicolas Ferre: - move of the PIT (basic timer) from mach-at91 to its proper location: drivers/clocksource - big cleanup of this driver along the way * tag 'at91-drivers2' of git://github.com/at91linux/linux-at91: ARM: at91: PIT: Move the driver to drivers/clocksource ARM: at91: Give the PIT irq as an argument of at91sam926x_pit_init ARM: at91: Convert the boards to the init_time callback ARM: at91: soc: Add init_time callback ARM: at91: PIT: (Almost) remove the global variables ARM: at91: PIT: use request_irq instead of setup_irq ARM: at91: PIT: Use pr_fmt ARM: at91: PIT: Use consistent exit path in probe ARM: at91: dt: Remove init_time definitions ARM: at91: PIT: Rework probe functions ARM: at91: PIT: Use of_have_populated_dt instead of CONFIG_OF ARM: at91: PIT: Use DIV_ROUND_CLOSEST to compute the cycles ARM: at91: generic.h: Add include safe guards ARM: at91: PIT: Follow the general coding rules Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
4693c723f7
@ -33,15 +33,11 @@ config OLD_IRQ_AT91
|
||||
select MULTI_IRQ_HANDLER
|
||||
select SPARSE_IRQ
|
||||
|
||||
config AT91_SAM9_TIME
|
||||
bool
|
||||
|
||||
config HAVE_AT91_SMD
|
||||
bool
|
||||
|
||||
config SOC_AT91SAM9
|
||||
bool
|
||||
select AT91_SAM9_TIME
|
||||
select ATMEL_AIC_IRQ if !OLD_IRQ_AT91
|
||||
select CPU_ARM926T
|
||||
select GENERIC_CLOCKEVENTS
|
||||
@ -50,7 +46,6 @@ config SOC_AT91SAM9
|
||||
|
||||
config SOC_SAMA5
|
||||
bool
|
||||
select AT91_SAM9_TIME
|
||||
select ATMEL_AIC5_IRQ
|
||||
select CPU_V7
|
||||
select GENERIC_CLOCKEVENTS
|
||||
|
@ -9,7 +9,6 @@ obj- :=
|
||||
|
||||
obj-$(CONFIG_OLD_IRQ_AT91) += irq.o
|
||||
obj-$(CONFIG_OLD_CLK_AT91) += clock.o
|
||||
obj-$(CONFIG_AT91_SAM9_TIME) += at91sam926x_time.o
|
||||
obj-$(CONFIG_SOC_AT91SAM9) += sam9_smc.o
|
||||
|
||||
# CPU-specific support
|
||||
|
@ -440,6 +440,11 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
|
||||
0, /* Advanced Interrupt Controller */
|
||||
};
|
||||
|
||||
static void __init at91sam9260_init_time(void)
|
||||
{
|
||||
at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
|
||||
}
|
||||
|
||||
AT91_SOC_START(at91sam9260)
|
||||
.map_io = at91sam9260_map_io,
|
||||
.default_irq_priority = at91sam9260_default_irq_priority,
|
||||
@ -449,4 +454,5 @@ AT91_SOC_START(at91sam9260)
|
||||
.register_clocks = at91sam9260_register_clocks,
|
||||
.register_devices = at91sam9260_register_devices,
|
||||
.init = at91sam9260_initialize,
|
||||
.init_time = at91sam9260_init_time,
|
||||
AT91_SOC_END
|
||||
|
@ -399,6 +399,11 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
|
||||
0, /* Advanced Interrupt Controller */
|
||||
};
|
||||
|
||||
static void __init at91sam9261_init_time(void)
|
||||
{
|
||||
at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
|
||||
}
|
||||
|
||||
AT91_SOC_START(at91sam9261)
|
||||
.map_io = at91sam9261_map_io,
|
||||
.default_irq_priority = at91sam9261_default_irq_priority,
|
||||
@ -408,4 +413,5 @@ AT91_SOC_START(at91sam9261)
|
||||
.register_clocks = at91sam9261_register_clocks,
|
||||
.register_devices = at91sam9261_register_devices,
|
||||
.init = at91sam9261_initialize,
|
||||
.init_time = at91sam9261_init_time,
|
||||
AT91_SOC_END
|
||||
|
@ -422,6 +422,11 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
|
||||
0, /* Advanced Interrupt Controller (IRQ1) */
|
||||
};
|
||||
|
||||
static void __init at91sam9263_init_time(void)
|
||||
{
|
||||
at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
|
||||
}
|
||||
|
||||
AT91_SOC_START(at91sam9263)
|
||||
.map_io = at91sam9263_map_io,
|
||||
.default_irq_priority = at91sam9263_default_irq_priority,
|
||||
@ -430,4 +435,5 @@ AT91_SOC_START(at91sam9263)
|
||||
.register_clocks = at91sam9263_register_clocks,
|
||||
.register_devices = at91sam9263_register_devices,
|
||||
.init = at91sam9263_initialize,
|
||||
.init_time = at91sam9263_init_time,
|
||||
AT91_SOC_END
|
||||
|
@ -1,294 +0,0 @@
|
||||
/*
|
||||
* at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x
|
||||
*
|
||||
* Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France
|
||||
* Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France
|
||||
* Converted to ClockSource/ClockEvents by David Brownell.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#include <asm/mach/time.h>
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#define AT91_PIT_MR 0x00 /* Mode Register */
|
||||
#define AT91_PIT_PITIEN (1 << 25) /* Timer Interrupt Enable */
|
||||
#define AT91_PIT_PITEN (1 << 24) /* Timer Enabled */
|
||||
#define AT91_PIT_PIV (0xfffff) /* Periodic Interval Value */
|
||||
|
||||
#define AT91_PIT_SR 0x04 /* Status Register */
|
||||
#define AT91_PIT_PITS (1 << 0) /* Timer Status */
|
||||
|
||||
#define AT91_PIT_PIVR 0x08 /* Periodic Interval Value Register */
|
||||
#define AT91_PIT_PIIR 0x0c /* Periodic Interval Image Register */
|
||||
#define AT91_PIT_PICNT (0xfff << 20) /* Interval Counter */
|
||||
#define AT91_PIT_CPIV (0xfffff) /* Inverval Value */
|
||||
|
||||
#define PIT_CPIV(x) ((x) & AT91_PIT_CPIV)
|
||||
#define PIT_PICNT(x) (((x) & AT91_PIT_PICNT) >> 20)
|
||||
|
||||
static u32 pit_cycle; /* write-once */
|
||||
static u32 pit_cnt; /* access only w/system irq blocked */
|
||||
static void __iomem *pit_base_addr __read_mostly;
|
||||
static struct clk *mck;
|
||||
|
||||
static inline unsigned int pit_read(unsigned int reg_offset)
|
||||
{
|
||||
return __raw_readl(pit_base_addr + reg_offset);
|
||||
}
|
||||
|
||||
static inline void pit_write(unsigned int reg_offset, unsigned long value)
|
||||
{
|
||||
__raw_writel(value, pit_base_addr + reg_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clocksource: just a monotonic counter of MCK/16 cycles.
|
||||
* We don't care whether or not PIT irqs are enabled.
|
||||
*/
|
||||
static cycle_t read_pit_clk(struct clocksource *cs)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 elapsed;
|
||||
u32 t;
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
elapsed = pit_cnt;
|
||||
t = pit_read(AT91_PIT_PIIR);
|
||||
raw_local_irq_restore(flags);
|
||||
|
||||
elapsed += PIT_PICNT(t) * pit_cycle;
|
||||
elapsed += PIT_CPIV(t);
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
static struct clocksource pit_clk = {
|
||||
.name = "pit",
|
||||
.rating = 175,
|
||||
.read = read_pit_clk,
|
||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16)
|
||||
*/
|
||||
static void
|
||||
pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
|
||||
{
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
/* update clocksource counter */
|
||||
pit_cnt += pit_cycle * PIT_PICNT(pit_read(AT91_PIT_PIVR));
|
||||
pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN
|
||||
| AT91_PIT_PITIEN);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
BUG();
|
||||
/* FALLTHROUGH */
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
/* disable irq, leaving the clocksource active */
|
||||
pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_RESUME:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void at91sam926x_pit_suspend(struct clock_event_device *cedev)
|
||||
{
|
||||
/* Disable timer */
|
||||
pit_write(AT91_PIT_MR, 0);
|
||||
}
|
||||
|
||||
static void at91sam926x_pit_reset(void)
|
||||
{
|
||||
/* Disable timer and irqs */
|
||||
pit_write(AT91_PIT_MR, 0);
|
||||
|
||||
/* Clear any pending interrupts, wait for PIT to stop counting */
|
||||
while (PIT_CPIV(pit_read(AT91_PIT_PIVR)) != 0)
|
||||
cpu_relax();
|
||||
|
||||
/* Start PIT but don't enable IRQ */
|
||||
pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
|
||||
}
|
||||
|
||||
static void at91sam926x_pit_resume(struct clock_event_device *cedev)
|
||||
{
|
||||
at91sam926x_pit_reset();
|
||||
}
|
||||
|
||||
static struct clock_event_device pit_clkevt = {
|
||||
.name = "pit",
|
||||
.features = CLOCK_EVT_FEAT_PERIODIC,
|
||||
.shift = 32,
|
||||
.rating = 100,
|
||||
.set_mode = pit_clkevt_mode,
|
||||
.suspend = at91sam926x_pit_suspend,
|
||||
.resume = at91sam926x_pit_resume,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* IRQ handler for the timer.
|
||||
*/
|
||||
static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
/*
|
||||
* irqs should be disabled here, but as the irq is shared they are only
|
||||
* guaranteed to be off if the timer irq is registered first.
|
||||
*/
|
||||
WARN_ON_ONCE(!irqs_disabled());
|
||||
|
||||
/* The PIT interrupt may be disabled, and is shared */
|
||||
if ((pit_clkevt.mode == CLOCK_EVT_MODE_PERIODIC)
|
||||
&& (pit_read(AT91_PIT_SR) & AT91_PIT_PITS)) {
|
||||
unsigned nr_ticks;
|
||||
|
||||
/* Get number of ticks performed before irq, and ack it */
|
||||
nr_ticks = PIT_PICNT(pit_read(AT91_PIT_PIVR));
|
||||
do {
|
||||
pit_cnt += pit_cycle;
|
||||
pit_clkevt.event_handler(&pit_clkevt);
|
||||
nr_ticks--;
|
||||
} while (nr_ticks);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static struct irqaction at91sam926x_pit_irq = {
|
||||
.name = "at91_tick",
|
||||
.flags = IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
|
||||
.handler = at91sam926x_pit_interrupt,
|
||||
.irq = NR_IRQS_LEGACY + AT91_ID_SYS,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id pit_timer_ids[] = {
|
||||
{ .compatible = "atmel,at91sam9260-pit" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int __init of_at91sam926x_pit_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
np = of_find_matching_node(NULL, pit_timer_ids);
|
||||
if (!np)
|
||||
goto err;
|
||||
|
||||
pit_base_addr = of_iomap(np, 0);
|
||||
if (!pit_base_addr)
|
||||
goto node_err;
|
||||
|
||||
mck = of_clk_get(np, 0);
|
||||
|
||||
/* Get the interrupts property */
|
||||
ret = irq_of_parse_and_map(np, 0);
|
||||
if (!ret) {
|
||||
pr_crit("AT91: PIT: Unable to get IRQ from DT\n");
|
||||
if (!IS_ERR(mck))
|
||||
clk_put(mck);
|
||||
goto ioremap_err;
|
||||
}
|
||||
at91sam926x_pit_irq.irq = ret;
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
return 0;
|
||||
|
||||
ioremap_err:
|
||||
iounmap(pit_base_addr);
|
||||
node_err:
|
||||
of_node_put(np);
|
||||
err:
|
||||
return -EINVAL;
|
||||
}
|
||||
#else
|
||||
static int __init of_at91sam926x_pit_init(void)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set up both clocksource and clockevent support.
|
||||
*/
|
||||
void __init at91sam926x_pit_init(void)
|
||||
{
|
||||
unsigned long pit_rate;
|
||||
unsigned bits;
|
||||
int ret;
|
||||
|
||||
mck = ERR_PTR(-ENOENT);
|
||||
|
||||
/* For device tree enabled device: initialize here */
|
||||
of_at91sam926x_pit_init();
|
||||
|
||||
/*
|
||||
* Use our actual MCK to figure out how many MCK/16 ticks per
|
||||
* 1/HZ period (instead of a compile-time constant LATCH).
|
||||
*/
|
||||
if (IS_ERR(mck))
|
||||
mck = clk_get(NULL, "mck");
|
||||
|
||||
if (IS_ERR(mck))
|
||||
panic("AT91: PIT: Unable to get mck clk\n");
|
||||
pit_rate = clk_get_rate(mck) / 16;
|
||||
pit_cycle = (pit_rate + HZ/2) / HZ;
|
||||
WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0);
|
||||
|
||||
/* Initialize and enable the timer */
|
||||
at91sam926x_pit_reset();
|
||||
|
||||
/*
|
||||
* Register clocksource. The high order bits of PIV are unused,
|
||||
* so this isn't a 32-bit counter unless we get clockevent irqs.
|
||||
*/
|
||||
bits = 12 /* PICNT */ + ilog2(pit_cycle) /* PIV */;
|
||||
pit_clk.mask = CLOCKSOURCE_MASK(bits);
|
||||
clocksource_register_hz(&pit_clk, pit_rate);
|
||||
|
||||
/* Set up irq handler */
|
||||
ret = setup_irq(at91sam926x_pit_irq.irq, &at91sam926x_pit_irq);
|
||||
if (ret)
|
||||
pr_crit("AT91: PIT: Unable to setup IRQ\n");
|
||||
|
||||
/* Set up and register clockevents */
|
||||
pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift);
|
||||
pit_clkevt.cpumask = cpumask_of(0);
|
||||
clockevents_register_device(&pit_clkevt);
|
||||
}
|
||||
|
||||
void __init at91sam926x_ioremap_pit(u32 addr)
|
||||
{
|
||||
#if defined(CONFIG_OF)
|
||||
struct device_node *np =
|
||||
of_find_matching_node(NULL, pit_timer_ids);
|
||||
|
||||
if (np) {
|
||||
of_node_put(np);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
pit_base_addr = ioremap(addr, 16);
|
||||
|
||||
if (!pit_base_addr)
|
||||
panic("Impossible to ioremap PIT\n");
|
||||
}
|
@ -477,6 +477,11 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
|
||||
0, /* Advanced Interrupt Controller (IRQ0) */
|
||||
};
|
||||
|
||||
static void __init at91sam9g45_init_time(void)
|
||||
{
|
||||
at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
|
||||
}
|
||||
|
||||
AT91_SOC_START(at91sam9g45)
|
||||
.map_io = at91sam9g45_map_io,
|
||||
.default_irq_priority = at91sam9g45_default_irq_priority,
|
||||
@ -485,4 +490,5 @@ AT91_SOC_START(at91sam9g45)
|
||||
.register_clocks = at91sam9g45_register_clocks,
|
||||
.register_devices = at91sam9g45_register_devices,
|
||||
.init = at91sam9g45_initialize,
|
||||
.init_time = at91sam9g45_init_time,
|
||||
AT91_SOC_END
|
||||
|
@ -410,6 +410,11 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
|
||||
0, /* Advanced Interrupt Controller */
|
||||
};
|
||||
|
||||
static void __init at91sam9rl_init_time(void)
|
||||
{
|
||||
at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
|
||||
}
|
||||
|
||||
AT91_SOC_START(at91sam9rl)
|
||||
.map_io = at91sam9rl_map_io,
|
||||
.default_irq_priority = at91sam9rl_default_irq_priority,
|
||||
@ -420,4 +425,5 @@ AT91_SOC_START(at91sam9rl)
|
||||
#endif
|
||||
.register_devices = at91sam9rl_register_devices,
|
||||
.init = at91sam9rl_initialize,
|
||||
.init_time = at91sam9rl_init_time,
|
||||
AT91_SOC_END
|
||||
|
@ -213,7 +213,7 @@ static void __init afeb9260_board_init(void)
|
||||
|
||||
MACHINE_START(AFEB9260, "Custom afeb9260 board")
|
||||
/* Maintainer: Sergey Lapin <slapin@ossfans.org> */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = afeb9260_init_early,
|
||||
|
@ -190,7 +190,7 @@ static void __init cam60_board_init(void)
|
||||
|
||||
MACHINE_START(CAM60, "KwikByte CAM60")
|
||||
/* Maintainer: KwikByte */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = cam60_init_early,
|
||||
|
@ -377,7 +377,7 @@ MACHINE_START(CPUAT9260, "Eukrea CPU9260")
|
||||
MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
|
||||
#endif
|
||||
/* Maintainer: Eric Benard - EUKREA Electromatique */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = cpu9krea_init_early,
|
||||
|
@ -25,15 +25,6 @@
|
||||
#include "board.h"
|
||||
#include "generic.h"
|
||||
|
||||
|
||||
static void __init sam9_dt_timer_init(void)
|
||||
{
|
||||
#if defined(CONFIG_COMMON_CLK)
|
||||
of_clk_init(NULL);
|
||||
#endif
|
||||
at91sam926x_pit_init();
|
||||
}
|
||||
|
||||
static const char *at91_dt_board_compat[] __initdata = {
|
||||
"atmel,at91sam9",
|
||||
NULL
|
||||
@ -41,7 +32,6 @@ static const char *at91_dt_board_compat[] __initdata = {
|
||||
|
||||
DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = sam9_dt_timer_init,
|
||||
.map_io = at91_map_io,
|
||||
.init_early = at91_dt_initialize,
|
||||
.dt_compat = at91_dt_board_compat,
|
||||
|
@ -27,14 +27,6 @@
|
||||
#include "at91_aic.h"
|
||||
#include "generic.h"
|
||||
|
||||
static void __init sama5_dt_timer_init(void)
|
||||
{
|
||||
#if defined(CONFIG_COMMON_CLK)
|
||||
of_clk_init(NULL);
|
||||
#endif
|
||||
at91sam926x_pit_init();
|
||||
}
|
||||
|
||||
static int ksz9021rn_phy_fixup(struct phy_device *phy)
|
||||
{
|
||||
int value;
|
||||
@ -69,7 +61,6 @@ static const char *sama5_dt_board_compat[] __initdata = {
|
||||
|
||||
DT_MACHINE_START(sama5_dt, "Atmel SAMA5 (Device Tree)")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = sama5_dt_timer_init,
|
||||
.map_io = at91_map_io,
|
||||
.init_early = at91_dt_initialize,
|
||||
.init_machine = sama5_dt_device_init,
|
||||
|
@ -162,7 +162,7 @@ static void __init flexibity_board_init(void)
|
||||
|
||||
MACHINE_START(FLEXIBITY, "Flexibity Connect")
|
||||
/* Maintainer: Maxim Osipov */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = flexibity_init_early,
|
||||
|
@ -263,7 +263,7 @@ static void __init foxg20_board_init(void)
|
||||
|
||||
MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
|
||||
/* Maintainer: Sergio Tanzilli */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = foxg20_init_early,
|
||||
|
@ -576,7 +576,7 @@ static void __init gsia18s_board_init(void)
|
||||
}
|
||||
|
||||
MACHINE_START(GSIA18S, "GS_IA18_S")
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = gsia18s_init_early,
|
||||
|
@ -219,7 +219,7 @@ static void __init pcontrol_g20_board_init(void)
|
||||
|
||||
MACHINE_START(PCONTROL_G20, "PControl G20")
|
||||
/* Maintainer: pgsellmann@portner-elektronik.at */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = pcontrol_g20_init_early,
|
||||
|
@ -221,7 +221,7 @@ static void __init ek_board_init(void)
|
||||
|
||||
MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
|
||||
/* Maintainer: Olimex */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = ek_init_early,
|
||||
|
@ -345,7 +345,7 @@ static void __init ek_board_init(void)
|
||||
|
||||
MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = ek_init_early,
|
||||
|
@ -604,7 +604,7 @@ static void __init ek_board_init(void)
|
||||
|
||||
MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = ek_init_early,
|
||||
@ -614,7 +614,7 @@ MACHINE_END
|
||||
|
||||
MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = ek_init_early,
|
||||
|
@ -484,7 +484,7 @@ static void __init ek_board_init(void)
|
||||
|
||||
MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = ek_init_early,
|
||||
|
@ -410,7 +410,7 @@ static void __init ek_board_init(void)
|
||||
|
||||
MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = ek_init_early,
|
||||
@ -420,7 +420,7 @@ MACHINE_END
|
||||
|
||||
MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = ek_init_early,
|
||||
|
@ -518,7 +518,7 @@ static void __init ek_board_init(void)
|
||||
|
||||
MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = ek_init_early,
|
||||
|
@ -324,7 +324,7 @@ static void __init ek_board_init(void)
|
||||
|
||||
MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
|
||||
/* Maintainer: Atmel */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = ek_init_early,
|
||||
|
@ -180,7 +180,7 @@ static void __init snapper9260_board_init(void)
|
||||
}
|
||||
|
||||
MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = snapper9260_init_early,
|
||||
|
@ -275,7 +275,7 @@ static void __init stamp9g20evb_board_init(void)
|
||||
|
||||
MACHINE_START(PORTUXG20, "taskit PortuxG20")
|
||||
/* Maintainer: taskit GmbH */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = stamp9g20_init_early,
|
||||
@ -285,7 +285,7 @@ MACHINE_END
|
||||
|
||||
MACHINE_START(STAMP9G20, "taskit Stamp9G20")
|
||||
/* Maintainer: taskit GmbH */
|
||||
.init_time = at91sam926x_pit_init,
|
||||
.init_time = at91_init_time,
|
||||
.map_io = at91_map_io,
|
||||
.handle_irq = at91_aic_handle_irq,
|
||||
.init_early = stamp9g20_init_early,
|
||||
|
@ -8,6 +8,9 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _AT91_GENERIC_H
|
||||
#define _AT91_GENERIC_H
|
||||
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/reboot.h>
|
||||
@ -41,10 +44,11 @@ extern void __init at91_sysirq_mask_rtt(u32 rtt_base);
|
||||
extern void __init at91_register_devices(void);
|
||||
|
||||
/* Timer */
|
||||
extern void __init at91_init_time(void);
|
||||
extern void at91rm9200_ioremap_st(u32 addr);
|
||||
extern void at91rm9200_timer_init(void);
|
||||
extern void at91sam926x_ioremap_pit(u32 addr);
|
||||
extern void at91sam926x_pit_init(void);
|
||||
extern void at91sam926x_pit_init(int irq);
|
||||
extern void at91x40_timer_init(void);
|
||||
|
||||
/* Clocks */
|
||||
@ -84,3 +88,5 @@ extern int __init at91_gpio_of_irq_setup(struct device_node *node,
|
||||
struct device_node *parent);
|
||||
|
||||
extern u32 at91_get_extern_irq(void);
|
||||
|
||||
#endif /* _AT91_GENERIC_H */
|
||||
|
@ -416,3 +416,8 @@ void __init at91_register_devices(void)
|
||||
{
|
||||
at91_boot_soc.register_devices();
|
||||
}
|
||||
|
||||
void __init at91_init_time(void)
|
||||
{
|
||||
at91_boot_soc.init_time();
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ struct at91_init_soc {
|
||||
void (*register_clocks)(void);
|
||||
void (*register_devices)(void);
|
||||
void (*init)(void);
|
||||
void (*init_time)(void);
|
||||
};
|
||||
|
||||
extern struct at91_init_soc at91_boot_soc;
|
||||
|
@ -120,6 +120,10 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
|
||||
help
|
||||
Use ARM global timer clock source as sched_clock
|
||||
|
||||
config ATMEL_PIT
|
||||
select CLKSRC_OF if OF
|
||||
def_bool SOC_AT91SAM9 || SOC_SAMA5
|
||||
|
||||
config CLKSRC_METAG_GENERIC
|
||||
def_bool y if METAG
|
||||
help
|
||||
|
@ -1,4 +1,5 @@
|
||||
obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o
|
||||
obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o
|
||||
obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
|
||||
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
|
||||
obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
|
||||
|
296
drivers/clocksource/timer-atmel-pit.c
Normal file
296
drivers/clocksource/timer-atmel-pit.c
Normal file
@ -0,0 +1,296 @@
|
||||
/*
|
||||
* at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x
|
||||
*
|
||||
* Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France
|
||||
* Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France
|
||||
* Converted to ClockSource/ClockEvents by David Brownell.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "AT91: PIT: " fmt
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define AT91_PIT_MR 0x00 /* Mode Register */
|
||||
#define AT91_PIT_PITIEN BIT(25) /* Timer Interrupt Enable */
|
||||
#define AT91_PIT_PITEN BIT(24) /* Timer Enabled */
|
||||
#define AT91_PIT_PIV GENMASK(19, 0) /* Periodic Interval Value */
|
||||
|
||||
#define AT91_PIT_SR 0x04 /* Status Register */
|
||||
#define AT91_PIT_PITS BIT(0) /* Timer Status */
|
||||
|
||||
#define AT91_PIT_PIVR 0x08 /* Periodic Interval Value Register */
|
||||
#define AT91_PIT_PIIR 0x0c /* Periodic Interval Image Register */
|
||||
#define AT91_PIT_PICNT GENMASK(31, 20) /* Interval Counter */
|
||||
#define AT91_PIT_CPIV GENMASK(19, 0) /* Inverval Value */
|
||||
|
||||
#define PIT_CPIV(x) ((x) & AT91_PIT_CPIV)
|
||||
#define PIT_PICNT(x) (((x) & AT91_PIT_PICNT) >> 20)
|
||||
|
||||
struct pit_data {
|
||||
struct clock_event_device clkevt;
|
||||
struct clocksource clksrc;
|
||||
|
||||
void __iomem *base;
|
||||
u32 cycle;
|
||||
u32 cnt;
|
||||
unsigned int irq;
|
||||
struct clk *mck;
|
||||
};
|
||||
|
||||
static inline struct pit_data *clksrc_to_pit_data(struct clocksource *clksrc)
|
||||
{
|
||||
return container_of(clksrc, struct pit_data, clksrc);
|
||||
}
|
||||
|
||||
static inline struct pit_data *clkevt_to_pit_data(struct clock_event_device *clkevt)
|
||||
{
|
||||
return container_of(clkevt, struct pit_data, clkevt);
|
||||
}
|
||||
|
||||
static inline unsigned int pit_read(void __iomem *base, unsigned int reg_offset)
|
||||
{
|
||||
return __raw_readl(base + reg_offset);
|
||||
}
|
||||
|
||||
static inline void pit_write(void __iomem *base, unsigned int reg_offset, unsigned long value)
|
||||
{
|
||||
__raw_writel(value, base + reg_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clocksource: just a monotonic counter of MCK/16 cycles.
|
||||
* We don't care whether or not PIT irqs are enabled.
|
||||
*/
|
||||
static cycle_t read_pit_clk(struct clocksource *cs)
|
||||
{
|
||||
struct pit_data *data = clksrc_to_pit_data(cs);
|
||||
unsigned long flags;
|
||||
u32 elapsed;
|
||||
u32 t;
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
elapsed = data->cnt;
|
||||
t = pit_read(data->base, AT91_PIT_PIIR);
|
||||
raw_local_irq_restore(flags);
|
||||
|
||||
elapsed += PIT_PICNT(t) * data->cycle;
|
||||
elapsed += PIT_CPIV(t);
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16)
|
||||
*/
|
||||
static void
|
||||
pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
|
||||
{
|
||||
struct pit_data *data = clkevt_to_pit_data(dev);
|
||||
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
/* update clocksource counter */
|
||||
data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR));
|
||||
pit_write(data->base, AT91_PIT_MR,
|
||||
(data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
BUG();
|
||||
/* FALLTHROUGH */
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
/* disable irq, leaving the clocksource active */
|
||||
pit_write(data->base, AT91_PIT_MR,
|
||||
(data->cycle - 1) | AT91_PIT_PITEN);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_RESUME:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void at91sam926x_pit_suspend(struct clock_event_device *cedev)
|
||||
{
|
||||
struct pit_data *data = clkevt_to_pit_data(cedev);
|
||||
|
||||
/* Disable timer */
|
||||
pit_write(data->base, AT91_PIT_MR, 0);
|
||||
}
|
||||
|
||||
static void at91sam926x_pit_reset(struct pit_data *data)
|
||||
{
|
||||
/* Disable timer and irqs */
|
||||
pit_write(data->base, AT91_PIT_MR, 0);
|
||||
|
||||
/* Clear any pending interrupts, wait for PIT to stop counting */
|
||||
while (PIT_CPIV(pit_read(data->base, AT91_PIT_PIVR)) != 0)
|
||||
cpu_relax();
|
||||
|
||||
/* Start PIT but don't enable IRQ */
|
||||
pit_write(data->base, AT91_PIT_MR,
|
||||
(data->cycle - 1) | AT91_PIT_PITEN);
|
||||
}
|
||||
|
||||
static void at91sam926x_pit_resume(struct clock_event_device *cedev)
|
||||
{
|
||||
struct pit_data *data = clkevt_to_pit_data(cedev);
|
||||
|
||||
at91sam926x_pit_reset(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQ handler for the timer.
|
||||
*/
|
||||
static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct pit_data *data = dev_id;
|
||||
|
||||
/*
|
||||
* irqs should be disabled here, but as the irq is shared they are only
|
||||
* guaranteed to be off if the timer irq is registered first.
|
||||
*/
|
||||
WARN_ON_ONCE(!irqs_disabled());
|
||||
|
||||
/* The PIT interrupt may be disabled, and is shared */
|
||||
if ((data->clkevt.mode == CLOCK_EVT_MODE_PERIODIC) &&
|
||||
(pit_read(data->base, AT91_PIT_SR) & AT91_PIT_PITS)) {
|
||||
unsigned nr_ticks;
|
||||
|
||||
/* Get number of ticks performed before irq, and ack it */
|
||||
nr_ticks = PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR));
|
||||
do {
|
||||
data->cnt += data->cycle;
|
||||
data->clkevt.event_handler(&data->clkevt);
|
||||
nr_ticks--;
|
||||
} while (nr_ticks);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up both clocksource and clockevent support.
|
||||
*/
|
||||
static void __init at91sam926x_pit_common_init(struct pit_data *data)
|
||||
{
|
||||
unsigned long pit_rate;
|
||||
unsigned bits;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Use our actual MCK to figure out how many MCK/16 ticks per
|
||||
* 1/HZ period (instead of a compile-time constant LATCH).
|
||||
*/
|
||||
pit_rate = clk_get_rate(data->mck) / 16;
|
||||
data->cycle = DIV_ROUND_CLOSEST(pit_rate, HZ);
|
||||
WARN_ON(((data->cycle - 1) & ~AT91_PIT_PIV) != 0);
|
||||
|
||||
/* Initialize and enable the timer */
|
||||
at91sam926x_pit_reset(data);
|
||||
|
||||
/*
|
||||
* Register clocksource. The high order bits of PIV are unused,
|
||||
* so this isn't a 32-bit counter unless we get clockevent irqs.
|
||||
*/
|
||||
bits = 12 /* PICNT */ + ilog2(data->cycle) /* PIV */;
|
||||
data->clksrc.mask = CLOCKSOURCE_MASK(bits);
|
||||
data->clksrc.name = "pit";
|
||||
data->clksrc.rating = 175;
|
||||
data->clksrc.read = read_pit_clk,
|
||||
data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||
clocksource_register_hz(&data->clksrc, pit_rate);
|
||||
|
||||
/* Set up irq handler */
|
||||
ret = request_irq(data->irq, at91sam926x_pit_interrupt,
|
||||
IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
|
||||
"at91_tick", data);
|
||||
if (ret)
|
||||
panic(pr_fmt("Unable to setup IRQ\n"));
|
||||
|
||||
/* Set up and register clockevents */
|
||||
data->clkevt.name = "pit";
|
||||
data->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
|
||||
data->clkevt.shift = 32;
|
||||
data->clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, data->clkevt.shift);
|
||||
data->clkevt.rating = 100;
|
||||
data->clkevt.cpumask = cpumask_of(0);
|
||||
|
||||
data->clkevt.set_mode = pit_clkevt_mode;
|
||||
data->clkevt.resume = at91sam926x_pit_resume;
|
||||
data->clkevt.suspend = at91sam926x_pit_suspend;
|
||||
clockevents_register_device(&data->clkevt);
|
||||
}
|
||||
|
||||
static void __init at91sam926x_pit_dt_init(struct device_node *node)
|
||||
{
|
||||
struct pit_data *data;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
panic(pr_fmt("Unable to allocate memory\n"));
|
||||
|
||||
data->base = of_iomap(node, 0);
|
||||
if (!data->base)
|
||||
panic(pr_fmt("Could not map PIT address\n"));
|
||||
|
||||
data->mck = of_clk_get(node, 0);
|
||||
if (IS_ERR(data->mck))
|
||||
/* Fallback on clkdev for !CCF-based boards */
|
||||
data->mck = clk_get(NULL, "mck");
|
||||
|
||||
if (IS_ERR(data->mck))
|
||||
panic(pr_fmt("Unable to get mck clk\n"));
|
||||
|
||||
/* Get the interrupts property */
|
||||
data->irq = irq_of_parse_and_map(node, 0);
|
||||
if (!data->irq)
|
||||
panic(pr_fmt("Unable to get IRQ from DT\n"));
|
||||
|
||||
at91sam926x_pit_common_init(data);
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit",
|
||||
at91sam926x_pit_dt_init);
|
||||
|
||||
static void __iomem *pit_base_addr;
|
||||
|
||||
void __init at91sam926x_pit_init(int irq)
|
||||
{
|
||||
struct pit_data *data;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
panic(pr_fmt("Unable to allocate memory\n"));
|
||||
|
||||
data->base = pit_base_addr;
|
||||
|
||||
data->mck = clk_get(NULL, "mck");
|
||||
if (IS_ERR(data->mck))
|
||||
panic(pr_fmt("Unable to get mck clk\n"));
|
||||
|
||||
data->irq = irq;
|
||||
|
||||
at91sam926x_pit_common_init(data);
|
||||
}
|
||||
|
||||
void __init at91sam926x_ioremap_pit(u32 addr)
|
||||
{
|
||||
if (of_have_populated_dt())
|
||||
return;
|
||||
|
||||
pit_base_addr = ioremap(addr, 16);
|
||||
|
||||
if (!pit_base_addr)
|
||||
panic(pr_fmt("Impossible to ioremap PIT\n"));
|
||||
}
|
Loading…
Reference in New Issue
Block a user