PageRenderTime 23ms CodeModel.GetById 12ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/arm/mach-ks8695/time.c

https://github.com/AICP/kernel_google_msm
C | 130 lines | 65 code | 23 blank | 42 comment | 4 complexity | f3526e52dc3fd7105af4b3a59d266b43 MD5 | raw file
  1/*
  2 * arch/arm/mach-ks8695/time.c
  3 *
  4 * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk>
  5 * Copyright (C) 2006 Simtec Electronics
  6 *
  7 * This program is free software; you can redistribute it and/or modify
  8 * it under the terms of the GNU General Public License as published by
  9 * the Free Software Foundation; either version 2 of the License, or
 10 * (at your option) any later version.
 11 *
 12 * This program is distributed in the hope that it will be useful,
 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 * GNU General Public License for more details.
 16 *
 17 * You should have received a copy of the GNU General Public License
 18 * along with this program; if not, write to the Free Software
 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 20 */
 21
 22#include <linux/init.h>
 23#include <linux/interrupt.h>
 24#include <linux/irq.h>
 25#include <linux/kernel.h>
 26#include <linux/sched.h>
 27#include <linux/io.h>
 28
 29#include <asm/mach/time.h>
 30#include <asm/system_misc.h>
 31
 32#include <mach/regs-timer.h>
 33#include <mach/regs-irq.h>
 34
 35#include "generic.h"
 36
 37/*
 38 * Returns number of ms since last clock interrupt.  Note that interrupts
 39 * will have been disabled by do_gettimeoffset()
 40 */
 41static unsigned long ks8695_gettimeoffset (void)
 42{
 43	unsigned long elapsed, tick2, intpending;
 44
 45	/*
 46	 * Get the current number of ticks.  Note that there is a race
 47	 * condition between us reading the timer and checking for an
 48	 * interrupt.  We solve this by ensuring that the counter has not
 49	 * reloaded between our two reads.
 50	 */
 51	elapsed = __raw_readl(KS8695_TMR_VA + KS8695_T1TC) + __raw_readl(KS8695_TMR_VA + KS8695_T1PD);
 52	do {
 53		tick2 = elapsed;
 54		intpending = __raw_readl(KS8695_IRQ_VA + KS8695_INTST) & (1 << KS8695_IRQ_TIMER1);
 55		elapsed = __raw_readl(KS8695_TMR_VA + KS8695_T1TC) + __raw_readl(KS8695_TMR_VA + KS8695_T1PD);
 56	} while (elapsed > tick2);
 57
 58	/* Convert to number of ticks expired (not remaining) */
 59	elapsed = (CLOCK_TICK_RATE / HZ) - elapsed;
 60
 61	/* Is interrupt pending?  If so, then timer has been reloaded already. */
 62	if (intpending)
 63		elapsed += (CLOCK_TICK_RATE / HZ);
 64
 65	/* Convert ticks to usecs */
 66	return (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
 67}
 68
 69/*
 70 * IRQ handler for the timer.
 71 */
 72static irqreturn_t ks8695_timer_interrupt(int irq, void *dev_id)
 73{
 74	timer_tick();
 75	return IRQ_HANDLED;
 76}
 77
 78static struct irqaction ks8695_timer_irq = {
 79	.name		= "ks8695_tick",
 80	.flags		= IRQF_DISABLED | IRQF_TIMER,
 81	.handler	= ks8695_timer_interrupt,
 82};
 83
 84static void ks8695_timer_setup(void)
 85{
 86	unsigned long tmout = CLOCK_TICK_RATE / HZ;
 87	unsigned long tmcon;
 88
 89	/* disable timer1 */
 90	tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
 91	__raw_writel(tmcon & ~TMCON_T1EN, KS8695_TMR_VA + KS8695_TMCON);
 92
 93	__raw_writel(tmout / 2, KS8695_TMR_VA + KS8695_T1TC);
 94	__raw_writel(tmout / 2, KS8695_TMR_VA + KS8695_T1PD);
 95
 96	/* re-enable timer1 */
 97	__raw_writel(tmcon | TMCON_T1EN, KS8695_TMR_VA + KS8695_TMCON);
 98}
 99
100static void __init ks8695_timer_init (void)
101{
102	ks8695_timer_setup();
103
104	/* Enable timer interrupts */
105	setup_irq(KS8695_IRQ_TIMER1, &ks8695_timer_irq);
106}
107
108struct sys_timer ks8695_timer = {
109	.init		= ks8695_timer_init,
110	.offset		= ks8695_gettimeoffset,
111	.resume		= ks8695_timer_setup,
112};
113
114void ks8695_restart(char mode, const char *cmd)
115{
116	unsigned int reg;
117
118	if (mode == 's')
119		soft_restart(0);
120
121	/* disable timer0 */
122	reg = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
123	__raw_writel(reg & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
124
125	/* enable watchdog mode */
126	__raw_writel((10 << 8) | T0TC_WATCHDOG, KS8695_TMR_VA + KS8695_T0TC);
127
128	/* re-enable timer0 */
129	__raw_writel(reg | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
130}