linux/drivers/clocksource/dw_apb_timer_of.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2012 Altera Corporation
   3 * Copyright (c) 2011 Picochip Ltd., Jamie Iles
   4 *
   5 * Modified from mach-picoxcell/time.c
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19#include <linux/dw_apb_timer.h>
  20#include <linux/of.h>
  21#include <linux/of_address.h>
  22#include <linux/of_irq.h>
  23
  24#include <asm/mach/time.h>
  25#include <asm/sched_clock.h>
  26
  27static void timer_get_base_and_rate(struct device_node *np,
  28                                    void __iomem **base, u32 *rate)
  29{
  30        *base = of_iomap(np, 0);
  31
  32        if (!*base)
  33                panic("Unable to map regs for %s", np->name);
  34
  35        if (of_property_read_u32(np, "clock-freq", rate) &&
  36                of_property_read_u32(np, "clock-frequency", rate))
  37                panic("No clock-frequency property for %s", np->name);
  38}
  39
  40static void add_clockevent(struct device_node *event_timer)
  41{
  42        void __iomem *iobase;
  43        struct dw_apb_clock_event_device *ced;
  44        u32 irq, rate;
  45
  46        irq = irq_of_parse_and_map(event_timer, 0);
  47        if (irq == NO_IRQ)
  48                panic("No IRQ for clock event timer");
  49
  50        timer_get_base_and_rate(event_timer, &iobase, &rate);
  51
  52        ced = dw_apb_clockevent_init(0, event_timer->name, 300, iobase, irq,
  53                                     rate);
  54        if (!ced)
  55                panic("Unable to initialise clockevent device");
  56
  57        dw_apb_clockevent_register(ced);
  58}
  59
  60static void add_clocksource(struct device_node *source_timer)
  61{
  62        void __iomem *iobase;
  63        struct dw_apb_clocksource *cs;
  64        u32 rate;
  65
  66        timer_get_base_and_rate(source_timer, &iobase, &rate);
  67
  68        cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate);
  69        if (!cs)
  70                panic("Unable to initialise clocksource device");
  71
  72        dw_apb_clocksource_start(cs);
  73        dw_apb_clocksource_register(cs);
  74}
  75
  76static void __iomem *sched_io_base;
  77
  78static u32 read_sched_clock(void)
  79{
  80        return __raw_readl(sched_io_base);
  81}
  82
  83static const struct of_device_id sptimer_ids[] __initconst = {
  84        { .compatible = "picochip,pc3x2-rtc" },
  85        { .compatible = "snps,dw-apb-timer-sp" },
  86        { /* Sentinel */ },
  87};
  88
  89static void init_sched_clock(void)
  90{
  91        struct device_node *sched_timer;
  92        u32 rate;
  93
  94        sched_timer = of_find_matching_node(NULL, sptimer_ids);
  95        if (!sched_timer)
  96                panic("No RTC for sched clock to use");
  97
  98        timer_get_base_and_rate(sched_timer, &sched_io_base, &rate);
  99        of_node_put(sched_timer);
 100
 101        setup_sched_clock(read_sched_clock, 32, rate);
 102}
 103
 104static const struct of_device_id osctimer_ids[] __initconst = {
 105        { .compatible = "picochip,pc3x2-timer" },
 106        { .compatible = "snps,dw-apb-timer-osc" },
 107        {},
 108};
 109
 110static void __init timer_init(void)
 111{
 112        struct device_node *event_timer, *source_timer;
 113
 114        event_timer = of_find_matching_node(NULL, osctimer_ids);
 115        if (!event_timer)
 116                panic("No timer for clockevent");
 117        add_clockevent(event_timer);
 118
 119        source_timer = of_find_matching_node(event_timer, osctimer_ids);
 120        if (!source_timer)
 121                panic("No timer for clocksource");
 122        add_clocksource(source_timer);
 123
 124        of_node_put(source_timer);
 125
 126        init_sched_clock();
 127}
 128
 129struct sys_timer dw_apb_timer = {
 130        .init = timer_init,
 131};
 132
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.