summaryrefslogtreecommitdiffstats
path: root/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.8-rc5/0015-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch
diff options
context:
space:
mode:
Diffstat (limited to 'configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.8-rc5/0015-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch')
-rw-r--r--configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.8-rc5/0015-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch629
1 files changed, 629 insertions, 0 deletions
diff --git a/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.8-rc5/0015-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch b/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.8-rc5/0015-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch
new file mode 100644
index 0000000..304e80a
--- /dev/null
+++ b/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.8-rc5/0015-ARM-new-platform-for-Energy-Micro-s-EFM32-Cortex-M3-.patch
@@ -0,0 +1,629 @@
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Thu, 17 Nov 2011 14:36:23 +0100
+Subject: [PATCH] ARM: new platform for Energy Micro's EFM32 Cortex-M3 SoCs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ arch/arm/Kconfig | 13 +-
+ arch/arm/Kconfig.debug | 16 +++
+ arch/arm/Makefile | 1 +
+ arch/arm/boot/dts/efm32gg-dk3750.dts | 69 ++++++++++
+ arch/arm/mach-efm32/Makefile | 3 +
+ arch/arm/mach-efm32/Makefile.boot | 1 +
+ arch/arm/mach-efm32/clk.c | 38 ++++++
+ arch/arm/mach-efm32/cmu.h | 11 ++
+ arch/arm/mach-efm32/common.h | 1 +
+ arch/arm/mach-efm32/dtmachine.c | 43 ++++++
+ arch/arm/mach-efm32/include/mach/debug-macro.S | 48 +++++++
+ arch/arm/mach-efm32/include/mach/entry-macro.S | 12 ++
+ arch/arm/mach-efm32/include/mach/io.h | 6 +
+ arch/arm/mach-efm32/include/mach/irqs.h | 6 +
+ arch/arm/mach-efm32/include/mach/system.h | 18 +++
+ arch/arm/mach-efm32/include/mach/timex.h | 7 +
+ arch/arm/mach-efm32/time.c | 170 ++++++++++++++++++++++++
+ 17 files changed, 462 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/boot/dts/efm32gg-dk3750.dts
+ create mode 100644 arch/arm/mach-efm32/Makefile
+ create mode 100644 arch/arm/mach-efm32/Makefile.boot
+ create mode 100644 arch/arm/mach-efm32/clk.c
+ create mode 100644 arch/arm/mach-efm32/cmu.h
+ create mode 100644 arch/arm/mach-efm32/common.h
+ create mode 100644 arch/arm/mach-efm32/dtmachine.c
+ create mode 100644 arch/arm/mach-efm32/include/mach/debug-macro.S
+ create mode 100644 arch/arm/mach-efm32/include/mach/entry-macro.S
+ create mode 100644 arch/arm/mach-efm32/include/mach/io.h
+ create mode 100644 arch/arm/mach-efm32/include/mach/irqs.h
+ create mode 100644 arch/arm/mach-efm32/include/mach/system.h
+ create mode 100644 arch/arm/mach-efm32/include/mach/timex.h
+ create mode 100644 arch/arm/mach-efm32/time.c
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 9d09a41..029f074 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -418,6 +418,17 @@ config ARCH_EBSA110
+ Ethernet interface, two PCMCIA sockets, two serial ports and a
+ parallel port.
+
++config ARCH_EFM32
++ bool "EnergyMicro Cortex M3 Platform"
++ depends on !MMU
++ select ARM_NVIC
++ select CLKSRC_MMIO
++ select CPU_V7M
++ select GENERIC_CLOCKEVENTS
++ select HAVE_CLK
++ select NO_DMA
++ select NO_IOPORT
++
+ config ARCH_EP93XX
+ bool "EP93xx-based"
+ select ARCH_HAS_HOLES_MEMORYMODEL
+@@ -1785,7 +1796,7 @@ config FORCE_MAX_ZONEORDER
+ int "Maximum zone order" if ARCH_SHMOBILE
+ range 11 64 if ARCH_SHMOBILE
+ default "12" if SOC_AM33XX
+- default "9" if SA1111
++ default "9" if SA1111 || ARCH_EFM32
+ default "11"
+ help
+ The kernel memory allocator divides physically contiguous memory
+diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
+index 661030d..e0f675a 100644
+--- a/arch/arm/Kconfig.debug
++++ b/arch/arm/Kconfig.debug
+@@ -156,6 +156,22 @@ choice
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port in the DC21285 (Footbridge).
+
++ config DEBUG_EFM32_USART1
++ bool "Kernel low-level debugging messages via USART1"
++ depends on ARCH_EFM32
++ help
++ Say Y here if you want the debug print routines to direct
++ their output to the second USART port on efm32 based
++ machines.
++
++ config DEBUG_EFM32_UART1
++ bool "Kernel low-level debugging messages via UART1"
++ depends on ARCH_EFM32
++ help
++ Say Y here if you want the debug print routines to direct
++ their output to the second UART port on efm32 based
++ machines.
++
+ config DEBUG_FOOTBRIDGE_COM1
+ bool "Kernel low-level debugging messages via footbridge 8250 at PCI COM1"
+ depends on FOOTBRIDGE
+diff --git a/arch/arm/Makefile b/arch/arm/Makefile
+index 69a5955..374e25a 100644
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -146,6 +146,7 @@ machine-$(CONFIG_ARCH_CNS3XXX) += cns3xxx
+ machine-$(CONFIG_ARCH_DAVINCI) += davinci
+ machine-$(CONFIG_ARCH_DOVE) += dove
+ machine-$(CONFIG_ARCH_EBSA110) += ebsa110
++machine-$(CONFIG_ARCH_EFM32) += efm32
+ machine-$(CONFIG_ARCH_EP93XX) += ep93xx
+ machine-$(CONFIG_ARCH_GEMINI) += gemini
+ machine-$(CONFIG_ARCH_H720X) += h720x
+diff --git a/arch/arm/boot/dts/efm32gg-dk3750.dts b/arch/arm/boot/dts/efm32gg-dk3750.dts
+new file mode 100644
+index 0000000..3fc2369
+--- /dev/null
++++ b/arch/arm/boot/dts/efm32gg-dk3750.dts
+@@ -0,0 +1,69 @@
++/dts-v1/;
++/include/ "skeleton.dtsi"
++
++/ {
++ model = "Energy Micro Giant Gecko Development Kit";
++ compatible = "efm32,dk3750";
++
++ aliases {
++ serial4 = &uart4;
++ };
++
++ nvic: nv-interrupt-controller@0xe0000000 {
++ compatible = "arm,cortex-m3-nvic";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ reg = <0xe000e000 0x4000>;
++ };
++
++ chosen {
++ bootargs = "console=ttyefm4,115200 init=/linuxrc ignore_loglevel ihash_entries=64 dhash_entries=64 earlyprintk uclinux.physaddr=0x8c000000 root=/dev/mtdblock0";
++ };
++
++ memory {
++ reg = <0x88000000 0x400000>;
++ };
++
++ soc {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "simple-bus";
++ interrupt-parent = <&nvic>;
++ ranges;
++
++ spi@0x4000c400 { /* USART1 */
++ #address-cells = <1>;
++ #size-cells = <0>;
++ compatible = "efm32,spi";
++ reg = <0x4000c400 0x400>;
++ interrupts = <15>;
++ status = "ok";
++
++ ks8851@0 {
++ compatible = "ks8851";
++ spi-max-frequency = <6000000>;
++ reg = <0>;
++ interrupt-parent = <&boardfpga>;
++ interrupts = <4>;
++ status = "ok";
++ };
++ };
++
++ uart4: uart@0x4000e400 { /* UART1 */
++ compatible = "efm32,uart";
++ reg = <0x4000e400 0x400>;
++ interrupts = <22>;
++ location = <2>;
++ status = "ok";
++ };
++
++ boardfpga: boardfpga@0x80000000 {
++ compatible = "efm32board";
++ reg = <0x80000000 0x400>;
++ /* this is a lie, gpio_even = 1 */
++ interrupts = <1>;
++ interrupt-controller;
++ #interrupt-cells = <1>;
++ };
++ };
++};
+diff --git a/arch/arm/mach-efm32/Makefile b/arch/arm/mach-efm32/Makefile
+new file mode 100644
+index 0000000..10a3426
+--- /dev/null
++++ b/arch/arm/mach-efm32/Makefile
+@@ -0,0 +1,3 @@
++obj-y += clk.o time.o
++
++obj-$(CONFIG_OF) += dtmachine.o
+diff --git a/arch/arm/mach-efm32/Makefile.boot b/arch/arm/mach-efm32/Makefile.boot
+new file mode 100644
+index 0000000..385e93a
+--- /dev/null
++++ b/arch/arm/mach-efm32/Makefile.boot
+@@ -0,0 +1 @@
++dtb-$(CONFIG_MACH_EFM32GG_DK3750) += efm32gg-dk3750.dtb
+diff --git a/arch/arm/mach-efm32/clk.c b/arch/arm/mach-efm32/clk.c
+new file mode 100644
+index 0000000..5b158ab
+--- /dev/null
++++ b/arch/arm/mach-efm32/clk.c
+@@ -0,0 +1,38 @@
++#include <linux/clk.h>
++#include <linux/export.h>
++#include <linux/io.h>
++
++#include "cmu.h"
++
++struct clk *clk_get(struct device *dev, const char *id)
++{
++ return NULL;
++}
++EXPORT_SYMBOL(clk_get);
++
++int clk_enable(struct clk *clk)
++{
++ return 0;
++}
++EXPORT_SYMBOL(clk_enable);
++
++void clk_disable(struct clk *clk)
++{
++}
++EXPORT_SYMBOL(clk_disable);
++
++unsigned long clk_get_rate(struct clk *clk)
++{
++ u32 cmu_status = __raw_readl(CMU_STATUS);
++
++ if (cmu_status & CMU_STATUS_HFRCOSEL)
++ return 14000000;
++ else
++ return 48000000;
++}
++EXPORT_SYMBOL(clk_get_rate);
++
++void clk_put(struct clk *clk)
++{
++}
++EXPORT_SYMBOL(clk_put);
+diff --git a/arch/arm/mach-efm32/cmu.h b/arch/arm/mach-efm32/cmu.h
+new file mode 100644
+index 0000000..05ef676
+--- /dev/null
++++ b/arch/arm/mach-efm32/cmu.h
+@@ -0,0 +1,11 @@
++#include "common.h"
++
++#define CMU_OSCENCMD IOMEM(0x400c8020)
++#define CMU_OSCENCMD_HFXOEN 0x00000004
++
++#define CMU_CMD IOMEM(0x400C8024)
++#define CMU_CMD_HFCLKSEL_HFXO 0x00000002
++
++#define CMU_STATUS IOMEM(0x400c802c)
++#define CMU_STATUS_HFRCOSEL 0x00000400
++#define CMU_STATUS_HFXOSEL 0x00000800
+diff --git a/arch/arm/mach-efm32/common.h b/arch/arm/mach-efm32/common.h
+new file mode 100644
+index 0000000..d2ff797
+--- /dev/null
++++ b/arch/arm/mach-efm32/common.h
+@@ -0,0 +1 @@
++extern struct sys_timer efm32_timer;
+diff --git a/arch/arm/mach-efm32/dtmachine.c b/arch/arm/mach-efm32/dtmachine.c
+new file mode 100644
+index 0000000..a64c4a4
+--- /dev/null
++++ b/arch/arm/mach-efm32/dtmachine.c
+@@ -0,0 +1,43 @@
++#include <linux/kernel.h>
++#include <linux/pinctrl/machine.h>
++#include <linux/irqdomain.h>
++#include <linux/of_platform.h>
++#include <linux/of_irq.h>
++
++#include <asm/hardware/nvic.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/time.h>
++
++#include "common.h"
++#include "devices.h"
++
++static const struct of_device_id efm32_irq_match[] __initconst = {
++ {
++ .compatible = "arm,cortex-m3-nvic",
++ .data = nvic_of_init,
++ }, {
++ /* sentinel */
++ }
++};
++
++static void __init efm32_init_irq(void)
++{
++ of_irq_init(efm32_irq_match);
++}
++
++static void __init efm32_init(void)
++{
++ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
++}
++
++static const char *const efm32gg_compat[] __initconst = {
++ "efm32,dk3750",
++ NULL
++};
++
++DT_MACHINE_START(EFM32DT, "EFM32 (Device Tree Support)")
++ .init_irq = efm32_init_irq,
++ .timer = &efm32_timer,
++ .init_machine = efm32_init,
++ .dt_compat = efm32gg_compat,
++MACHINE_END
+diff --git a/arch/arm/mach-efm32/include/mach/debug-macro.S b/arch/arm/mach-efm32/include/mach/debug-macro.S
+new file mode 100644
+index 0000000..c58915c
+--- /dev/null
++++ b/arch/arm/mach-efm32/include/mach/debug-macro.S
+@@ -0,0 +1,48 @@
++/*
++ * 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 UARTn_CMD 0x000c
++#define UARTn_CMD_TXEN 0x0004
++
++#define UARTn_STATUS 0x0010
++#define UARTn_STATUS_TXC 0x0020
++#define UARTn_STATUS_TXBL 0x0040
++
++#define UARTn_TXDATA 0x0034
++
++ .macro addruart, rx, tmp
++#if defined(CONFIG_DEBUG_EFM32_USART1)
++ ldr \rx, =(0x4000c400) /* USART1 */
++#elif defined(CONFIG_DEBUG_EFM32_UART1)
++ ldr \rx, =(0x4000e400) /* UART1 */
++#else
++#error "No debug port configured"
++#endif
++ /*
++ * enable TX. The driver might disable that to save energy. We
++ * don't care about disabling at the end as during debug power
++ * consumption isn't that important.
++ */
++ ldr \tmp, =(UARTn_CMD_TXEN)
++ str \tmp, [\rx, #UARTn_CMD]
++ .endm
++
++
++ .macro senduart,rd,rx
++ strb \rd, [\rx, #UARTn_TXDATA]
++ .endm
++
++ .macro waituart,rd,rx
++1001: ldr \rd, [\rx, #UARTn_STATUS]
++ tst \rd, #UARTn_STATUS_TXBL
++ beq 1001b
++ .endm
++
++ .macro busyuart,rd,rx
++1001: ldr \rd, [\rx, UARTn_STATUS]
++ tst \rd, #UARTn_STATUS_TXC
++ bne 1001b
++ .endm
+diff --git a/arch/arm/mach-efm32/include/mach/entry-macro.S b/arch/arm/mach-efm32/include/mach/entry-macro.S
+new file mode 100644
+index 0000000..75b304a
+--- /dev/null
++++ b/arch/arm/mach-efm32/include/mach/entry-macro.S
+@@ -0,0 +1,12 @@
++/*
++ *
++ */
++#include <asm/hardware/gic.h>
++
++ .macro get_irqnr_preamble, base, tmp
++ ldr \base, =gic_cpu_base_addr
++ ldr \base, [\base]
++ .endm
++
++ .macro arch_ret_to_user, tmp1, tmp2
++ .endm
+diff --git a/arch/arm/mach-efm32/include/mach/io.h b/arch/arm/mach-efm32/include/mach/io.h
+new file mode 100644
+index 0000000..bc3519b
+--- /dev/null
++++ b/arch/arm/mach-efm32/include/mach/io.h
+@@ -0,0 +1,6 @@
++#ifndef __MACH_IO_H__
++#define __MACH_IO_H__
++
++#define __mem_pci(a) (a)
++
++#endif /* __MACH_IO_H__ */
+diff --git a/arch/arm/mach-efm32/include/mach/irqs.h b/arch/arm/mach-efm32/include/mach/irqs.h
+new file mode 100644
+index 0000000..e33ed12
+--- /dev/null
++++ b/arch/arm/mach-efm32/include/mach/irqs.h
+@@ -0,0 +1,6 @@
++#ifndef __MACH_IRQS_H__
++#define __MACH_IRQS_H__
++
++#define NR_IRQS 82
++
++#endif /* __MACH_IRQS_H__ */
+diff --git a/arch/arm/mach-efm32/include/mach/system.h b/arch/arm/mach-efm32/include/mach/system.h
+new file mode 100644
+index 0000000..619222c
+--- /dev/null
++++ b/arch/arm/mach-efm32/include/mach/system.h
+@@ -0,0 +1,18 @@
++#ifndef __MACH_SYSTEM_H__
++#define __MACH_SYSTEM_H__
++
++#include <asm/io.h>
++
++static inline void arch_idle(void)
++{
++ cpu_do_idle();
++}
++
++static inline void arch_reset(char mode, const char *cmd)
++{
++ /* XXX: move this to (say) cpuv7m_reset */
++ dsb();
++ __raw_writel(0x05fa0004, (void __iomem *)0xe000ed0c);
++ dsb();
++}
++#endif /* __MACH_SYSTEM_H__ */
+diff --git a/arch/arm/mach-efm32/include/mach/timex.h b/arch/arm/mach-efm32/include/mach/timex.h
+new file mode 100644
+index 0000000..b408dce
+--- /dev/null
++++ b/arch/arm/mach-efm32/include/mach/timex.h
+@@ -0,0 +1,7 @@
++#ifndef __MACH_TIMEX_H__
++#define __MACH_TIMEX_H__
++
++/* just a bogus value */
++#define CLOCK_TICK_RATE 12345678
++
++#endif /* __MACH_TIMEX_H__ */
+diff --git a/arch/arm/mach-efm32/time.c b/arch/arm/mach-efm32/time.c
+new file mode 100644
+index 0000000..f91a3ef
+--- /dev/null
++++ b/arch/arm/mach-efm32/time.c
+@@ -0,0 +1,170 @@
++#include <linux/kernel.h>
++#include <linux/clocksource.h>
++#include <linux/clockchips.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/stringify.h>
++
++#include <asm/mach/time.h>
++
++#include "common.h"
++
++#define BASEADDR_TIMER(n) IOMEM(0x40010000 + (n) * 0x400)
++
++#define TIMERn_CTRL 0x00
++#define TIMERn_CTRL_PRESC(val) (((val) & 0xf) << 24)
++#define TIMERn_CTRL_PRESC_1024 TIMERn_CTRL_PRESC(10)
++#define TIMERn_CTRL_CLKSEL(val) (((val) & 0x3) << 16)
++#define TIMERn_CTRL_CLKSEL_PRESCHFPERCLK TIMERn_CTRL_CLKSEL(0)
++#define TIMERn_CTRL_OSMEN 0x00000010
++#define TIMERn_CTRL_MODE(val) (((val) & 0x3) << 0)
++#define TIMERn_CTRL_MODE_UP TIMERn_CTRL_MODE(0)
++#define TIMERn_CTRL_MODE_DOWN TIMERn_CTRL_MODE(1)
++
++#define TIMERn_CMD 0x04
++#define TIMERn_CMD_START 0x1
++#define TIMERn_CMD_STOP 0x2
++
++#define TIMERn_IEN 0x0c
++#define TIMERn_IF 0x10
++#define TIMERn_IFS 0x14
++#define TIMERn_IFC 0x18
++#define TIMERn_IRQ_UF 0x2
++#define TIMERn_IRQ_OF 0x1
++
++#define TIMERn_TOP 0x1c
++#define TIMERn_CNT 0x24
++
++#define TIMER_CLOCKSOURCE 1
++#define TIMER_CLOCKEVENT 2
++#define IRQ_CLOCKEVENT NVIC_IRQ(13)
++
++static void efm32_timer_write(unsigned timerno, u32 val, unsigned offset)
++{
++ __raw_writel(val, BASEADDR_TIMER(timerno) + offset);
++}
++
++static void efm32_clock_event_set_mode(enum clock_event_mode mode,
++ struct clock_event_device *unused)
++{
++ switch (mode) {
++ case CLOCK_EVT_MODE_PERIODIC:
++ efm32_timer_write(TIMER_CLOCKEVENT,
++ TIMERn_CMD_STOP, TIMERn_CMD);
++ efm32_timer_write(TIMER_CLOCKEVENT, 137, TIMERn_TOP);
++ efm32_timer_write(TIMER_CLOCKEVENT,
++ TIMERn_CTRL_PRESC_1024 |
++ TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
++ TIMERn_CTRL_MODE_DOWN, TIMERn_CTRL);
++ efm32_timer_write(TIMER_CLOCKEVENT,
++ TIMERn_CMD_START, TIMERn_CMD);
++ break;
++
++ case CLOCK_EVT_MODE_ONESHOT:
++ efm32_timer_write(TIMER_CLOCKEVENT,
++ TIMERn_CMD_STOP, TIMERn_CMD);
++ efm32_timer_write(TIMER_CLOCKEVENT,
++ TIMERn_CTRL_PRESC_1024 |
++ TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
++ TIMERn_CTRL_OSMEN |
++ TIMERn_CTRL_MODE_DOWN, TIMERn_CTRL);
++ break;
++
++ case CLOCK_EVT_MODE_UNUSED:
++ case CLOCK_EVT_MODE_SHUTDOWN:
++ efm32_timer_write(TIMER_CLOCKEVENT, TIMERn_CMD_STOP,
++ TIMERn_CMD);
++ break;
++
++ case CLOCK_EVT_MODE_RESUME:
++ break;
++ }
++}
++
++static int efm32_clock_event_set_next_event(unsigned long evt,
++ struct clock_event_device *unused)
++{
++ efm32_timer_write(TIMER_CLOCKEVENT, TIMERn_CMD_STOP, TIMERn_CMD);
++ efm32_timer_write(TIMER_CLOCKEVENT, evt, TIMERn_CNT);
++ efm32_timer_write(TIMER_CLOCKEVENT, TIMERn_CMD_START, TIMERn_CMD);
++
++ return 0;
++}
++
++static struct clock_event_device efm32_clock_event_device = {
++ .name = "efm32 clockevent (" __stringify(TIMER_CLOCKEVENT) ")",
++ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_MODE_PERIODIC,
++ .set_mode = efm32_clock_event_set_mode,
++ .set_next_event = efm32_clock_event_set_next_event,
++ .rating = 200,
++};
++
++static irqreturn_t efm32_clock_event_handler(int irq, void *dev_id)
++{
++ struct clock_event_device *evt = &efm32_clock_event_device;
++
++ /* ack irq */
++ efm32_timer_write(TIMER_CLOCKEVENT, TIMERn_IRQ_UF, TIMERn_IFC);
++
++ evt->event_handler(evt);
++
++ return IRQ_HANDLED;
++}
++
++static struct irqaction efm32_clock_event_irq = {
++ .name = "efm32 clockevent",
++ .flags = IRQF_TIMER,
++ .handler = efm32_clock_event_handler,
++ .dev_id = &efm32_clock_event_device,
++};
++
++/*
++ * XXX: use clk_ API to get frequency and enabling of the clocks used.
++ * Here the reset defaults are used:
++ * - freq_{HFPERCLK} = freq_{HFCLK}
++ * (CMU_HFPERCLKDIV_HFPERCLKDIV = 0x0)
++ * - freq_{HFCLK} = freq_{HFRCO}
++ * (CMU_CTRL_HFCLKDIV = 0x0, CMU_STATUS_HFRCOSEL = 0x1)
++ * - freq_{HFRCO} = 14MHz
++ * (CMU_HFRCOCTRL_BAND = 0x3)
++ *
++ * So the HFPERCLK runs at 14MHz. The timer has an additional prescaler
++ * programmed to /1024. This make the timer run at
++ *
++ * 14 MHz / 1024 = 13671.875 Hz
++ *
++ * When HFXO is used HFPERCLK runs at 48 MHz, so the timer runs at
++ *
++ * 48 MHz / 1024 = 46875 Hz
++ *
++ */
++static void __init efm32_timer_init(void)
++{
++ /* enable CMU_HFPERCLKEN0_TIMERn for clocksource via bit-band */
++ __raw_writel(1, IOMEM(0x43900894 + 4 * TIMER_CLOCKSOURCE));
++
++ efm32_timer_write(TIMER_CLOCKSOURCE,
++ TIMERn_CTRL_PRESC_1024 |
++ TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
++ TIMERn_CTRL_MODE_UP, TIMERn_CTRL);
++ efm32_timer_write(TIMER_CLOCKSOURCE, TIMERn_CMD_START, TIMERn_CMD);
++
++ clocksource_mmio_init(BASEADDR_TIMER(TIMER_CLOCKSOURCE) + TIMERn_CNT,
++ "efm32 timer", 46875, 200, 16,
++ clocksource_mmio_readl_up);
++
++ /* enable CMU_HFPERCLKEN0_TIMERn for clockevent via bit-band */
++ __raw_writel(1, IOMEM(0x43900894 + 4 * TIMER_CLOCKEVENT));
++
++ efm32_timer_write(TIMER_CLOCKEVENT, TIMERn_IRQ_UF, TIMERn_IEN);
++
++ setup_irq(IRQ_CLOCKEVENT, &efm32_clock_event_irq);
++
++ /* XXX: tune min_delta */
++ clockevents_config_and_register(&efm32_clock_event_device,
++ 46875, 0xf, 0xffff);
++}
++
++struct sys_timer efm32_timer = {
++ .init = efm32_timer_init,
++};