1/* 2 * linux/arch/arm/mach-w90x900/time.c 3 * 4 * Based on linux/arch/arm/plat-s3c24xx/time.c by Ben Dooks 5 * 6 * Copyright (c) 2009 Nuvoton technology corporation 7 * All rights reserved. 8 * 9 * Wan ZongShun <mcuos.com@gmail.com> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 */ 17 18#include <linux/kernel.h> 19#include <linux/sched.h> 20#include <linux/init.h> 21#include <linux/interrupt.h> 22#include <linux/err.h> 23#include <linux/clk.h> 24#include <linux/io.h> 25#include <linux/leds.h> 26#include <linux/clocksource.h> 27#include <linux/clockchips.h> 28 29#include <asm/mach-types.h> 30#include <asm/mach/irq.h> 31#include <asm/mach/time.h> 32 33#include <mach/map.h> 34#include <mach/regs-timer.h> 35 36#include "nuc9xx.h" 37 38#define RESETINT 0x1f 39#define PERIOD (0x01 << 27) 40#define ONESHOT (0x00 << 27) 41#define COUNTEN (0x01 << 30) 42#define INTEN (0x01 << 29) 43 44#define TICKS_PER_SEC 100 45#define PRESCALE 0x63 /* Divider = prescale + 1 */ 46 47#define TDR_SHIFT 24 48 49static unsigned int timer0_load; 50 51static int nuc900_clockevent_shutdown(struct clock_event_device *evt) 52{ 53 unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27); 54 55 __raw_writel(val, REG_TCSR0); 56 return 0; 57} 58 59static int nuc900_clockevent_set_oneshot(struct clock_event_device *evt) 60{ 61 unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27); 62 63 val |= (ONESHOT | COUNTEN | INTEN | PRESCALE); 64 65 __raw_writel(val, REG_TCSR0); 66 return 0; 67} 68 69static int nuc900_clockevent_set_periodic(struct clock_event_device *evt) 70{ 71 unsigned int val = __raw_readl(REG_TCSR0) & ~(0x03 << 27); 72 73 __raw_writel(timer0_load, REG_TICR0); 74 val |= (PERIOD | COUNTEN | INTEN | PRESCALE); 75 __raw_writel(val, REG_TCSR0); 76 return 0; 77} 78 79static int nuc900_clockevent_setnextevent(unsigned long evt, 80 struct clock_event_device *clk) 81{ 82 unsigned int val; 83 84 __raw_writel(evt, REG_TICR0); 85 86 val = __raw_readl(REG_TCSR0); 87 val |= (COUNTEN | INTEN | PRESCALE); 88 __raw_writel(val, REG_TCSR0); 89 90 return 0; 91} 92 93static struct clock_event_device nuc900_clockevent_device = { 94 .name = "nuc900-timer0", 95 .features = CLOCK_EVT_FEAT_PERIODIC | 96 CLOCK_EVT_FEAT_ONESHOT, 97 .set_state_shutdown = nuc900_clockevent_shutdown, 98 .set_state_periodic = nuc900_clockevent_set_periodic, 99 .set_state_oneshot = nuc900_clockevent_set_oneshot, 100 .tick_resume = nuc900_clockevent_shutdown, 101 .set_next_event = nuc900_clockevent_setnextevent, 102 .rating = 300, 103}; 104 105/*IRQ handler for the timer*/ 106 107static irqreturn_t nuc900_timer0_interrupt(int irq, void *dev_id) 108{ 109 struct clock_event_device *evt = &nuc900_clockevent_device; 110 111 __raw_writel(0x01, REG_TISR); /* clear TIF0 */ 112 113 evt->event_handler(evt); 114 return IRQ_HANDLED; 115} 116 117static struct irqaction nuc900_timer0_irq = { 118 .name = "nuc900-timer0", 119 .flags = IRQF_TIMER | IRQF_IRQPOLL, 120 .handler = nuc900_timer0_interrupt, 121}; 122 123static void __init nuc900_clockevents_init(void) 124{ 125 unsigned int rate; 126 struct clk *clk = clk_get(NULL, "timer0"); 127 128 BUG_ON(IS_ERR(clk)); 129 130 __raw_writel(0x00, REG_TCSR0); 131 132 clk_enable(clk); 133 rate = clk_get_rate(clk) / (PRESCALE + 1); 134 135 timer0_load = (rate / TICKS_PER_SEC); 136 137 __raw_writel(RESETINT, REG_TISR); 138 setup_irq(IRQ_TIMER0, &nuc900_timer0_irq); 139 140 nuc900_clockevent_device.cpumask = cpumask_of(0); 141 142 clockevents_config_and_register(&nuc900_clockevent_device, rate, 143 0xf, 0xffffffff); 144} 145 146static void __init nuc900_clocksource_init(void) 147{ 148 unsigned int val; 149 unsigned int rate; 150 struct clk *clk = clk_get(NULL, "timer1"); 151 152 BUG_ON(IS_ERR(clk)); 153 154 __raw_writel(0x00, REG_TCSR1); 155 156 clk_enable(clk); 157 rate = clk_get_rate(clk) / (PRESCALE + 1); 158 159 __raw_writel(0xffffffff, REG_TICR1); 160 161 val = __raw_readl(REG_TCSR1); 162 val |= (COUNTEN | PERIOD | PRESCALE); 163 __raw_writel(val, REG_TCSR1); 164 165 clocksource_mmio_init(REG_TDR1, "nuc900-timer1", rate, 200, 166 TDR_SHIFT, clocksource_mmio_readl_down); 167} 168 169void __init nuc900_timer_init(void) 170{ 171 nuc900_clocksource_init(); 172 nuc900_clockevents_init(); 173} 174