aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 21:24:44 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 21:24:44 -0400
commit11801e9de26992d37cb869cc74f389b6a7677e0e (patch)
tree322b7ea2b475d52da27d3e01f5bc2992bb708d59 /drivers/clocksource
parent1a58ddfc0fcf3d83a92573c71771962f9b218993 (diff)
parentb6e3b5c2fea9c76617e101cbbc54ed14961f9dee (diff)
Merge tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM soc-specific updates from Olof Johansson: "Most notable here is probably the addition of basic support for the BCM2835, an SoC used in some of the Roku 2 players as well as the much-hyped Raspberry Pi, cleaned up and contributed by Stephen Warren. It's still early days on mainline support, with just the basics working. But it has to start somewhere! Beyond that there's some conversions of clock infrastructure on tegra to common clock, misc updates for several other platforms, and OMAP now has its own bus (under drivers/bus) to manage its devices through. This branch adds two new directories outside of arch/arm: drivers/irqchip for new irq controllers, and drivers/bus for the above OMAP bus. It's expected that some of the other platforms will migrate parts of their platforms to those directories over time as well." Fix up trivial conflicts with the clk infrastructure changes. * tag 'soc' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (62 commits) ARM: shmobile: add new __iomem annotation for new code ARM: LPC32xx: Support GPI 28 ARM: LPC32xx: Platform update for devicetree completion of spi-pl022 ARM: LPC32xx: Board cleanup irqchip: fill in empty Kconfig ARM: SAMSUNG: Add check for NULL in clock interface ARM: EXYNOS: Put PCM, Slimbus, Spdif clocks to off state ARM: EXYNOS: Add bus clock for FIMD ARM: SAMSUNG: Fix HDMI related warnings ARM: S3C24XX: Add .get_rate callback for "camif-upll" clock ARM: EXYNOS: Fix incorrect help text ARM: EXYNOS: Turn off clocks for NAND, OneNAND and TSI controllers ARM: OMAP: AM33xx hwmod: fixup SPI after platform_data move MAINTAINERS: add an entry for the BCM2835 ARM sub-architecture ARM: bcm2835: instantiate console UART ARM: bcm2835: add stub clock driver ARM: bcm2835: add system timer ARM: bcm2835: add interrupt controller driver ARM: add infra-structure for BCM2835 and Raspberry Pi ARM: tegra20: add CPU hotplug support ...
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/bcm2835_timer.c161
2 files changed, 163 insertions, 0 deletions
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 65919901a30..603be366f76 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -13,4 +13,6 @@ obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
13obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o 13obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
14obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o 14obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
15obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o 15obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
16obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
17
16obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o 18obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o
diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c
new file mode 100644
index 00000000000..bc19f12c20c
--- /dev/null
+++ b/drivers/clocksource/bcm2835_timer.c
@@ -0,0 +1,161 @@
1/*
2 * Copyright 2012 Simon Arlott
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#include <linux/bcm2835_timer.h>
20#include <linux/bitops.h>
21#include <linux/clockchips.h>
22#include <linux/clocksource.h>
23#include <linux/interrupt.h>
24#include <linux/irqreturn.h>
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/of_address.h>
28#include <linux/of_irq.h>
29#include <linux/of_platform.h>
30#include <linux/slab.h>
31#include <linux/string.h>
32
33#include <asm/sched_clock.h>
34#include <asm/irq.h>
35
36#define REG_CONTROL 0x00
37#define REG_COUNTER_LO 0x04
38#define REG_COUNTER_HI 0x08
39#define REG_COMPARE(n) (0x0c + (n) * 4)
40#define MAX_TIMER 3
41#define DEFAULT_TIMER 3
42
43struct bcm2835_timer {
44 void __iomem *control;
45 void __iomem *compare;
46 int match_mask;
47 struct clock_event_device evt;
48 struct irqaction act;
49};
50
51static void __iomem *system_clock __read_mostly;
52
53static u32 notrace bcm2835_sched_read(void)
54{
55 return readl_relaxed(system_clock);
56}
57
58static void bcm2835_time_set_mode(enum clock_event_mode mode,
59 struct clock_event_device *evt_dev)
60{
61 switch (mode) {
62 case CLOCK_EVT_MODE_ONESHOT:
63 case CLOCK_EVT_MODE_UNUSED:
64 case CLOCK_EVT_MODE_SHUTDOWN:
65 case CLOCK_EVT_MODE_RESUME:
66 break;
67 default:
68 WARN(1, "%s: unhandled event mode %d\n", __func__, mode);
69 break;
70 }
71}
72
73static int bcm2835_time_set_next_event(unsigned long event,
74 struct clock_event_device *evt_dev)
75{
76 struct bcm2835_timer *timer = container_of(evt_dev,
77 struct bcm2835_timer, evt);
78 writel_relaxed(readl_relaxed(system_clock) + event,
79 timer->compare);
80 return 0;
81}
82
83static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id)
84{
85 struct bcm2835_timer *timer = dev_id;
86 void (*event_handler)(struct clock_event_device *);
87 if (readl_relaxed(timer->control) & timer->match_mask) {
88 writel_relaxed(timer->match_mask, timer->control);
89
90 event_handler = ACCESS_ONCE(timer->evt.event_handler);
91 if (event_handler)
92 event_handler(&timer->evt);
93 return IRQ_HANDLED;
94 } else {
95 return IRQ_NONE;
96 }
97}
98
99static struct of_device_id bcm2835_time_match[] __initconst = {
100 { .compatible = "brcm,bcm2835-system-timer" },
101 {}
102};
103
104static void __init bcm2835_time_init(void)
105{
106 struct device_node *node;
107 void __iomem *base;
108 u32 freq;
109 int irq;
110 struct bcm2835_timer *timer;
111
112 node = of_find_matching_node(NULL, bcm2835_time_match);
113 if (!node)
114 panic("No bcm2835 timer node");
115
116 base = of_iomap(node, 0);
117 if (!base)
118 panic("Can't remap registers");
119
120 if (of_property_read_u32(node, "clock-frequency", &freq))
121 panic("Can't read clock-frequency");
122
123 system_clock = base + REG_COUNTER_LO;
124 setup_sched_clock(bcm2835_sched_read, 32, freq);
125
126 clocksource_mmio_init(base + REG_COUNTER_LO, node->name,
127 freq, 300, 32, clocksource_mmio_readl_up);
128
129 irq = irq_of_parse_and_map(node, DEFAULT_TIMER);
130 if (irq <= 0)
131 panic("Can't parse IRQ");
132
133 timer = kzalloc(sizeof(*timer), GFP_KERNEL);
134 if (!timer)
135 panic("Can't allocate timer struct\n");
136
137 timer->control = base + REG_CONTROL;
138 timer->compare = base + REG_COMPARE(DEFAULT_TIMER);
139 timer->match_mask = BIT(DEFAULT_TIMER);
140 timer->evt.name = node->name;
141 timer->evt.rating = 300;
142 timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
143 timer->evt.set_mode = bcm2835_time_set_mode;
144 timer->evt.set_next_event = bcm2835_time_set_next_event;
145 timer->evt.cpumask = cpumask_of(0);
146 timer->act.name = node->name;
147 timer->act.flags = IRQF_TIMER | IRQF_SHARED;
148 timer->act.dev_id = timer;
149 timer->act.handler = bcm2835_time_interrupt;
150
151 if (setup_irq(irq, &timer->act))
152 panic("Can't set up timer IRQ\n");
153
154 clockevents_config_and_register(&timer->evt, freq, 0xf, 0xffffffff);
155
156 pr_info("bcm2835: system timer (irq = %d)\n", irq);
157}
158
159struct sys_timer bcm2835_timer = {
160 .init = bcm2835_time_init,
161};