Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * arch/arm/mach-orion/time.c
  3  *
  4  * Core time functions for Marvell Orion System On Chip
  5  *
  6  * Maintainer: Tzachi Perelstein <tzachi@marvell.com>
  7  *
  8  * This file is licensed under the terms of the GNU General Public
  9  * License version 2. This program is licensed "as is" without any
 10  * warranty of any kind, whether express or implied.
 11  */
 12 
 13 #include <linux/kernel.h>
 14 #include <linux/clockchips.h>
 15 #include <linux/interrupt.h>
 16 #include <linux/irq.h>
 17 #include <asm/mach/time.h>
 18 #include <asm/arch/orion.h>
 19 #include "common.h"
 20 
 21 /*
 22  * Timer0: clock_event_device, Tick.
 23  * Timer1: clocksource, Free running.
 24  * WatchDog: Not used.
 25  *
 26  * Timers are counting down.
 27  */
 28 #define CLOCKEVENT      0
 29 #define CLOCKSOURCE     1
 30 
 31 /*
 32  * Timers bits
 33  */
 34 #define BRIDGE_INT_TIMER(x)     (1 << ((x) + 1))
 35 #define TIMER_EN(x)             (1 << ((x) * 2))
 36 #define TIMER_RELOAD_EN(x)      (1 << (((x) * 2) + 1))
 37 #define BRIDGE_INT_TIMER_WD     (1 << 3)
 38 #define TIMER_WD_EN             (1 << 4)
 39 #define TIMER_WD_RELOAD_EN      (1 << 5)
 40 
 41 static cycle_t orion_clksrc_read(void)
 42 {
 43         return (0xffffffff - orion_read(TIMER_VAL(CLOCKSOURCE)));
 44 }
 45 
 46 static struct clocksource orion_clksrc = {
 47         .name           = "orion_clocksource",
 48         .shift          = 20,
 49         .rating         = 300,
 50         .read           = orion_clksrc_read,
 51         .mask           = CLOCKSOURCE_MASK(32),
 52         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 53 };
 54 
 55 static int
 56 orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev)
 57 {
 58         unsigned long flags;
 59 
 60         if (delta == 0)
 61                 return -ETIME;
 62 
 63         local_irq_save(flags);
 64 
 65         /*
 66          * Clear and enable timer interrupt bit
 67          */
 68         orion_write(BRIDGE_CAUSE, ~BRIDGE_INT_TIMER(CLOCKEVENT));
 69         orion_setbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKEVENT));
 70 
 71         /*
 72          * Setup new timer value
 73          */
 74         orion_write(TIMER_VAL(CLOCKEVENT), delta);
 75 
 76         /*
 77          * Disable auto reload and kickoff the timer
 78          */
 79         orion_clrbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKEVENT));
 80         orion_setbits(TIMER_CTRL, TIMER_EN(CLOCKEVENT));
 81 
 82         local_irq_restore(flags);
 83 
 84         return 0;
 85 }
 86 
 87 static void
 88 orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
 89 {
 90         unsigned long flags;
 91 
 92         local_irq_save(flags);
 93 
 94         if (mode == CLOCK_EVT_MODE_PERIODIC) {
 95                 /*
 96                  * Setup latch cycles in timer and enable reload interrupt.
 97                  */
 98                 orion_write(TIMER_VAL_RELOAD(CLOCKEVENT), LATCH);
 99                 orion_write(TIMER_VAL(CLOCKEVENT), LATCH);
100                 orion_setbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKEVENT));
101                 orion_setbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKEVENT) |
102                                           TIMER_EN(CLOCKEVENT));
103         } else {
104                 /*
105                  * Disable timer and interrupt
106                  */
107                 orion_clrbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKEVENT));
108                 orion_write(BRIDGE_CAUSE, ~BRIDGE_INT_TIMER(CLOCKEVENT));
109                 orion_clrbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKEVENT) |
110                                           TIMER_EN(CLOCKEVENT));
111         }
112 
113         local_irq_restore(flags);
114 }
115 
116 static struct clock_event_device orion_clkevt = {
117         .name           = "orion_tick",
118         .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
119         .shift          = 32,
120         .rating         = 300,
121         .cpumask        = CPU_MASK_CPU0,
122         .set_next_event = orion_clkevt_next_event,
123         .set_mode       = orion_clkevt_mode,
124 };
125 
126 static irqreturn_t orion_timer_interrupt(int irq, void *dev_id)
127 {
128         /*
129          * Clear cause bit and do event
130          */
131         orion_write(BRIDGE_CAUSE, ~BRIDGE_INT_TIMER(CLOCKEVENT));
132         orion_clkevt.event_handler(&orion_clkevt);
133         return IRQ_HANDLED;
134 }
135 
136 static struct irqaction orion_timer_irq = {
137         .name           = "orion_tick",
138         .flags          = IRQF_DISABLED | IRQF_TIMER,
139         .handler        = orion_timer_interrupt
140 };
141 
142 static void orion_timer_init(void)
143 {
144         /*
145          * Setup clocksource free running timer (no interrupt on reload)
146          */
147         orion_write(TIMER_VAL(CLOCKSOURCE), 0xffffffff);
148         orion_write(TIMER_VAL_RELOAD(CLOCKSOURCE), 0xffffffff);
149         orion_clrbits(BRIDGE_MASK, BRIDGE_INT_TIMER(CLOCKSOURCE));
150         orion_setbits(TIMER_CTRL, TIMER_RELOAD_EN(CLOCKSOURCE) |
151                                   TIMER_EN(CLOCKSOURCE));
152 
153         /*
154          * Register clocksource
155          */
156         orion_clksrc.mult =
157                 clocksource_hz2mult(CLOCK_TICK_RATE, orion_clksrc.shift);
158 
159         clocksource_register(&orion_clksrc);
160 
161         /*
162          * Connect and enable tick handler
163          */
164         setup_irq(IRQ_ORION_BRIDGE, &orion_timer_irq);
165 
166         /*
167          * Register clockevent
168          */
169         orion_clkevt.mult =
170                 div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, orion_clkevt.shift);
171         orion_clkevt.max_delta_ns =
172                 clockevent_delta2ns(0xfffffffe, &orion_clkevt);
173         orion_clkevt.min_delta_ns =
174                 clockevent_delta2ns(1, &orion_clkevt);
175 
176         clockevents_register_device(&orion_clkevt);
177 }
178 
179 struct sys_timer orion_timer = {
180         .init = orion_timer_init,
181 };
182 
  This page was automatically generated by the LXR engine.