Root/
Source at commit ef60fc3200a68f7ebd2a5a9fff585073f233bb5e created 14 years 3 months ago. By xiangfu, file | |
---|---|
1 | /* |
2 | * linux/arch/mips/jz4740/time.c |
3 | * |
4 | * Setting up the clock on the JZ4740 boards. |
5 | * |
6 | * Copyright (C) 2008 Ingenic Semiconductor Inc. |
7 | * Author: <jlwei@ingenic.cn> |
8 | * |
9 | * This program is free software; you can distribute it and/or modify it |
10 | * under the terms of the GNU General Public License (Version 2) as |
11 | * published by the Free Software Foundation. |
12 | * |
13 | * This program is distributed in the hope it will be useful, but WITHOUT |
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
16 | * for more details. |
17 | * |
18 | * You should have received a copy of the GNU General Public License along |
19 | * with this program; if not, write to the Free Software Foundation, Inc., |
20 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. |
21 | * |
22 | */ |
23 | #include <linux/types.h> |
24 | #include <linux/interrupt.h> |
25 | #include <linux/time.h> |
26 | #include <linux/clockchips.h> |
27 | |
28 | #include <asm/time.h> |
29 | #include <asm/mach-jz4740/regs.h> |
30 | #include <asm/mach-jz4740/jz4740.h> |
31 | |
32 | /* This is for machines which generate the exact clock. */ |
33 | |
34 | #define JZ_TIMER_CHAN 0 |
35 | #define JZ_TIMER_IRQ JZ_IRQ_TCU0 |
36 | |
37 | #define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */ |
38 | |
39 | static struct clocksource clocksource_jz; /* Jz clock source */ |
40 | static struct clock_event_device jz_clockevent_device; /* Jz clock event */ |
41 | |
42 | void (*jz_timer_callback)(void); |
43 | |
44 | static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) |
45 | { |
46 | struct clock_event_device *cd = dev_id; |
47 | |
48 | REG_TCU_TFCR = 1 << JZ_TIMER_CHAN; /* ACK timer */ |
49 | |
50 | if (jz_timer_callback) |
51 | jz_timer_callback(); |
52 | |
53 | cd->event_handler(cd); |
54 | |
55 | return IRQ_HANDLED; |
56 | } |
57 | |
58 | static struct irqaction jz_irqaction = { |
59 | .handler = jz_timer_interrupt, |
60 | .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, |
61 | .name = "jz-timerirq", |
62 | }; |
63 | |
64 | |
65 | cycle_t jz_get_cycles(void) |
66 | { |
67 | /* convert jiffes to jz timer cycles */ |
68 | return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_TCNT(JZ_TIMER_CHAN)); |
69 | } |
70 | |
71 | static struct clocksource clocksource_jz = { |
72 | .name = "jz_clocksource", |
73 | .rating = 300, |
74 | .read = jz_get_cycles, |
75 | .mask = 0xFFFF, |
76 | .shift = 10, |
77 | .flags = CLOCK_SOURCE_WATCHDOG, |
78 | }; |
79 | |
80 | static int __init jz_clocksource_init(void) |
81 | { |
82 | clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); |
83 | clocksource_register(&clocksource_jz); |
84 | return 0; |
85 | } |
86 | |
87 | static int jz_set_next_event(unsigned long evt, |
88 | struct clock_event_device *unused) |
89 | { |
90 | return 0; |
91 | } |
92 | |
93 | static void jz_set_mode(enum clock_event_mode mode, |
94 | struct clock_event_device *evt) |
95 | { |
96 | switch (mode) { |
97 | case CLOCK_EVT_MODE_PERIODIC: |
98 | break; |
99 | case CLOCK_EVT_MODE_ONESHOT: |
100 | case CLOCK_EVT_MODE_UNUSED: |
101 | case CLOCK_EVT_MODE_SHUTDOWN: |
102 | break; |
103 | case CLOCK_EVT_MODE_RESUME: |
104 | break; |
105 | } |
106 | } |
107 | |
108 | static struct clock_event_device jz_clockevent_device = { |
109 | .name = "jz-clockenvent", |
110 | .features = CLOCK_EVT_FEAT_PERIODIC, |
111 | // .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */ |
112 | |
113 | /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ |
114 | .mult = 1, |
115 | .rating = 300, |
116 | .irq = JZ_TIMER_IRQ, |
117 | .set_mode = jz_set_mode, |
118 | .set_next_event = jz_set_next_event, |
119 | }; |
120 | |
121 | static void __init jz_clockevent_init(void) |
122 | { |
123 | struct clock_event_device *cd = &jz_clockevent_device; |
124 | unsigned int cpu = smp_processor_id(); |
125 | |
126 | cd->cpumask = cpumask_of(cpu); |
127 | clockevents_register_device(cd); |
128 | } |
129 | |
130 | static void __init jz_timer_setup(void) |
131 | { |
132 | jz_clocksource_init(); /* init jz clock source */ |
133 | jz_clockevent_init(); /* init jz clock event */ |
134 | |
135 | /* |
136 | * Make irqs happen for the system timer |
137 | */ |
138 | jz_irqaction.dev_id = &jz_clockevent_device; |
139 | setup_irq(JZ_TIMER_IRQ, &jz_irqaction); |
140 | } |
141 | |
142 | |
143 | void __init plat_time_init(void) |
144 | { |
145 | unsigned int latch; |
146 | /* Init timer */ |
147 | latch = ( JZ_TIMER_CLOCK + (HZ>>1)) / HZ; |
148 | |
149 | REG_TCU_TCSR(JZ_TIMER_CHAN) = TCU_TCSR_PRESCALE16 | TCU_TCSR_EXT_EN; |
150 | REG_TCU_TCNT(JZ_TIMER_CHAN) = 0; |
151 | REG_TCU_TDHR(JZ_TIMER_CHAN) = 0; |
152 | REG_TCU_TDFR(JZ_TIMER_CHAN) = latch; |
153 | |
154 | REG_TCU_TMSR = (1 << (JZ_TIMER_CHAN + 16)); /* mask half irq */ |
155 | REG_TCU_TMCR = (1 << JZ_TIMER_CHAN); /* unmask full irq */ |
156 | REG_TCU_TSCR = (1 << JZ_TIMER_CHAN); /* enable timer clock */ |
157 | REG_TCU_TESR = (1 << JZ_TIMER_CHAN); /* start counting up */ |
158 | |
159 | jz_timer_setup(); |
160 | } |
161 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9