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 32static irqreturn_t 33stmp3xxx_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 58static cycle_t stmp3xxx_clock_read(struct clocksource *cs) 59{ 60 return ~((__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1) 61 & 0xFFFF0000) >> 16); 62} 63 64static int 65stmp3xxx_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 73static void 74stmp3xxx_timrot_set_mode(enum clock_event_mode mode, 75 struct clock_event_device *dev) 76{ 77} 78 79static 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 87static struct clocksource cksrc_stmp3xxx = { 88 .name = "cksrc_stmp3xxx", 89 .rating = 250, 90 .read = stmp3xxx_clock_read, 91 .mask = CLOCKSOURCE_MASK(16), 92 .shift = 10, 93 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 94}; 95 96static struct irqaction stmp3xxx_timer_irq = { 97 .name = "stmp3xxx_timer", 98 .flags = IRQF_DISABLED | IRQF_TIMER, 99 .handler = stmp3xxx_timer_interrupt, 100 .dev_id = &ckevt_timrot, 101}; 102 103 104/* 105 * Set up timer interrupt, and return the current time in seconds. 106 */ 107static void __init stmp3xxx_init_timer(void) 108{ 109 cksrc_stmp3xxx.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 110 cksrc_stmp3xxx.shift); 111 ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 112 ckevt_timrot.shift); 113 ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot); 114 ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot); 115 ckevt_timrot.cpumask = cpumask_of(0); 116 117 stmp3xxx_reset_block(REGS_TIMROT_BASE, false); 118 119 /* clear two timers */ 120 __raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0); 121 __raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1); 122 123 /* configure them */ 124 __raw_writel( 125 (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */ 126 BM_TIMROT_TIMCTRLn_RELOAD | 127 BM_TIMROT_TIMCTRLn_UPDATE | 128 BM_TIMROT_TIMCTRLn_IRQ_EN, 129 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0); 130 __raw_writel( 131 (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */ 132 BM_TIMROT_TIMCTRLn_RELOAD | 133 BM_TIMROT_TIMCTRLn_UPDATE | 134 BM_TIMROT_TIMCTRLn_IRQ_EN, 135 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1); 136 137 __raw_writel(CLOCK_TICK_RATE / HZ - 1, 138 REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0); 139 __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1); 140 141 setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq); 142 143 clocksource_register(&cksrc_stmp3xxx); 144 clockevents_register_device(&ckevt_timrot); 145} 146 147#ifdef CONFIG_PM 148 149void stmp3xxx_suspend_timer(void) 150{ 151 stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN | BM_TIMROT_TIMCTRLn_IRQ, 152 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0); 153 stmp3xxx_setl(BM_TIMROT_ROTCTRL_CLKGATE, 154 REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL); 155} 156 157void stmp3xxx_resume_timer(void) 158{ 159 stmp3xxx_clearl(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE, 160 REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL); 161 __raw_writel( 162 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */ 163 BM_TIMROT_TIMCTRLn_RELOAD | 164 BM_TIMROT_TIMCTRLn_UPDATE | 165 BM_TIMROT_TIMCTRLn_IRQ_EN, 166 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0); 167 __raw_writel( 168 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */ 169 BM_TIMROT_TIMCTRLn_RELOAD | 170 BM_TIMROT_TIMCTRLn_UPDATE | 171 BM_TIMROT_TIMCTRLn_IRQ_EN, 172 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1); 173 __raw_writel(CLOCK_TICK_RATE / HZ - 1, 174 REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0); 175 __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1); 176} 177 178#else 179 180#define stmp3xxx_suspend_timer NULL 181#define stmp3xxx_resume_timer NULL 182 183#endif /* CONFIG_PM */ 184 185struct sys_timer stmp3xxx_timer = { 186 .init = stmp3xxx_init_timer, 187 .suspend = stmp3xxx_suspend_timer, 188 .resume = stmp3xxx_resume_timer, 189}; 190