162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/***************************************************************************/ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* 562306a36Sopenharmony_ci * pit.c -- Freescale ColdFire PIT timer. Currently this type of 662306a36Sopenharmony_ci * hardware timer only exists in the Freescale ColdFire 762306a36Sopenharmony_ci * 5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire 862306a36Sopenharmony_ci * family members will probably use it too. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com) 1162306a36Sopenharmony_ci * Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com) 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/***************************************************************************/ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/sched.h> 1862306a36Sopenharmony_ci#include <linux/param.h> 1962306a36Sopenharmony_ci#include <linux/init.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include <linux/irq.h> 2262306a36Sopenharmony_ci#include <linux/clockchips.h> 2362306a36Sopenharmony_ci#include <asm/machdep.h> 2462306a36Sopenharmony_ci#include <asm/io.h> 2562306a36Sopenharmony_ci#include <asm/coldfire.h> 2662306a36Sopenharmony_ci#include <asm/mcfpit.h> 2762306a36Sopenharmony_ci#include <asm/mcfsim.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/***************************************************************************/ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * By default use timer1 as the system clock timer. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci#define FREQ ((MCF_CLK / 2) / 64) 3562306a36Sopenharmony_ci#define TA(a) (MCFPIT_BASE1 + (a)) 3662306a36Sopenharmony_ci#define PIT_CYCLES_PER_JIFFY (FREQ / HZ) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic u32 pit_cnt; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * Initialize the PIT timer. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * This is also called after resume to bring the PIT into operation again. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int cf_pit_set_periodic(struct clock_event_device *evt) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); 4962306a36Sopenharmony_ci __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR)); 5062306a36Sopenharmony_ci __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | 5162306a36Sopenharmony_ci MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | 5262306a36Sopenharmony_ci MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); 5362306a36Sopenharmony_ci return 0; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int cf_pit_set_oneshot(struct clock_event_device *evt) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); 5962306a36Sopenharmony_ci __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | 6062306a36Sopenharmony_ci MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int cf_pit_shutdown(struct clock_event_device *evt) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * Program the next event in oneshot mode 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * Delta is given in PIT ticks 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_cistatic int cf_pit_next_event(unsigned long delta, 7662306a36Sopenharmony_ci struct clock_event_device *evt) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci __raw_writew(delta, TA(MCFPIT_PMR)); 7962306a36Sopenharmony_ci return 0; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistruct clock_event_device cf_pit_clockevent = { 8362306a36Sopenharmony_ci .name = "pit", 8462306a36Sopenharmony_ci .features = CLOCK_EVT_FEAT_PERIODIC | 8562306a36Sopenharmony_ci CLOCK_EVT_FEAT_ONESHOT, 8662306a36Sopenharmony_ci .set_state_shutdown = cf_pit_shutdown, 8762306a36Sopenharmony_ci .set_state_periodic = cf_pit_set_periodic, 8862306a36Sopenharmony_ci .set_state_oneshot = cf_pit_set_oneshot, 8962306a36Sopenharmony_ci .set_next_event = cf_pit_next_event, 9062306a36Sopenharmony_ci .shift = 32, 9162306a36Sopenharmony_ci .irq = MCF_IRQ_PIT1, 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/***************************************************************************/ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic irqreturn_t pit_tick(int irq, void *dummy) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct clock_event_device *evt = &cf_pit_clockevent; 10162306a36Sopenharmony_ci u16 pcsr; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Reset the ColdFire timer */ 10462306a36Sopenharmony_ci pcsr = __raw_readw(TA(MCFPIT_PCSR)); 10562306a36Sopenharmony_ci __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR)); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci pit_cnt += PIT_CYCLES_PER_JIFFY; 10862306a36Sopenharmony_ci evt->event_handler(evt); 10962306a36Sopenharmony_ci return IRQ_HANDLED; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/***************************************************************************/ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic u64 pit_read_clk(struct clocksource *cs) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci unsigned long flags; 11762306a36Sopenharmony_ci u32 cycles; 11862306a36Sopenharmony_ci u16 pcntr; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci local_irq_save(flags); 12162306a36Sopenharmony_ci pcntr = __raw_readw(TA(MCFPIT_PCNTR)); 12262306a36Sopenharmony_ci cycles = pit_cnt; 12362306a36Sopenharmony_ci local_irq_restore(flags); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return cycles + PIT_CYCLES_PER_JIFFY - pcntr; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/***************************************************************************/ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic struct clocksource pit_clk = { 13162306a36Sopenharmony_ci .name = "pit", 13262306a36Sopenharmony_ci .rating = 100, 13362306a36Sopenharmony_ci .read = pit_read_clk, 13462306a36Sopenharmony_ci .mask = CLOCKSOURCE_MASK(32), 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/***************************************************************************/ 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_civoid hw_timer_init(void) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci int ret; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id()); 14462306a36Sopenharmony_ci cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32); 14562306a36Sopenharmony_ci cf_pit_clockevent.max_delta_ns = 14662306a36Sopenharmony_ci clockevent_delta2ns(0xFFFF, &cf_pit_clockevent); 14762306a36Sopenharmony_ci cf_pit_clockevent.max_delta_ticks = 0xFFFF; 14862306a36Sopenharmony_ci cf_pit_clockevent.min_delta_ns = 14962306a36Sopenharmony_ci clockevent_delta2ns(0x3f, &cf_pit_clockevent); 15062306a36Sopenharmony_ci cf_pit_clockevent.min_delta_ticks = 0x3f; 15162306a36Sopenharmony_ci clockevents_register_device(&cf_pit_clockevent); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci ret = request_irq(MCF_IRQ_PIT1, pit_tick, IRQF_TIMER, "timer", NULL); 15462306a36Sopenharmony_ci if (ret) { 15562306a36Sopenharmony_ci pr_err("Failed to request irq %d (timer): %pe\n", MCF_IRQ_PIT1, 15662306a36Sopenharmony_ci ERR_PTR(ret)); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci clocksource_register_hz(&pit_clk, FREQ); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/***************************************************************************/ 163