xref: /OK3568_Linux_fs/kernel/drivers/clocksource/h8300_timer8.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  linux/arch/h8300/kernel/cpu/timer/timer8.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Yoshinori Sato <ysato@users.sourcefoge.jp>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *  8bit Timer driver
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/interrupt.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/clockchips.h>
16*4882a593Smuzhiyun #include <linux/clk.h>
17*4882a593Smuzhiyun #include <linux/io.h>
18*4882a593Smuzhiyun #include <linux/of.h>
19*4882a593Smuzhiyun #include <linux/of_address.h>
20*4882a593Smuzhiyun #include <linux/of_irq.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define _8TCR	0
23*4882a593Smuzhiyun #define _8TCSR	2
24*4882a593Smuzhiyun #define TCORA	4
25*4882a593Smuzhiyun #define TCORB	6
26*4882a593Smuzhiyun #define _8TCNT	8
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define CMIEA	6
29*4882a593Smuzhiyun #define CMFA	6
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define FLAG_STARTED (1 << 3)
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define SCALE 64
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a))
36*4882a593Smuzhiyun #define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a))
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun struct timer8_priv {
39*4882a593Smuzhiyun 	struct clock_event_device ced;
40*4882a593Smuzhiyun 	void __iomem *mapbase;
41*4882a593Smuzhiyun 	unsigned long flags;
42*4882a593Smuzhiyun 	unsigned int rate;
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun 
timer8_interrupt(int irq,void * dev_id)45*4882a593Smuzhiyun static irqreturn_t timer8_interrupt(int irq, void *dev_id)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	struct timer8_priv *p = dev_id;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (clockevent_state_oneshot(&p->ced))
50*4882a593Smuzhiyun 		iowrite16be(0x0000, p->mapbase + _8TCR);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	p->ced.event_handler(&p->ced);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	bclr(CMFA, p->mapbase + _8TCSR);
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	return IRQ_HANDLED;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
timer8_set_next(struct timer8_priv * p,unsigned long delta)59*4882a593Smuzhiyun static void timer8_set_next(struct timer8_priv *p, unsigned long delta)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	if (delta >= 0x10000)
62*4882a593Smuzhiyun 		pr_warn("delta out of range\n");
63*4882a593Smuzhiyun 	bclr(CMIEA, p->mapbase + _8TCR);
64*4882a593Smuzhiyun 	iowrite16be(delta, p->mapbase + TCORA);
65*4882a593Smuzhiyun 	iowrite16be(0x0000, p->mapbase + _8TCNT);
66*4882a593Smuzhiyun 	bclr(CMFA, p->mapbase + _8TCSR);
67*4882a593Smuzhiyun 	bset(CMIEA, p->mapbase + _8TCR);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
timer8_enable(struct timer8_priv * p)70*4882a593Smuzhiyun static int timer8_enable(struct timer8_priv *p)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	iowrite16be(0xffff, p->mapbase + TCORA);
73*4882a593Smuzhiyun 	iowrite16be(0x0000, p->mapbase + _8TCNT);
74*4882a593Smuzhiyun 	iowrite16be(0x0c02, p->mapbase + _8TCR);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
timer8_start(struct timer8_priv * p)79*4882a593Smuzhiyun static int timer8_start(struct timer8_priv *p)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	int ret;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	if ((p->flags & FLAG_STARTED))
84*4882a593Smuzhiyun 		return 0;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	ret = timer8_enable(p);
87*4882a593Smuzhiyun 	if (!ret)
88*4882a593Smuzhiyun 		p->flags |= FLAG_STARTED;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	return ret;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
timer8_stop(struct timer8_priv * p)93*4882a593Smuzhiyun static void timer8_stop(struct timer8_priv *p)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	iowrite16be(0x0000, p->mapbase + _8TCR);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
ced_to_priv(struct clock_event_device * ced)98*4882a593Smuzhiyun static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	return container_of(ced, struct timer8_priv, ced);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
timer8_clock_event_start(struct timer8_priv * p,unsigned long delta)103*4882a593Smuzhiyun static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	timer8_start(p);
106*4882a593Smuzhiyun 	timer8_set_next(p, delta);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
timer8_clock_event_shutdown(struct clock_event_device * ced)109*4882a593Smuzhiyun static int timer8_clock_event_shutdown(struct clock_event_device *ced)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	timer8_stop(ced_to_priv(ced));
112*4882a593Smuzhiyun 	return 0;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
timer8_clock_event_periodic(struct clock_event_device * ced)115*4882a593Smuzhiyun static int timer8_clock_event_periodic(struct clock_event_device *ced)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	struct timer8_priv *p = ced_to_priv(ced);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	pr_info("%s: used for periodic clock events\n", ced->name);
120*4882a593Smuzhiyun 	timer8_stop(p);
121*4882a593Smuzhiyun 	timer8_clock_event_start(p, (p->rate + HZ/2) / HZ);
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	return 0;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
timer8_clock_event_oneshot(struct clock_event_device * ced)126*4882a593Smuzhiyun static int timer8_clock_event_oneshot(struct clock_event_device *ced)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	struct timer8_priv *p = ced_to_priv(ced);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	pr_info("%s: used for oneshot clock events\n", ced->name);
131*4882a593Smuzhiyun 	timer8_stop(p);
132*4882a593Smuzhiyun 	timer8_clock_event_start(p, 0x10000);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	return 0;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
timer8_clock_event_next(unsigned long delta,struct clock_event_device * ced)137*4882a593Smuzhiyun static int timer8_clock_event_next(unsigned long delta,
138*4882a593Smuzhiyun 				   struct clock_event_device *ced)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	struct timer8_priv *p = ced_to_priv(ced);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	BUG_ON(!clockevent_state_oneshot(ced));
143*4882a593Smuzhiyun 	timer8_set_next(p, delta - 1);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun static struct timer8_priv timer8_priv = {
149*4882a593Smuzhiyun 	.ced = {
150*4882a593Smuzhiyun 		.name = "h8300_8timer",
151*4882a593Smuzhiyun 		.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
152*4882a593Smuzhiyun 		.rating = 200,
153*4882a593Smuzhiyun 		.set_next_event = timer8_clock_event_next,
154*4882a593Smuzhiyun 		.set_state_shutdown = timer8_clock_event_shutdown,
155*4882a593Smuzhiyun 		.set_state_periodic = timer8_clock_event_periodic,
156*4882a593Smuzhiyun 		.set_state_oneshot = timer8_clock_event_oneshot,
157*4882a593Smuzhiyun 	},
158*4882a593Smuzhiyun };
159*4882a593Smuzhiyun 
h8300_8timer_init(struct device_node * node)160*4882a593Smuzhiyun static int __init h8300_8timer_init(struct device_node *node)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	void __iomem *base;
163*4882a593Smuzhiyun 	int irq, ret;
164*4882a593Smuzhiyun 	struct clk *clk;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	clk = of_clk_get(node, 0);
167*4882a593Smuzhiyun 	if (IS_ERR(clk)) {
168*4882a593Smuzhiyun 		pr_err("failed to get clock for clockevent\n");
169*4882a593Smuzhiyun 		return PTR_ERR(clk);
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	ret = -ENXIO;
173*4882a593Smuzhiyun 	base = of_iomap(node, 0);
174*4882a593Smuzhiyun 	if (!base) {
175*4882a593Smuzhiyun 		pr_err("failed to map registers for clockevent\n");
176*4882a593Smuzhiyun 		goto free_clk;
177*4882a593Smuzhiyun 	}
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	ret = -EINVAL;
180*4882a593Smuzhiyun 	irq = irq_of_parse_and_map(node, 0);
181*4882a593Smuzhiyun 	if (!irq) {
182*4882a593Smuzhiyun 		pr_err("failed to get irq for clockevent\n");
183*4882a593Smuzhiyun 		goto unmap_reg;
184*4882a593Smuzhiyun 	}
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	timer8_priv.mapbase = base;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	timer8_priv.rate = clk_get_rate(clk) / SCALE;
189*4882a593Smuzhiyun 	if (!timer8_priv.rate) {
190*4882a593Smuzhiyun 		pr_err("Failed to get rate for the clocksource\n");
191*4882a593Smuzhiyun 		goto unmap_reg;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	if (request_irq(irq, timer8_interrupt, IRQF_TIMER,
195*4882a593Smuzhiyun 			timer8_priv.ced.name, &timer8_priv) < 0) {
196*4882a593Smuzhiyun 		pr_err("failed to request irq %d for clockevent\n", irq);
197*4882a593Smuzhiyun 		goto unmap_reg;
198*4882a593Smuzhiyun 	}
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	clockevents_config_and_register(&timer8_priv.ced,
201*4882a593Smuzhiyun 					timer8_priv.rate, 1, 0x0000ffff);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	return 0;
204*4882a593Smuzhiyun unmap_reg:
205*4882a593Smuzhiyun 	iounmap(base);
206*4882a593Smuzhiyun free_clk:
207*4882a593Smuzhiyun 	clk_put(clk);
208*4882a593Smuzhiyun 	return ret;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun TIMER_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);
212