dc21285-timer.c (3253B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * linux/arch/arm/mach-footbridge/dc21285-timer.c 4 * 5 * Copyright (C) 1998 Russell King. 6 * Copyright (C) 1998 Phil Blundell 7 */ 8#include <linux/clockchips.h> 9#include <linux/clocksource.h> 10#include <linux/init.h> 11#include <linux/interrupt.h> 12#include <linux/irq.h> 13#include <linux/sched_clock.h> 14 15#include <asm/irq.h> 16 17#include <asm/hardware/dec21285.h> 18#include <asm/mach/time.h> 19#include <asm/system_info.h> 20 21#include "common.h" 22 23static u64 cksrc_dc21285_read(struct clocksource *cs) 24{ 25 return cs->mask - *CSR_TIMER2_VALUE; 26} 27 28static int cksrc_dc21285_enable(struct clocksource *cs) 29{ 30 *CSR_TIMER2_LOAD = cs->mask; 31 *CSR_TIMER2_CLR = 0; 32 *CSR_TIMER2_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16; 33 return 0; 34} 35 36static void cksrc_dc21285_disable(struct clocksource *cs) 37{ 38 *CSR_TIMER2_CNTL = 0; 39} 40 41static struct clocksource cksrc_dc21285 = { 42 .name = "dc21285_timer2", 43 .rating = 200, 44 .read = cksrc_dc21285_read, 45 .enable = cksrc_dc21285_enable, 46 .disable = cksrc_dc21285_disable, 47 .mask = CLOCKSOURCE_MASK(24), 48 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 49}; 50 51static int ckevt_dc21285_set_next_event(unsigned long delta, 52 struct clock_event_device *c) 53{ 54 *CSR_TIMER1_CLR = 0; 55 *CSR_TIMER1_LOAD = delta; 56 *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16; 57 58 return 0; 59} 60 61static int ckevt_dc21285_shutdown(struct clock_event_device *c) 62{ 63 *CSR_TIMER1_CNTL = 0; 64 return 0; 65} 66 67static int ckevt_dc21285_set_periodic(struct clock_event_device *c) 68{ 69 *CSR_TIMER1_CLR = 0; 70 *CSR_TIMER1_LOAD = (mem_fclk_21285 + 8 * HZ) / (16 * HZ); 71 *CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | 72 TIMER_CNTL_DIV16; 73 return 0; 74} 75 76static struct clock_event_device ckevt_dc21285 = { 77 .name = "dc21285_timer1", 78 .features = CLOCK_EVT_FEAT_PERIODIC | 79 CLOCK_EVT_FEAT_ONESHOT, 80 .rating = 200, 81 .irq = IRQ_TIMER1, 82 .set_next_event = ckevt_dc21285_set_next_event, 83 .set_state_shutdown = ckevt_dc21285_shutdown, 84 .set_state_periodic = ckevt_dc21285_set_periodic, 85 .set_state_oneshot = ckevt_dc21285_shutdown, 86 .tick_resume = ckevt_dc21285_set_periodic, 87}; 88 89static irqreturn_t timer1_interrupt(int irq, void *dev_id) 90{ 91 struct clock_event_device *ce = dev_id; 92 93 *CSR_TIMER1_CLR = 0; 94 95 /* Stop the timer if in one-shot mode */ 96 if (clockevent_state_oneshot(ce)) 97 *CSR_TIMER1_CNTL = 0; 98 99 ce->event_handler(ce); 100 101 return IRQ_HANDLED; 102} 103 104/* 105 * Set up timer interrupt. 106 */ 107void __init footbridge_timer_init(void) 108{ 109 struct clock_event_device *ce = &ckevt_dc21285; 110 unsigned rate = DIV_ROUND_CLOSEST(mem_fclk_21285, 16); 111 112 clocksource_register_hz(&cksrc_dc21285, rate); 113 114 if (request_irq(ce->irq, timer1_interrupt, IRQF_TIMER | IRQF_IRQPOLL, 115 "dc21285_timer1", &ckevt_dc21285)) 116 pr_err("Failed to request irq %d (dc21285_timer1)", ce->irq); 117 118 ce->cpumask = cpumask_of(smp_processor_id()); 119 clockevents_config_and_register(ce, rate, 0x4, 0xffffff); 120} 121 122static u64 notrace footbridge_read_sched_clock(void) 123{ 124 return ~*CSR_TIMER3_VALUE; 125} 126 127void __init footbridge_sched_clock(void) 128{ 129 unsigned rate = DIV_ROUND_CLOSEST(mem_fclk_21285, 16); 130 131 *CSR_TIMER3_LOAD = 0; 132 *CSR_TIMER3_CLR = 0; 133 *CSR_TIMER3_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV16; 134 135 sched_clock_register(footbridge_read_sched_clock, 24, rate); 136}