[PATCH 06/11] ST SPEAr: Added source files for SPEAr platform
Viresh KUMAR
viresh.kumar at st.com
Wed Mar 3 00:07:36 EST 2010
Signed-off-by: Viresh Kumar <viresh.kumar at st.com>
---
arch/arm/plat-spear/Kconfig | 31 +++
arch/arm/plat-spear/Makefile | 6 +
arch/arm/plat-spear/gpt.c | 537 ++++++++++++++++++++++++++++++++++++++++++
arch/arm/plat-spear/time.c | 197 +++++++++++++++
4 files changed, 771 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/plat-spear/Kconfig
create mode 100644 arch/arm/plat-spear/Makefile
create mode 100644 arch/arm/plat-spear/gpt.c
create mode 100644 arch/arm/plat-spear/time.c
diff --git a/arch/arm/plat-spear/Kconfig b/arch/arm/plat-spear/Kconfig
new file mode 100644
index 0000000..1bb3dbc
--- /dev/null
+++ b/arch/arm/plat-spear/Kconfig
@@ -0,0 +1,31 @@
+#
+# SPEAr Platform configuration file
+#
+
+if PLAT_SPEAR
+
+choice
+ prompt "ST SPEAr Family"
+ default ARCH_SPEAR3XX
+
+config ARCH_SPEAR3XX
+ bool "SPEAr3XX"
+ select ARM_VIC
+ select CPU_ARM926T
+ help
+ Supports for ARM's SPEAR3XX family
+
+config ARCH_SPEAR6XX
+ bool "SPEAr6XX"
+ select ARM_VIC
+ select CPU_ARM926T
+ help
+ Supports for ARM's SPEAR6XX family
+
+endchoice
+
+# Adding SPEAr machine specific configuration files
+source "arch/arm/mach-spear3xx/Kconfig"
+source "arch/arm/mach-spear6xx/Kconfig"
+
+endif
diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile
new file mode 100644
index 0000000..4412f05
--- /dev/null
+++ b/arch/arm/plat-spear/Makefile
@@ -0,0 +1,6 @@
+#
+# SPEAr Platform specific Makefile
+#
+
+# Common support
+obj-y := clock.o gpt.o time.o
diff --git a/arch/arm/plat-spear/gpt.c b/arch/arm/plat-spear/gpt.c
new file mode 100644
index 0000000..3b16360
--- /dev/null
+++ b/arch/arm/plat-spear/gpt.c
@@ -0,0 +1,537 @@
+/*
+ * arch/arm/plat-spear/gpt.c
+ *
+ * ST GPT Timer driver, based on omap's dmtimer.c
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Shiraz Hashim<shiraz.hashim at st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <mach/irqs.h>
+#include <mach/spear.h>
+#include <plat/gpt.h>
+
+static const char *src_clk_con_id[] __initdata = {
+ "pll3_48m_clk",
+ "pll1_clk",
+ NULL
+};
+
+static struct clk *spear_source_clocks[2];
+static struct spear_timer *spear_timers;
+static int spear_timer_count;
+static spinlock_t spear_timer_lock;
+
+/*
+ * static helper functions
+ */
+static inline u16 spear_timer_read_reg(struct spear_timer *timer, u32 reg)
+{
+ return readw(timer->io_base + (reg & 0xff));
+}
+
+static inline void spear_timer_write_reg(struct spear_timer *timer, u32 reg,
+ u16 value)
+{
+ writew(value, timer->io_base + (reg & 0xff));
+}
+
+static void spear_timer_reset(struct spear_timer *timer)
+{
+
+ spear_timer_write_reg(timer, GPT_CTRL_OFF, 0x0);
+ spear_timer_write_reg(timer, GPT_LOAD_OFF, 0x0);
+ spear_timer_write_reg(timer, GPT_INT_OFF, GPT_STATUS_MATCH);
+ timer->prescaler = 0;
+}
+
+static void spear_timer_prepare(struct spear_timer *timer)
+{
+ spear_timer_enable(timer);
+ spear_timer_reset(timer);
+}
+
+/* functions exported for application */
+
+/**
+ * spear_timer_enable - enable a timer
+ * @timer: timer
+ *
+ * This API enables the functional clock of the timer
+ */
+int spear_timer_enable(struct spear_timer *timer)
+{
+ if (!timer)
+ return -ENODEV;
+
+ if (timer->enabled)
+ return -EINVAL;
+
+ clk_enable(timer->fclk);
+
+ timer->enabled = 1;
+
+ return 0;
+}
+
+/**
+ * spear_timer_disable - disables timer
+ * @timer: timer
+ *
+ * The API disables the functional clock of the timer
+ */
+int spear_timer_disable(struct spear_timer *timer)
+{
+ if (!timer)
+ return -ENODEV;
+
+ if (!timer->enabled)
+ return -EINVAL;
+
+ clk_disable(timer->fclk);
+
+ timer->enabled = 0;
+
+ return 0;
+}
+
+/**
+ * spear_timer_request - request for a timer
+ *
+ * This API returns a timer which is available, returns NULL if none is
+ * available
+ */
+struct spear_timer *spear_timer_request(void)
+{
+ struct spear_timer *timer = NULL;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&spear_timer_lock, flags);
+
+ for (i = 0; i < spear_timer_count; i++) {
+ if (spear_timers[i].reserved)
+ continue;
+
+ timer = &spear_timers[i];
+ timer->reserved = 1;
+ break;
+ }
+
+ spin_unlock_irqrestore(&spear_timer_lock, flags);
+
+ if (timer != NULL)
+ spear_timer_prepare(timer);
+
+ return timer;
+}
+EXPORT_SYMBOL(spear_timer_request);
+
+/**
+ * spear_timer_request_specific - request for a specific timer
+ * @id: timer id requested, 1 onwards
+ *
+ * This API returns specific timer which is requested, returns NULL if it is
+ * not available.
+ */
+struct spear_timer *spear_timer_request_specific(int id)
+{
+ struct spear_timer *timer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&spear_timer_lock, flags);
+
+ if (id < 0 || id >= spear_timer_count ||
+ spear_timers[id].reserved) {
+ spin_unlock_irqrestore(&spear_timer_lock, flags);
+ printk(KERN_ERR "BUG: unable to get timer %d\n", id);
+ dump_stack();
+ return NULL;
+ }
+
+ timer = &spear_timers[id];
+ timer->reserved = 1;
+ spin_unlock_irqrestore(&spear_timer_lock, flags);
+
+ spear_timer_prepare(timer);
+
+ return timer;
+}
+EXPORT_SYMBOL(spear_timer_request_specific);
+
+/**
+ * spear_timer_free - free the timer
+ * @timer: timer which should be freed
+ *
+ * Applications should free the timer when not in use. The API also resets and
+ * disables the timer clock
+ */
+int spear_timer_free(struct spear_timer *timer)
+{
+ if (!timer)
+ return -ENODEV;
+
+ WARN_ON(!timer->reserved);
+
+ spear_timer_reset(timer);
+ spear_timer_disable(timer);
+
+ timer->reserved = 0;
+
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_free);
+
+/**
+ * spear_timer_get_irq - get the irq number associated
+ * @timer: return the irq number for this timer
+ *
+ * The application may require the irq associated with a timer to register it
+ * with the OS interrupt framework.
+ */
+int spear_timer_get_irq(struct spear_timer *timer)
+{
+ return (timer) ? timer->irq : -ENODEV;
+}
+EXPORT_SYMBOL(spear_timer_get_irq);
+
+/**
+ * spear_timer_get_fclk - return the functional clock
+ * @timer: timer for which fclk is required
+ *
+ * Returns the functional clock of the timer at which it is operating.
+ * Functional clock represents the actual clock at which the timer is
+ * operating. The count period depends on this clock
+ */
+struct clk *spear_timer_get_fclk(struct spear_timer *timer)
+{
+ if (!timer)
+ return NULL;
+
+ return timer->fclk;
+}
+EXPORT_SYMBOL(spear_timer_get_fclk);
+
+/**
+ * spear_timer_start - start the timer operation
+ * @timer: timer to start
+ *
+ * The timer shall start operating only after calling this API
+ */
+int spear_timer_start(struct spear_timer *timer)
+{
+ u16 val;
+
+ if (!timer)
+ return -ENODEV;
+
+ val = spear_timer_read_reg(timer, GPT_CTRL_OFF);
+ if (!(val & GPT_CTRL_ENABLE)) {
+ val |= GPT_CTRL_ENABLE;
+ spear_timer_write_reg(timer, GPT_CTRL_OFF, val);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_start);
+
+/**
+ * spear_timer_stop - stop the timer operation
+ * @timer: timer to stop
+ *
+ * This API can be used to stop the timer operation
+ */
+int spear_timer_stop(struct spear_timer *timer)
+{
+ u16 val;
+
+ if (!timer)
+ return -ENODEV;
+
+ val = spear_timer_read_reg(timer, GPT_CTRL_OFF);
+ if (val & GPT_CTRL_ENABLE) {
+ val &= ~GPT_CTRL_ENABLE;
+ spear_timer_write_reg(timer, GPT_CTRL_OFF, val);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_stop);
+
+/**
+ * spear_timer_set_source - select the proper source clock
+ * @timer: timer
+ * @source: the clock cource
+ *
+ * source specifies the clock which has to be selected as the functional clock
+ * of timer. The available choice are 48 MHz (PLL3) output or AHB clock.
+ *
+ */
+int spear_timer_set_source(struct spear_timer *timer, int source)
+{
+ if (source < 0 || source >= 3)
+ return -EINVAL;
+
+ if (!timer)
+ return -ENODEV;
+
+ clk_disable(timer->fclk);
+ clk_set_parent(timer->fclk, spear_source_clocks[source]);
+ clk_enable(timer->fclk);
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_set_source);
+
+/**
+ * spear_timer_set_load - program the count value of timer
+ * @timer: timer
+ * @autoreload: boolean, whether the count will be reloaded
+ * @load: the actual count deciding the time period
+ *
+ * The timer will be programmed as per the value in load. The time period will
+ * depend on the clock and prescaler selected.
+ */
+int spear_timer_set_load(struct spear_timer *timer, int autoreload,
+ u16 load)
+{
+ u16 val;
+
+ if (!timer)
+ return -ENODEV;
+
+ val = spear_timer_read_reg(timer, GPT_CTRL_OFF);
+ if (autoreload)
+ val &= ~GPT_CTRL_MODE_AR;
+ else
+ val |= GPT_CTRL_MODE_AR;
+
+ spear_timer_write_reg(timer, GPT_LOAD_OFF, load);
+ spear_timer_write_reg(timer, GPT_CTRL_OFF, val);
+
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_set_load);
+
+/**
+ * spear_timer_set_load_start - program the count value of timer and start
+ * @timer: timer
+ * @autoreload: boolean, whether the count will be reloaded
+ * @load: the actual count deciding the time period
+ *
+ * The timer will be programmed as per the value in load and the operation will
+ * be started.
+ */
+int spear_timer_set_load_start(struct spear_timer *timer, int autoreload,
+ u16 load)
+{
+ u16 val;
+
+ if (!timer)
+ return -ENODEV;
+
+ val = spear_timer_read_reg(timer, GPT_CTRL_OFF);
+ if (autoreload)
+ val &= ~GPT_CTRL_MODE_AR;
+ else
+ val |= GPT_CTRL_MODE_AR;
+
+ val |= GPT_CTRL_ENABLE;
+
+ spear_timer_write_reg(timer, GPT_LOAD_OFF, load);
+ spear_timer_write_reg(timer, GPT_CTRL_OFF, val);
+
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_set_load_start);
+
+/**
+ * spear_timer_match_irq - enable the match interrupt
+ * @timer: timer
+ * @enable: boolean, 1 for enable
+ *
+ * If application wants to enable the interrupt on count match then this API
+ * should be called
+ */
+int spear_timer_match_irq(struct spear_timer *timer, int enable)
+{
+ u16 val;
+
+ if (!timer)
+ return -ENODEV;
+
+ val = spear_timer_read_reg(timer, GPT_CTRL_OFF);
+ if (enable)
+ val |= GPT_CTRL_MATCH_INT;
+ else
+ val &= ~GPT_CTRL_MATCH_INT;
+ spear_timer_write_reg(timer, GPT_CTRL_OFF, val);
+
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_match_irq);
+
+/**
+ * spear_timer_set_prescaler - set the prescaler for the timer
+ * @timer: timer
+ * @prescaler: the division factor to be applied on the src clk
+ *
+ * This API can be used to program the prescaler for the timer. Its value can
+ * be from 1 to 8 signifying division by 2^prescaler
+ */
+int spear_timer_set_prescaler(struct spear_timer *timer, int prescaler)
+{
+ u16 val;
+
+ if (!timer)
+ return -ENODEV;
+
+ val = spear_timer_read_reg(timer, GPT_CTRL_OFF);
+ if (prescaler >= 0x00 && prescaler <= 0x08) {
+ val &= 0xFFF0;
+ val |= prescaler;
+ } else {
+ printk(KERN_ERR "Invalid prescaler\n");
+ }
+
+ timer->prescaler = val & 0xF;
+ spear_timer_write_reg(timer, GPT_CTRL_OFF, val);
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_set_prescaler);
+
+/**
+ * spear_timer_read_status - read the interrupt status
+ * @timer: timer
+ *
+ * This API can be used to read the interrupt status of timer. Currently only
+ * match interrupt, at offset 0, is part of this.
+ */
+int spear_timer_read_status(struct spear_timer *timer)
+{
+ u16 val;
+
+ if (!timer)
+ return -ENODEV;
+
+ val = spear_timer_read_reg(timer, GPT_INT_OFF);
+
+ return val;
+}
+EXPORT_SYMBOL(spear_timer_read_status);
+
+/**
+ * spear_timer_clear_status - write to the interrupt status reg to clear
+ * @timer: timer
+ * @value: value to be written
+ *
+ * The API can be used to clear the match interrupt status by writing a value
+ * 0.
+ */
+int spear_timer_clear_status(struct spear_timer *timer, u16 value)
+{
+ if (!timer)
+ return -ENODEV;
+
+ spear_timer_write_reg(timer, GPT_INT_OFF, value);
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_clear_status);
+
+/**
+ * spear_timer_read_counter - get the current count value
+ * @timer: timer
+ *
+ * The API returns the current count value of the timer. One has to remember
+ * that if the timer is operating on asynchronous clock source then there is a
+ * probability that the application may get some junk count value. This is due
+ * to the fact that the count register is being accessed by two independent
+ * clock, one driving the timer (48MHz) and the other on which this register is
+ * read (system AHB clock). For more details refer GPT Application note.
+ */
+int spear_timer_read_counter(struct spear_timer *timer)
+{
+ u16 val;
+
+ if (!timer)
+ return -ENODEV;
+
+ val = spear_timer_read_reg(timer, GPT_COUNT_OFF);
+
+ return val;
+}
+EXPORT_SYMBOL(spear_timer_read_counter);
+
+/**
+ * spear_timer_active - is timer active
+ * @timer: timer
+ *
+ * This API can be used to find whether a timer is already enabled and is
+ * active i.e. it is under operation
+ */
+int spear_timer_active(struct spear_timer *timer)
+{
+ if (!timer)
+ return 0;
+
+ if (!timer->enabled)
+ return 0;
+
+ if (spear_timer_read_reg(timer, GPT_CTRL_OFF) & GPT_CTRL_ENABLE)
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(spear_timer_active);
+
+/**
+ * spear_timer_init - initialize the set of timers
+ * @timer: list of timers to be intialized
+ * @count: number of timers supported in platform
+ *
+ * This API must not be called by user and it is called only once by the
+ * platform specific intialization code.
+ */
+int __init spear_timer_init(struct spear_timer *timers, int count)
+{
+ struct spear_timer *timer;
+ int i;
+ int mtu; /* timer unit */
+ char dev_id[16];
+
+ spin_lock_init(&spear_timer_lock);
+
+ spear_timers = timers;
+ spear_timer_count = count;
+
+ for (i = 0; src_clk_con_id[i] != NULL; i++)
+ spear_source_clocks[i] = clk_get(NULL, src_clk_con_id[i]);
+
+ for (i = 0; i < spear_timer_count; i++) {
+ timer = &spear_timers[i];
+ timer->io_base = (void __iomem *)ioremap(timer->phys_base,
+ SZ_1K);
+ if (!timer->io_base) {
+ printk(KERN_ERR "BUG:ioremap failed for timer:%d\n", i);
+ continue;
+ }
+
+ /* each mtu has 2 timers with same set of clocks */
+ mtu = i >> 1;
+
+ sprintf(dev_id, "gpt%d", mtu);
+ timer->fclk = clk_get_sys(dev_id, NULL);
+ }
+
+ return 0;
+}
diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c
new file mode 100644
index 0000000..d89ac17
--- /dev/null
+++ b/arch/arm/plat-spear/time.c
@@ -0,0 +1,197 @@
+/*
+ * arch/arm/plat-spear/time.c
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Shiraz Hashim<shiraz.hashim at st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/irq.h>
+#include <asm/mach/time.h>
+#include <mach/irqs.h>
+#include <mach/hardware.h>
+#include <mach/spear.h>
+#include <mach/generic.h>
+#include <plat/gpt.h>
+
+static void clockevent_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk_event_dev);
+static int clockevent_next_event(unsigned long evt,
+ struct clock_event_device *clk_event_dev);
+
+/*
+ * Timer0 and Timer1 both belong to same mtu in cpu subbsystem. Further they
+ * share same functional clock. Any change in one's functional clock will also
+ * affect other timer.
+ */
+static struct spear_timer *spear_timer_clkevt;
+static struct spear_timer *spear_timer_clksrc;
+
+/*
+ * Clock Source
+ */
+static cycle_t clocksource_read_cycles(struct clocksource *cs)
+{
+ return (cycle_t) spear_timer_read_counter(spear_timer_clksrc);
+}
+
+static struct clocksource clksrc = {
+ .name = "clock source",
+ .rating = 200, /* its a pretty decent clock */
+ .read = clocksource_read_cycles,
+ .mask = 0xFFFF, /* 16 bits */
+ .mult = 0, /* to be computed */
+ .shift = 10,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void spear_clocksource_init(void)
+{
+ static struct spear_timer *timer;
+ u32 tick_rate;
+
+ timer = spear_timer_request_specific(1);
+ BUG_ON(timer == NULL);
+ spear_timer_clksrc = timer;
+
+ spear_timer_set_source(timer, SPEAR_TIMER_SRC_PLL3_CLK);
+ spear_timer_set_prescaler(timer, GPT_CTRL_PRESCALER256);
+
+ /* find out actual clock driving Timer */
+ tick_rate = clk_get_rate(spear_timer_get_fclk(timer));
+ tick_rate >>= timer->prescaler;
+
+ spear_timer_set_load_start(timer, 1, 0xFFFF); /* 16 bit maximum */
+
+ clksrc.mult =
+ clocksource_khz2mult((tick_rate / 1000), clksrc.shift);
+
+ /* register the clocksource */
+ clocksource_register(&clksrc);
+}
+
+/*
+* Clock Event
+*/
+static struct clock_event_device clkevt = {
+ .name = "clock_event",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = clockevent_set_mode,
+ .set_next_event = clockevent_next_event,
+ .shift = 20,
+};
+
+static void clockevent_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk_event_dev)
+{
+ u32 period;
+ struct spear_timer *timer = spear_timer_clkevt;
+
+ if (timer)
+ return;
+
+ spear_timer_stop(timer);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ period = clk_get_rate(spear_timer_get_fclk(timer)) / HZ;
+ period >>= timer->prescaler;
+
+ spear_timer_match_irq(timer, 1);
+ spear_timer_set_load_start(timer, 1, period);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ spear_timer_match_irq(timer, 1);
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+
+ default:
+ printk(KERN_ERR "BUG: Invalid mode requested\n");
+ break;
+ }
+}
+
+static int clockevent_next_event(unsigned long cycles,
+ struct clock_event_device *clk_event_dev)
+{
+ spear_timer_set_load_start(spear_timer_clkevt, 0, (u16) cycles);
+
+ return 0;
+}
+
+static irqreturn_t spear_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &clkevt;
+ struct spear_timer *timer = (struct spear_timer *)dev_id;
+
+ spear_timer_clear_status(timer, GPT_STATUS_MATCH);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction spear_timer_irq = {
+ .name = "gp_timer",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = spear_timer_interrupt
+};
+
+static void __init spear_clockevent_init(void)
+{
+ struct spear_timer *timer;
+ u32 tick_rate;
+
+ timer = spear_timer_request_specific(0);
+ BUG_ON(timer == NULL);
+ spear_timer_clkevt = timer;
+
+ spear_timer_set_source(timer, SPEAR_TIMER_SRC_PLL3_CLK);
+ spear_timer_set_prescaler(timer, GPT_CTRL_PRESCALER16);
+
+ tick_rate = clk_get_rate(spear_timer_get_fclk(timer));
+ tick_rate >>= timer->prescaler;
+
+ clkevt.mult = div_sc(tick_rate, NSEC_PER_SEC,
+ clkevt.shift);
+ clkevt.max_delta_ns = clockevent_delta2ns(0xfff0,
+ &clkevt);
+ clkevt.min_delta_ns = clockevent_delta2ns(3, &clkevt);
+
+ clkevt.cpumask = cpumask_of(0);
+ clockevents_register_device(&clkevt);
+
+ spear_timer_irq.dev_id = (void *)timer;
+
+ setup_irq(spear_timer_get_irq(timer), &spear_timer_irq);
+ spear_timer_match_irq(timer, 1);
+}
+
+void __init spear_setup_timer(void)
+{
+ /* Initialize all General Purpose Timers */
+ spear_gpt_init();
+
+ spear_clockevent_init();
+ spear_clocksource_init();
+}
+
+struct sys_timer spear_sys_timer = {
+ .init = spear_setup_timer,
+};
--
1.6.0.2
More information about the linux-arm-kernel
mailing list