1 /*
2  * System timer for Freescale STMP37XX/STMP378X
3  *
4  * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5  *
6  * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7  * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8  */
9 
10 /*
11  * The code contained herein is licensed under the GNU General Public
12  * License. You may obtain a copy of the GNU General Public License
13  * Version 2 or later at the following locations:
14  *
15  * http://www.opensource.org/licenses/gpl-license.html
16  * http://www.gnu.org/copyleft/gpl.html
17  */
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <linux/spinlock.h>
21 #include <linux/clocksource.h>
22 #include <linux/clockchips.h>
23 #include <linux/io.h>
24 #include <linux/irq.h>
25 #include <linux/interrupt.h>
26 
27 #include <asm/mach/time.h>
28 #include <mach/stmp3xxx.h>
29 #include <mach/platform.h>
30 #include <mach/regs-timrot.h>
31 
32 static irqreturn_t
stmp3xxx_timer_interrupt(int irq,void * dev_id)33 stmp3xxx_timer_interrupt(int irq, void *dev_id)
34 {
35 	struct clock_event_device *c = dev_id;
36 
37 	/* timer 0 */
38 	if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0) &
39 			BM_TIMROT_TIMCTRLn_IRQ) {
40 		stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
41 				REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
42 		c->event_handler(c);
43 	}
44 
45 	/* timer 1 */
46 	else if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1)
47 			& BM_TIMROT_TIMCTRLn_IRQ) {
48 		stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
49 				REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
50 		stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN,
51 				REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
52 		__raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
53 	}
54 
55 	return IRQ_HANDLED;
56 }
57 
stmp3xxx_clock_read(struct clocksource * cs)58 static cycle_t stmp3xxx_clock_read(struct clocksource *cs)
59 {
60 	return ~((__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1)
61 				& 0xFFFF0000) >> 16);
62 }
63 
64 static int
stmp3xxx_timrot_set_next_event(unsigned long delta,struct clock_event_device * dev)65 stmp3xxx_timrot_set_next_event(unsigned long delta,
66 		struct clock_event_device *dev)
67 {
68 	/* reload the timer */
69 	__raw_writel(delta, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
70 	return 0;
71 }
72 
73 static void
stmp3xxx_timrot_set_mode(enum clock_event_mode mode,struct clock_event_device * dev)74 stmp3xxx_timrot_set_mode(enum clock_event_mode mode,
75 		struct clock_event_device *dev)
76 {
77 }
78 
79 static struct clock_event_device ckevt_timrot = {
80 	.name		= "timrot",
81 	.features	= CLOCK_EVT_FEAT_ONESHOT,
82 	.shift		= 32,
83 	.set_next_event	= stmp3xxx_timrot_set_next_event,
84 	.set_mode	= stmp3xxx_timrot_set_mode,
85 };
86 
87 static struct clocksource cksrc_stmp3xxx = {
88 	.name           = "cksrc_stmp3xxx",
89 	.rating         = 250,
90 	.read           = stmp3xxx_clock_read,
91 	.mask           = CLOCKSOURCE_MASK(16),
92 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
93 };
94 
95 static struct irqaction stmp3xxx_timer_irq = {
96 	.name		= "stmp3xxx_timer",
97 	.flags		= IRQF_DISABLED | IRQF_TIMER,
98 	.handler	= stmp3xxx_timer_interrupt,
99 	.dev_id		= &ckevt_timrot,
100 };
101 
102 
103 /*
104  * Set up timer interrupt, and return the current time in seconds.
105  */
stmp3xxx_init_timer(void)106 static void __init stmp3xxx_init_timer(void)
107 {
108 	ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
109 				ckevt_timrot.shift);
110 	ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
111 	ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
112 	ckevt_timrot.cpumask = cpumask_of(0);
113 
114 	stmp3xxx_reset_block(REGS_TIMROT_BASE, false);
115 
116 	/* clear two timers */
117 	__raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
118 	__raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
119 
120 	/* configure them */
121 	__raw_writel(
122 		(8 << BP_TIMROT_TIMCTRLn_SELECT) |  /* 32 kHz */
123 		BM_TIMROT_TIMCTRLn_RELOAD |
124 		BM_TIMROT_TIMCTRLn_UPDATE |
125 		BM_TIMROT_TIMCTRLn_IRQ_EN,
126 			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
127 	__raw_writel(
128 		(8 << BP_TIMROT_TIMCTRLn_SELECT) |  /* 32 kHz */
129 		BM_TIMROT_TIMCTRLn_RELOAD |
130 		BM_TIMROT_TIMCTRLn_UPDATE |
131 		BM_TIMROT_TIMCTRLn_IRQ_EN,
132 			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
133 
134 	__raw_writel(CLOCK_TICK_RATE / HZ - 1,
135 			REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
136 	__raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
137 
138 	setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq);
139 
140 	clocksource_register_hz(&cksrc_stmp3xxx, CLOCK_TICK_RATE);
141 	clockevents_register_device(&ckevt_timrot);
142 }
143 
144 #ifdef CONFIG_PM
145 
stmp3xxx_suspend_timer(void)146 void stmp3xxx_suspend_timer(void)
147 {
148 	stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN | BM_TIMROT_TIMCTRLn_IRQ,
149 			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
150 	stmp3xxx_setl(BM_TIMROT_ROTCTRL_CLKGATE,
151 			REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
152 }
153 
stmp3xxx_resume_timer(void)154 void stmp3xxx_resume_timer(void)
155 {
156 	stmp3xxx_clearl(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE,
157 			REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
158 	__raw_writel(
159 		8 << BP_TIMROT_TIMCTRLn_SELECT |  /* 32 kHz */
160 		BM_TIMROT_TIMCTRLn_RELOAD |
161 		BM_TIMROT_TIMCTRLn_UPDATE |
162 		BM_TIMROT_TIMCTRLn_IRQ_EN,
163 			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
164 	__raw_writel(
165 		8 << BP_TIMROT_TIMCTRLn_SELECT |  /* 32 kHz */
166 		BM_TIMROT_TIMCTRLn_RELOAD |
167 		BM_TIMROT_TIMCTRLn_UPDATE |
168 		BM_TIMROT_TIMCTRLn_IRQ_EN,
169 			REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
170 	__raw_writel(CLOCK_TICK_RATE / HZ - 1,
171 			REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
172 	__raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
173 }
174 
175 #else
176 
177 #define stmp3xxx_suspend_timer	NULL
178 #define	stmp3xxx_resume_timer	NULL
179 
180 #endif	/* CONFIG_PM */
181 
182 struct sys_timer stmp3xxx_timer = {
183 	.init		= stmp3xxx_init_timer,
184 	.suspend	= stmp3xxx_suspend_timer,
185 	.resume		= stmp3xxx_resume_timer,
186 };
187