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(>641xx_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(>641xx_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(>641xx_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(>641xx_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(>641xx_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(>641xx_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(>641xx_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(>641xx_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 = >641xx_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 = >641xx_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(>641xx_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