xref: /openbmc/linux/arch/mips/kernel/cevt-gt641xx.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
116216333SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21097c6acSYoichi Yuasa /*
31097c6acSYoichi Yuasa  *  GT641xx clockevent routines.
41097c6acSYoichi Yuasa  *
5ada8e951SYoichi Yuasa  *  Copyright (C) 2007	Yoichi Yuasa <yuasa@linux-mips.org>
61097c6acSYoichi Yuasa  */
71097c6acSYoichi Yuasa #include <linux/clockchips.h>
81097c6acSYoichi Yuasa #include <linux/init.h>
91097c6acSYoichi Yuasa #include <linux/interrupt.h>
101097c6acSYoichi Yuasa #include <linux/spinlock.h>
11ca4d3e67SDavid Howells #include <linux/irq.h>
121097c6acSYoichi Yuasa 
131097c6acSYoichi Yuasa #include <asm/gt64120.h>
141097c6acSYoichi Yuasa #include <asm/time.h>
151097c6acSYoichi Yuasa 
1634ee4148SRalf Baechle static DEFINE_RAW_SPINLOCK(gt641xx_timer_lock);
171097c6acSYoichi Yuasa static unsigned int gt641xx_base_clock;
181097c6acSYoichi Yuasa 
gt641xx_set_base_clock(unsigned int clock)191097c6acSYoichi Yuasa void gt641xx_set_base_clock(unsigned int clock)
201097c6acSYoichi Yuasa {
211097c6acSYoichi Yuasa 	gt641xx_base_clock = clock;
221097c6acSYoichi Yuasa }
231097c6acSYoichi Yuasa 
gt641xx_timer0_state(void)241097c6acSYoichi Yuasa int gt641xx_timer0_state(void)
251097c6acSYoichi Yuasa {
261097c6acSYoichi Yuasa 	if (GT_READ(GT_TC0_OFS))
271097c6acSYoichi Yuasa 		return 0;
281097c6acSYoichi Yuasa 
291097c6acSYoichi Yuasa 	GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
301097c6acSYoichi Yuasa 	GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK);
311097c6acSYoichi Yuasa 
321097c6acSYoichi Yuasa 	return 1;
331097c6acSYoichi Yuasa }
341097c6acSYoichi Yuasa 
gt641xx_timer0_set_next_event(unsigned long delta,struct clock_event_device * evt)351097c6acSYoichi Yuasa static int gt641xx_timer0_set_next_event(unsigned long delta,
361097c6acSYoichi Yuasa 					 struct clock_event_device *evt)
371097c6acSYoichi Yuasa {
381097c6acSYoichi Yuasa 	u32 ctrl;
391097c6acSYoichi Yuasa 
4034ee4148SRalf Baechle 	raw_spin_lock(&gt641xx_timer_lock);
411097c6acSYoichi Yuasa 
421097c6acSYoichi Yuasa 	ctrl = GT_READ(GT_TC_CONTROL_OFS);
431097c6acSYoichi Yuasa 	ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
441097c6acSYoichi Yuasa 	ctrl |= GT_TC_CONTROL_ENTC0_MSK;
451097c6acSYoichi Yuasa 
461097c6acSYoichi Yuasa 	GT_WRITE(GT_TC0_OFS, delta);
471097c6acSYoichi Yuasa 	GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
481097c6acSYoichi Yuasa 
4934ee4148SRalf Baechle 	raw_spin_unlock(&gt641xx_timer_lock);
501097c6acSYoichi Yuasa 
511097c6acSYoichi Yuasa 	return 0;
521097c6acSYoichi Yuasa }
531097c6acSYoichi Yuasa 
gt641xx_timer0_shutdown(struct clock_event_device * evt)54c88f2fb4SViresh Kumar static int gt641xx_timer0_shutdown(struct clock_event_device *evt)
551097c6acSYoichi Yuasa {
561097c6acSYoichi Yuasa 	u32 ctrl;
571097c6acSYoichi Yuasa 
5834ee4148SRalf Baechle 	raw_spin_lock(&gt641xx_timer_lock);
591097c6acSYoichi Yuasa 
601097c6acSYoichi Yuasa 	ctrl = GT_READ(GT_TC_CONTROL_OFS);
611097c6acSYoichi Yuasa 	ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
621097c6acSYoichi Yuasa 	GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
631097c6acSYoichi Yuasa 
6434ee4148SRalf Baechle 	raw_spin_unlock(&gt641xx_timer_lock);
65c88f2fb4SViresh Kumar 	return 0;
66c88f2fb4SViresh Kumar }
67c88f2fb4SViresh Kumar 
gt641xx_timer0_set_oneshot(struct clock_event_device * evt)68c88f2fb4SViresh Kumar static int gt641xx_timer0_set_oneshot(struct clock_event_device *evt)
69c88f2fb4SViresh Kumar {
70c88f2fb4SViresh Kumar 	u32 ctrl;
71c88f2fb4SViresh Kumar 
72c88f2fb4SViresh Kumar 	raw_spin_lock(&gt641xx_timer_lock);
73c88f2fb4SViresh Kumar 
74c88f2fb4SViresh Kumar 	ctrl = GT_READ(GT_TC_CONTROL_OFS);
75c88f2fb4SViresh Kumar 	ctrl &= ~GT_TC_CONTROL_SELTC0_MSK;
76c88f2fb4SViresh Kumar 	ctrl |= GT_TC_CONTROL_ENTC0_MSK;
77c88f2fb4SViresh Kumar 	GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
78c88f2fb4SViresh Kumar 
79c88f2fb4SViresh Kumar 	raw_spin_unlock(&gt641xx_timer_lock);
80c88f2fb4SViresh Kumar 	return 0;
81c88f2fb4SViresh Kumar }
82c88f2fb4SViresh Kumar 
gt641xx_timer0_set_periodic(struct clock_event_device * evt)83c88f2fb4SViresh Kumar static int gt641xx_timer0_set_periodic(struct clock_event_device *evt)
84c88f2fb4SViresh Kumar {
85c88f2fb4SViresh Kumar 	u32 ctrl;
86c88f2fb4SViresh Kumar 
87c88f2fb4SViresh Kumar 	raw_spin_lock(&gt641xx_timer_lock);
88c88f2fb4SViresh Kumar 
89c88f2fb4SViresh Kumar 	ctrl = GT_READ(GT_TC_CONTROL_OFS);
90c88f2fb4SViresh Kumar 	ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK;
91c88f2fb4SViresh Kumar 	GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
92c88f2fb4SViresh Kumar 
93c88f2fb4SViresh Kumar 	raw_spin_unlock(&gt641xx_timer_lock);
94c88f2fb4SViresh Kumar 	return 0;
951097c6acSYoichi Yuasa }
961097c6acSYoichi Yuasa 
gt641xx_timer0_event_handler(struct clock_event_device * dev)971097c6acSYoichi Yuasa static void gt641xx_timer0_event_handler(struct clock_event_device *dev)
981097c6acSYoichi Yuasa {
991097c6acSYoichi Yuasa }
1001097c6acSYoichi Yuasa 
1011097c6acSYoichi Yuasa static struct clock_event_device gt641xx_timer0_clockevent = {
1021097c6acSYoichi Yuasa 	.name			= "gt641xx-timer0",
103c88f2fb4SViresh Kumar 	.features		= CLOCK_EVT_FEAT_PERIODIC |
104c88f2fb4SViresh Kumar 				  CLOCK_EVT_FEAT_ONESHOT,
1051097c6acSYoichi Yuasa 	.irq			= GT641XX_TIMER0_IRQ,
1061097c6acSYoichi Yuasa 	.set_next_event		= gt641xx_timer0_set_next_event,
107c88f2fb4SViresh Kumar 	.set_state_shutdown	= gt641xx_timer0_shutdown,
108c88f2fb4SViresh Kumar 	.set_state_periodic	= gt641xx_timer0_set_periodic,
109c88f2fb4SViresh Kumar 	.set_state_oneshot	= gt641xx_timer0_set_oneshot,
110c88f2fb4SViresh Kumar 	.tick_resume		= gt641xx_timer0_shutdown,
1111097c6acSYoichi Yuasa 	.event_handler		= gt641xx_timer0_event_handler,
1121097c6acSYoichi Yuasa };
1131097c6acSYoichi Yuasa 
gt641xx_timer0_interrupt(int irq,void * dev_id)1141097c6acSYoichi Yuasa static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
1151097c6acSYoichi Yuasa {
1161097c6acSYoichi Yuasa 	struct clock_event_device *cd = &gt641xx_timer0_clockevent;
1171097c6acSYoichi Yuasa 
1181097c6acSYoichi Yuasa 	cd->event_handler(cd);
1191097c6acSYoichi Yuasa 
1201097c6acSYoichi Yuasa 	return IRQ_HANDLED;
1211097c6acSYoichi Yuasa }
1221097c6acSYoichi Yuasa 
gt641xx_timer0_clockevent_init(void)1231097c6acSYoichi Yuasa static int __init gt641xx_timer0_clockevent_init(void)
1241097c6acSYoichi Yuasa {
1251097c6acSYoichi Yuasa 	struct clock_event_device *cd;
1261097c6acSYoichi Yuasa 
1271097c6acSYoichi Yuasa 	if (!gt641xx_base_clock)
1281097c6acSYoichi Yuasa 		return 0;
1291097c6acSYoichi Yuasa 
1301097c6acSYoichi Yuasa 	GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
1311097c6acSYoichi Yuasa 
1321097c6acSYoichi Yuasa 	cd = &gt641xx_timer0_clockevent;
1331097c6acSYoichi Yuasa 	cd->rating = 200 + gt641xx_base_clock / 10000000;
13411c03a6fSYoichi Yuasa 	clockevent_set_clock(cd, gt641xx_base_clock);
1351097c6acSYoichi Yuasa 	cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
136e4db9253SNicolai Stange 	cd->max_delta_ticks = 0x7fffffff;
1371097c6acSYoichi Yuasa 	cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
138e4db9253SNicolai Stange 	cd->min_delta_ticks = 0x300;
139320ab2b0SRusty Russell 	cd->cpumask = cpumask_of(0);
1401097c6acSYoichi Yuasa 
1411097c6acSYoichi Yuasa 	clockevents_register_device(&gt641xx_timer0_clockevent);
1421097c6acSYoichi Yuasa 
143*ac8fd122Safzal mohammed 	return request_irq(GT641XX_TIMER0_IRQ, gt641xx_timer0_interrupt,
144*ac8fd122Safzal mohammed 			   IRQF_PERCPU | IRQF_TIMER, "gt641xx_timer0", NULL);
1451097c6acSYoichi Yuasa }
1461097c6acSYoichi Yuasa arch_initcall(gt641xx_timer0_clockevent_init);
147