mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
Merge branch 'depends/cleanup' into next/drivers
* depends/cleanup: (375 commits) ARM: at91: fix board-rm9200-dt after sys_timer conversion clocksource: use clockevents_config_and_register() where possible ARM: use clockevents_config_and_register() where possible clockevents: export clockevents_config_and_register for module use timer: vt8500: Move timer code to drivers/clocksource irqchip: Move ARM vic.h to include/linux/irqchip/arm-vic.h ARM: picoxcell: use common irqchip_init function ARM: spear: use common irqchip_init function irqchip: Move ARM VIC to drivers/irqchip ARM: samsung: remove unused tick.h ARM: remove unneeded vic.h includes ARM: remove mach .handle_irq for VIC users ARM: VIC: set handle_arch_irq in VIC initialization ARM: VIC: shrink down vic.h irqchip: Move ARM gic.h to include/linux/irqchip/arm-gic.h ARM: use common irqchip_init for GIC init irqchip: Move ARM GIC to drivers/irqchip ARM: remove mach .handle_irq for GIC users ARM: GIC: set handle_arch_irq in GIC initialization ARM: GIC: remove direct use of gic_raise_softirq ...
This commit is contained in:
commit
7bcdd8d5e3
1999 changed files with 9351 additions and 10186 deletions
|
|
@ -1,3 +1,6 @@
|
|||
config CLKSRC_OF
|
||||
bool
|
||||
|
||||
config CLKSRC_I8253
|
||||
bool
|
||||
|
||||
|
|
@ -25,6 +28,9 @@ config ARMADA_370_XP_TIMER
|
|||
config SUNXI_TIMER
|
||||
bool
|
||||
|
||||
config VT8500_TIMER
|
||||
bool
|
||||
|
||||
config CLKSRC_NOMADIK_MTU
|
||||
bool
|
||||
depends on (ARCH_NOMADIK || ARCH_U8500)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o
|
||||
obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
|
||||
obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
|
||||
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
|
||||
|
|
@ -16,5 +17,6 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
|
|||
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
|
||||
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
|
||||
obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
|
||||
obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
|
||||
|
||||
obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ static struct clocksource clocksource_acpi_pm = {
|
|||
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static int __devinitdata acpi_pm_good;
|
||||
static int acpi_pm_good;
|
||||
static int __init acpi_pm_good_setup(char *__str)
|
||||
{
|
||||
acpi_pm_good = 1;
|
||||
|
|
@ -102,7 +102,7 @@ static inline void acpi_pm_need_workaround(void)
|
|||
* incorrect when read). As a result, the ACPI free running count up
|
||||
* timer specification is violated due to erroneous reads.
|
||||
*/
|
||||
static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev)
|
||||
static void acpi_pm_check_blacklist(struct pci_dev *dev)
|
||||
{
|
||||
if (acpi_pm_good)
|
||||
return;
|
||||
|
|
@ -120,7 +120,7 @@ static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev)
|
|||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
|
||||
acpi_pm_check_blacklist);
|
||||
|
||||
static void __devinit acpi_pm_check_graylist(struct pci_dev *dev)
|
||||
static void acpi_pm_check_graylist(struct pci_dev *dev)
|
||||
{
|
||||
if (acpi_pm_good)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ static struct of_device_id bcm2835_time_match[] __initconst = {
|
|||
{}
|
||||
};
|
||||
|
||||
static void __init bcm2835_time_init(void)
|
||||
void __init bcm2835_timer_init(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
void __iomem *base;
|
||||
|
|
@ -155,7 +155,3 @@ static void __init bcm2835_time_init(void)
|
|||
|
||||
pr_info("bcm2835: system timer (irq = %d)\n", irq);
|
||||
}
|
||||
|
||||
struct sys_timer bcm2835_timer = {
|
||||
.init = bcm2835_time_init,
|
||||
};
|
||||
|
|
|
|||
35
drivers/clocksource/clksrc-of.c
Normal file
35
drivers/clocksource/clksrc-of.c
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
extern struct of_device_id __clksrc_of_table[];
|
||||
|
||||
static const struct of_device_id __clksrc_of_table_sentinel
|
||||
__used __section(__clksrc_of_table_end);
|
||||
|
||||
void __init clocksource_of_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
const struct of_device_id *match;
|
||||
void (*init_func)(void);
|
||||
|
||||
for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
|
||||
init_func = match->data;
|
||||
init_func();
|
||||
}
|
||||
}
|
||||
|
|
@ -100,7 +100,6 @@ static struct clock_event_device cs5535_clockevent = {
|
|||
.set_mode = mfgpt_set_mode,
|
||||
.set_next_event = mfgpt_next_event,
|
||||
.rating = 250,
|
||||
.shift = 32
|
||||
};
|
||||
|
||||
static irqreturn_t mfgpt_tick(int irq, void *dev_id)
|
||||
|
|
@ -169,17 +168,11 @@ static int __init cs5535_mfgpt_init(void)
|
|||
cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, val);
|
||||
|
||||
/* Set up the clock event */
|
||||
cs5535_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC,
|
||||
cs5535_clockevent.shift);
|
||||
cs5535_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
|
||||
&cs5535_clockevent);
|
||||
cs5535_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE,
|
||||
&cs5535_clockevent);
|
||||
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": Registering MFGPT timer as a clock event, using IRQ %d\n",
|
||||
timer_irq);
|
||||
clockevents_register_device(&cs5535_clockevent);
|
||||
clockevents_config_and_register(&cs5535_clockevent, MFGPT_HZ,
|
||||
0xF, 0xFFFE);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ static const struct of_device_id osctimer_ids[] __initconst = {
|
|||
{},
|
||||
};
|
||||
|
||||
static void __init timer_init(void)
|
||||
void __init dw_apb_timer_init(void)
|
||||
{
|
||||
struct device_node *event_timer, *source_timer;
|
||||
|
||||
|
|
@ -125,7 +125,3 @@ static void __init timer_init(void)
|
|||
|
||||
init_sched_clock();
|
||||
}
|
||||
|
||||
struct sys_timer dw_apb_timer = {
|
||||
.init = timer_init,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ static void em_sti_register_clockevent(struct em_sti_priv *p)
|
|||
clockevents_config_and_register(ced, 1, 2, 0xffffffff);
|
||||
}
|
||||
|
||||
static int __devinit em_sti_probe(struct platform_device *pdev)
|
||||
static int em_sti_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct em_sti_priv *p;
|
||||
struct resource *res;
|
||||
|
|
@ -379,12 +379,12 @@ err0:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit em_sti_remove(struct platform_device *pdev)
|
||||
static int em_sti_remove(struct platform_device *pdev)
|
||||
{
|
||||
return -EBUSY; /* cannot unregister clockevent and clocksource */
|
||||
}
|
||||
|
||||
static const struct of_device_id em_sti_dt_ids[] __devinitconst = {
|
||||
static const struct of_device_id em_sti_dt_ids[] = {
|
||||
{ .compatible = "renesas,em-sti", },
|
||||
{},
|
||||
};
|
||||
|
|
@ -392,7 +392,7 @@ MODULE_DEVICE_TABLE(of, em_sti_dt_ids);
|
|||
|
||||
static struct platform_driver em_sti_device_driver = {
|
||||
.probe = em_sti_probe,
|
||||
.remove = __devexit_p(em_sti_remove),
|
||||
.remove = em_sti_remove,
|
||||
.driver = {
|
||||
.name = "em_sti",
|
||||
.of_match_table = em_sti_dt_ids,
|
||||
|
|
|
|||
|
|
@ -141,12 +141,32 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode,
|
|||
}
|
||||
}
|
||||
|
||||
void nmdk_clksrc_reset(void)
|
||||
{
|
||||
/* Disable */
|
||||
writel(0, mtu_base + MTU_CR(0));
|
||||
|
||||
/* ClockSource: configure load and background-load, and fire it up */
|
||||
writel(nmdk_cycle, mtu_base + MTU_LR(0));
|
||||
writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
|
||||
|
||||
writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA,
|
||||
mtu_base + MTU_CR(0));
|
||||
}
|
||||
|
||||
static void nmdk_clkevt_resume(struct clock_event_device *cedev)
|
||||
{
|
||||
nmdk_clkevt_reset();
|
||||
nmdk_clksrc_reset();
|
||||
}
|
||||
|
||||
static struct clock_event_device nmdk_clkevt = {
|
||||
.name = "mtu_1",
|
||||
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
|
||||
.rating = 200,
|
||||
.set_mode = nmdk_clkevt_mode,
|
||||
.set_next_event = nmdk_clkevt_next,
|
||||
.resume = nmdk_clkevt_resume,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -168,19 +188,6 @@ static struct irqaction nmdk_timer_irq = {
|
|||
.dev_id = &nmdk_clkevt,
|
||||
};
|
||||
|
||||
void nmdk_clksrc_reset(void)
|
||||
{
|
||||
/* Disable */
|
||||
writel(0, mtu_base + MTU_CR(0));
|
||||
|
||||
/* ClockSource: configure load and background-load, and fire it up */
|
||||
writel(nmdk_cycle, mtu_base + MTU_LR(0));
|
||||
writel(nmdk_cycle, mtu_base + MTU_BGLR(0));
|
||||
|
||||
writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA,
|
||||
mtu_base + MTU_CR(0));
|
||||
}
|
||||
|
||||
void __init nmdk_timer_init(void __iomem *base, int irq)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
|
|
|||
|
|
@ -726,7 +726,7 @@ err0:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit sh_cmt_probe(struct platform_device *pdev)
|
||||
static int sh_cmt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sh_cmt_priv *p = platform_get_drvdata(pdev);
|
||||
struct sh_timer_config *cfg = pdev->dev.platform_data;
|
||||
|
|
@ -767,14 +767,14 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit sh_cmt_remove(struct platform_device *pdev)
|
||||
static int sh_cmt_remove(struct platform_device *pdev)
|
||||
{
|
||||
return -EBUSY; /* cannot unregister clockevent and clocksource */
|
||||
}
|
||||
|
||||
static struct platform_driver sh_cmt_device_driver = {
|
||||
.probe = sh_cmt_probe,
|
||||
.remove = __devexit_p(sh_cmt_remove),
|
||||
.remove = sh_cmt_remove,
|
||||
.driver = {
|
||||
.name = "sh_cmt",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -321,7 +321,7 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit sh_mtu2_probe(struct platform_device *pdev)
|
||||
static int sh_mtu2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
|
||||
struct sh_timer_config *cfg = pdev->dev.platform_data;
|
||||
|
|
@ -362,14 +362,14 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit sh_mtu2_remove(struct platform_device *pdev)
|
||||
static int sh_mtu2_remove(struct platform_device *pdev)
|
||||
{
|
||||
return -EBUSY; /* cannot unregister clockevent */
|
||||
}
|
||||
|
||||
static struct platform_driver sh_mtu2_device_driver = {
|
||||
.probe = sh_mtu2_probe,
|
||||
.remove = __devexit_p(sh_mtu2_remove),
|
||||
.remove = sh_mtu2_remove,
|
||||
.driver = {
|
||||
.name = "sh_mtu2",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -484,7 +484,7 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit sh_tmu_probe(struct platform_device *pdev)
|
||||
static int sh_tmu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sh_tmu_priv *p = platform_get_drvdata(pdev);
|
||||
struct sh_timer_config *cfg = pdev->dev.platform_data;
|
||||
|
|
@ -525,14 +525,14 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit sh_tmu_remove(struct platform_device *pdev)
|
||||
static int sh_tmu_remove(struct platform_device *pdev)
|
||||
{
|
||||
return -EBUSY; /* cannot unregister clockevent and clocksource */
|
||||
}
|
||||
|
||||
static struct platform_driver sh_tmu_device_driver = {
|
||||
.probe = sh_tmu_probe,
|
||||
.remove = __devexit_p(sh_tmu_remove),
|
||||
.remove = sh_tmu_remove,
|
||||
.driver = {
|
||||
.name = "sh_tmu",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ static int sunxi_clkevt_next_event(unsigned long evt,
|
|||
|
||||
static struct clock_event_device sunxi_clockevent = {
|
||||
.name = "sunxi_tick",
|
||||
.shift = 32,
|
||||
.rating = 300,
|
||||
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
||||
.set_mode = sunxi_clkevt_mode,
|
||||
|
|
@ -104,7 +103,7 @@ static struct of_device_id sunxi_timer_dt_ids[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static void __init sunxi_timer_init(void)
|
||||
void __init sunxi_timer_init(void)
|
||||
{
|
||||
struct device_node *node;
|
||||
unsigned long rate = 0;
|
||||
|
|
@ -154,18 +153,8 @@ static void __init sunxi_timer_init(void)
|
|||
val = readl(timer_base + TIMER_CTL_REG);
|
||||
writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG);
|
||||
|
||||
sunxi_clockevent.mult = div_sc(rate / TIMER_SCAL,
|
||||
NSEC_PER_SEC,
|
||||
sunxi_clockevent.shift);
|
||||
sunxi_clockevent.max_delta_ns = clockevent_delta2ns(0xff,
|
||||
&sunxi_clockevent);
|
||||
sunxi_clockevent.min_delta_ns = clockevent_delta2ns(0x1,
|
||||
&sunxi_clockevent);
|
||||
sunxi_clockevent.cpumask = cpumask_of(0);
|
||||
|
||||
clockevents_register_device(&sunxi_clockevent);
|
||||
clockevents_config_and_register(&sunxi_clockevent, rate / TIMER_SCAL,
|
||||
0x1, 0xff);
|
||||
}
|
||||
|
||||
struct sys_timer sunxi_timer = {
|
||||
.init = sunxi_timer_init,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -157,7 +157,6 @@ static struct tc_clkevt_device clkevt = {
|
|||
.name = "tc_clkevt",
|
||||
.features = CLOCK_EVT_FEAT_PERIODIC
|
||||
| CLOCK_EVT_FEAT_ONESHOT,
|
||||
.shift = 32,
|
||||
/* Should be lower than at91rm9200's system timer */
|
||||
.rating = 125,
|
||||
.set_next_event = tc_next_event,
|
||||
|
|
@ -196,13 +195,9 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
|
|||
|
||||
timer_clock = clk32k_divisor_idx;
|
||||
|
||||
clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift);
|
||||
clkevt.clkevt.max_delta_ns
|
||||
= clockevent_delta2ns(0xffff, &clkevt.clkevt);
|
||||
clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1;
|
||||
clkevt.clkevt.cpumask = cpumask_of(0);
|
||||
|
||||
clockevents_register_device(&clkevt.clkevt);
|
||||
clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff);
|
||||
|
||||
setup_irq(irq, &tc_irqaction);
|
||||
}
|
||||
|
|
|
|||
179
drivers/clocksource/vt8500_timer.c
Normal file
179
drivers/clocksource/vt8500_timer.c
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* arch/arm/mach-vt8500/timer.c
|
||||
*
|
||||
* Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
|
||||
* Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed in the hope that 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is copied and modified from the original timer.c provided by
|
||||
* Alexey Charkov. Minor changes have been made for Device Tree Support.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
||||
#define VT8500_TIMER_OFFSET 0x0100
|
||||
#define VT8500_TIMER_HZ 3000000
|
||||
#define TIMER_MATCH_VAL 0x0000
|
||||
#define TIMER_COUNT_VAL 0x0010
|
||||
#define TIMER_STATUS_VAL 0x0014
|
||||
#define TIMER_IER_VAL 0x001c /* interrupt enable */
|
||||
#define TIMER_CTRL_VAL 0x0020
|
||||
#define TIMER_AS_VAL 0x0024 /* access status */
|
||||
#define TIMER_COUNT_R_ACTIVE (1 << 5) /* not ready for read */
|
||||
#define TIMER_COUNT_W_ACTIVE (1 << 4) /* not ready for write */
|
||||
#define TIMER_MATCH_W_ACTIVE (1 << 0) /* not ready for write */
|
||||
|
||||
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
|
||||
|
||||
static void __iomem *regbase;
|
||||
|
||||
static cycle_t vt8500_timer_read(struct clocksource *cs)
|
||||
{
|
||||
int loops = msecs_to_loops(10);
|
||||
writel(3, regbase + TIMER_CTRL_VAL);
|
||||
while ((readl((regbase + TIMER_AS_VAL)) & TIMER_COUNT_R_ACTIVE)
|
||||
&& --loops)
|
||||
cpu_relax();
|
||||
return readl(regbase + TIMER_COUNT_VAL);
|
||||
}
|
||||
|
||||
static struct clocksource clocksource = {
|
||||
.name = "vt8500_timer",
|
||||
.rating = 200,
|
||||
.read = vt8500_timer_read,
|
||||
.mask = CLOCKSOURCE_MASK(32),
|
||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||
};
|
||||
|
||||
static int vt8500_timer_set_next_event(unsigned long cycles,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
int loops = msecs_to_loops(10);
|
||||
cycle_t alarm = clocksource.read(&clocksource) + cycles;
|
||||
while ((readl(regbase + TIMER_AS_VAL) & TIMER_MATCH_W_ACTIVE)
|
||||
&& --loops)
|
||||
cpu_relax();
|
||||
writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL);
|
||||
|
||||
if ((signed)(alarm - clocksource.read(&clocksource)) <= 16)
|
||||
return -ETIME;
|
||||
|
||||
writel(1, regbase + TIMER_IER_VAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vt8500_timer_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_RESUME:
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
writel(readl(regbase + TIMER_CTRL_VAL) | 1,
|
||||
regbase + TIMER_CTRL_VAL);
|
||||
writel(0, regbase + TIMER_IER_VAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct clock_event_device clockevent = {
|
||||
.name = "vt8500_timer",
|
||||
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||
.rating = 200,
|
||||
.set_next_event = vt8500_timer_set_next_event,
|
||||
.set_mode = vt8500_timer_set_mode,
|
||||
};
|
||||
|
||||
static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evt = dev_id;
|
||||
writel(0xf, regbase + TIMER_STATUS_VAL);
|
||||
evt->event_handler(evt);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irqaction irq = {
|
||||
.name = "vt8500_timer",
|
||||
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
|
||||
.handler = vt8500_timer_interrupt,
|
||||
.dev_id = &clockevent,
|
||||
};
|
||||
|
||||
static struct of_device_id vt8500_timer_ids[] = {
|
||||
{ .compatible = "via,vt8500-timer" },
|
||||
{ }
|
||||
};
|
||||
|
||||
void __init vt8500_timer_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
int timer_irq;
|
||||
|
||||
np = of_find_matching_node(NULL, vt8500_timer_ids);
|
||||
if (!np) {
|
||||
pr_err("%s: Timer description missing from Device Tree\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
regbase = of_iomap(np, 0);
|
||||
if (!regbase) {
|
||||
pr_err("%s: Missing iobase description in Device Tree\n",
|
||||
__func__);
|
||||
of_node_put(np);
|
||||
return;
|
||||
}
|
||||
timer_irq = irq_of_parse_and_map(np, 0);
|
||||
if (!timer_irq) {
|
||||
pr_err("%s: Missing irq description in Device Tree\n",
|
||||
__func__);
|
||||
of_node_put(np);
|
||||
return;
|
||||
}
|
||||
|
||||
writel(1, regbase + TIMER_CTRL_VAL);
|
||||
writel(0xf, regbase + TIMER_STATUS_VAL);
|
||||
writel(~0, regbase + TIMER_MATCH_VAL);
|
||||
|
||||
if (clocksource_register_hz(&clocksource, VT8500_TIMER_HZ))
|
||||
pr_err("%s: vt8500_timer_init: clocksource_register failed for %s\n",
|
||||
__func__, clocksource.name);
|
||||
|
||||
clockevent.cpumask = cpumask_of(0);
|
||||
|
||||
if (setup_irq(timer_irq, &irq))
|
||||
pr_err("%s: setup_irq failed for %s\n", __func__,
|
||||
clockevent.name);
|
||||
clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ,
|
||||
4, 0xf0000000);
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue