9
0
Fork 0
barebox/arch/arm/mach-tegra/tegra20-timer.c

110 lines
2.5 KiB
C

/*
* Copyright (C) 2013 Lucas Stach <l.stach@pengutronix.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file
* @brief Device driver for the Tegra 20 timer, which exposes a clocksource.
*/
#include <common.h>
#include <clock.h>
#include <init.h>
#include <io.h>
#include <linux/clk.h>
#include <mach/lowlevel.h>
/* register definitions */
#define TIMERUS_CNTR_1US 0x10
#define TIMERUS_USEC_CFG 0x14
static void __iomem *timer_base;
static uint64_t tegra20_timer_cs_read(void)
{
return readl(timer_base + TIMERUS_CNTR_1US);
}
static struct clocksource cs = {
.read = tegra20_timer_cs_read,
.mask = CLOCKSOURCE_MASK(32),
};
static int tegra20_timer_probe(struct device_d *dev)
{
u32 reg;
/* use only one timer */
if (timer_base)
return -EBUSY;
timer_base = dev_request_mem_region(dev, 0);
if (!timer_base) {
dev_err(dev, "could not get memory region\n");
return -ENODEV;
}
/*
* calibrate timer to run at 1MHz
* TIMERUS_USEC_CFG selects the scale down factor with bits [0:7]
* representing the divisor and bits [8:15] representing the dividend
* each in n+1 form.
*/
switch (tegra_get_osc_clock()) {
case 12000000:
reg = 0x000b;
break;
case 13000000:
reg = 0x000c;
break;
case 19200000:
reg = 0x045f;
break;
case 26000000:
reg = 0x0019;
break;
default:
reg = 0;
dev_warn(dev, "unknown timer clock rate\n");
break;
}
writel(reg, timer_base + TIMERUS_USEC_CFG);
cs.mult = clocksource_hz2mult(1000000, cs.shift);
init_clock(&cs);
return 0;
}
static __maybe_unused struct of_device_id tegra20_timer_dt_ids[] = {
{
.compatible = "nvidia,tegra20-timer",
}, {
/* sentinel */
}
};
static struct driver_d tegra20_timer_driver = {
.probe = tegra20_timer_probe,
.name = "tegra20-timer",
.of_compatible = DRV_OF_COMPAT(tegra20_timer_dt_ids),
};
static int tegra20_timer_init(void)
{
return platform_driver_register(&tegra20_timer_driver);
}
core_initcall(tegra20_timer_init);