Skip to content

Commit c28ca80

Browse files
maquefeldlezcano
authored andcommitted
clocksource: ep93xx: Add driver for Cirrus Logic EP93xx
Rewrite EP93xx timer driver located in arch/arm/mach-ep93xx/timer-ep93xx.c trying to do everything the device tree way: - Make every IO-access relative to a base address and dynamic so we can do a dynamic ioremap and get going. - Find register range and interrupt from the device tree. Reviewed-by: Linus Walleij <[email protected]> Tested-by: Alexander Sverdlin <[email protected]> Signed-off-by: Nikita Shubin <[email protected]> Signed-off-by: Daniel Lezcano <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 81824f7 commit c28ca80

File tree

3 files changed

+202
-0
lines changed

3 files changed

+202
-0
lines changed

drivers/clocksource/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,4 +732,15 @@ config GOLDFISH_TIMER
732732
help
733733
Support for the timer/counter of goldfish-rtc
734734

735+
config EP93XX_TIMER
736+
bool "Cirrus Logic ep93xx timer driver" if COMPILE_TEST
737+
depends on ARCH_EP93XX
738+
depends on GENERIC_CLOCKEVENTS
739+
depends on HAS_IOMEM
740+
select CLKSRC_MMIO
741+
select TIMER_OF
742+
help
743+
Enables support for the Cirrus Logic timer block
744+
EP93XX.
745+
735746
endmenu

drivers/clocksource/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,4 @@ obj-$(CONFIG_MSC313E_TIMER) += timer-msc313e.o
8989
obj-$(CONFIG_GOLDFISH_TIMER) += timer-goldfish.o
9090
obj-$(CONFIG_GXP_TIMER) += timer-gxp.o
9191
obj-$(CONFIG_CLKSRC_LOONGSON1_PWM) += timer-loongson1-pwm.o
92+
obj-$(CONFIG_EP93XX_TIMER) += timer-ep93xx.o

drivers/clocksource/timer-ep93xx.c

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Cirrus Logic EP93xx timer driver.
4+
* Copyright (C) 2021 Nikita Shubin <[email protected]>
5+
*
6+
* Based on a rewrite of arch/arm/mach-ep93xx/timer.c:
7+
*/
8+
9+
#include <linux/clockchips.h>
10+
#include <linux/clocksource.h>
11+
#include <linux/init.h>
12+
#include <linux/interrupt.h>
13+
#include <linux/io.h>
14+
#include <linux/io-64-nonatomic-lo-hi.h>
15+
#include <linux/irq.h>
16+
#include <linux/kernel.h>
17+
#include <linux/of_address.h>
18+
#include <linux/of_irq.h>
19+
#include <linux/sched_clock.h>
20+
21+
#include <asm/mach/time.h>
22+
23+
/*************************************************************************
24+
* Timer handling for EP93xx
25+
*************************************************************************
26+
* The ep93xx has four internal timers. Timers 1, 2 (both 16 bit) and
27+
* 3 (32 bit) count down at 508 kHz, are self-reloading, and can generate
28+
* an interrupt on underflow. Timer 4 (40 bit) counts down at 983.04 kHz,
29+
* is free-running, and can't generate interrupts.
30+
*
31+
* The 508 kHz timers are ideal for use for the timer interrupt, as the
32+
* most common values of HZ divide 508 kHz nicely. We pick the 32 bit
33+
* timer (timer 3) to get as long sleep intervals as possible when using
34+
* CONFIG_NO_HZ.
35+
*
36+
* The higher clock rate of timer 4 makes it a better choice than the
37+
* other timers for use as clock source and for sched_clock(), providing
38+
* a stable 40 bit time base.
39+
*************************************************************************
40+
*/
41+
42+
#define EP93XX_TIMER1_LOAD 0x00
43+
#define EP93XX_TIMER1_VALUE 0x04
44+
#define EP93XX_TIMER1_CONTROL 0x08
45+
#define EP93XX_TIMER123_CONTROL_ENABLE BIT(7)
46+
#define EP93XX_TIMER123_CONTROL_MODE BIT(6)
47+
#define EP93XX_TIMER123_CONTROL_CLKSEL BIT(3)
48+
#define EP93XX_TIMER1_CLEAR 0x0c
49+
#define EP93XX_TIMER2_LOAD 0x20
50+
#define EP93XX_TIMER2_VALUE 0x24
51+
#define EP93XX_TIMER2_CONTROL 0x28
52+
#define EP93XX_TIMER2_CLEAR 0x2c
53+
/*
54+
* This read-only register contains the low word of the time stamp debug timer
55+
* ( Timer4). When this register is read, the high byte of the Timer4 counter is
56+
* saved in the Timer4ValueHigh register.
57+
*/
58+
#define EP93XX_TIMER4_VALUE_LOW 0x60
59+
#define EP93XX_TIMER4_VALUE_HIGH 0x64
60+
#define EP93XX_TIMER4_VALUE_HIGH_ENABLE BIT(8)
61+
#define EP93XX_TIMER3_LOAD 0x80
62+
#define EP93XX_TIMER3_VALUE 0x84
63+
#define EP93XX_TIMER3_CONTROL 0x88
64+
#define EP93XX_TIMER3_CLEAR 0x8c
65+
66+
#define EP93XX_TIMER123_RATE 508469
67+
#define EP93XX_TIMER4_RATE 983040
68+
69+
struct ep93xx_tcu {
70+
void __iomem *base;
71+
};
72+
73+
static struct ep93xx_tcu *ep93xx_tcu;
74+
75+
static u64 ep93xx_clocksource_read(struct clocksource *c)
76+
{
77+
struct ep93xx_tcu *tcu = ep93xx_tcu;
78+
79+
return lo_hi_readq(tcu->base + EP93XX_TIMER4_VALUE_LOW) & GENMASK_ULL(39, 0);
80+
}
81+
82+
static u64 notrace ep93xx_read_sched_clock(void)
83+
{
84+
return ep93xx_clocksource_read(NULL);
85+
}
86+
87+
static int ep93xx_clkevt_set_next_event(unsigned long next,
88+
struct clock_event_device *evt)
89+
{
90+
struct ep93xx_tcu *tcu = ep93xx_tcu;
91+
/* Default mode: periodic, off, 508 kHz */
92+
u32 tmode = EP93XX_TIMER123_CONTROL_MODE |
93+
EP93XX_TIMER123_CONTROL_CLKSEL;
94+
95+
/* Clear timer */
96+
writel(tmode, tcu->base + EP93XX_TIMER3_CONTROL);
97+
98+
/* Set next event */
99+
writel(next, tcu->base + EP93XX_TIMER3_LOAD);
100+
writel(tmode | EP93XX_TIMER123_CONTROL_ENABLE,
101+
tcu->base + EP93XX_TIMER3_CONTROL);
102+
return 0;
103+
}
104+
105+
static int ep93xx_clkevt_shutdown(struct clock_event_device *evt)
106+
{
107+
struct ep93xx_tcu *tcu = ep93xx_tcu;
108+
/* Disable timer */
109+
writel(0, tcu->base + EP93XX_TIMER3_CONTROL);
110+
111+
return 0;
112+
}
113+
114+
static struct clock_event_device ep93xx_clockevent = {
115+
.name = "timer1",
116+
.features = CLOCK_EVT_FEAT_ONESHOT,
117+
.set_state_shutdown = ep93xx_clkevt_shutdown,
118+
.set_state_oneshot = ep93xx_clkevt_shutdown,
119+
.tick_resume = ep93xx_clkevt_shutdown,
120+
.set_next_event = ep93xx_clkevt_set_next_event,
121+
.rating = 300,
122+
};
123+
124+
static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id)
125+
{
126+
struct ep93xx_tcu *tcu = ep93xx_tcu;
127+
struct clock_event_device *evt = dev_id;
128+
129+
/* Writing any value clears the timer interrupt */
130+
writel(1, tcu->base + EP93XX_TIMER3_CLEAR);
131+
132+
evt->event_handler(evt);
133+
134+
return IRQ_HANDLED;
135+
}
136+
137+
static int __init ep93xx_timer_of_init(struct device_node *np)
138+
{
139+
int irq;
140+
unsigned long flags = IRQF_TIMER | IRQF_IRQPOLL;
141+
struct ep93xx_tcu *tcu;
142+
int ret;
143+
144+
tcu = kzalloc(sizeof(*tcu), GFP_KERNEL);
145+
if (!tcu)
146+
return -ENOMEM;
147+
148+
tcu->base = of_iomap(np, 0);
149+
if (!tcu->base) {
150+
pr_err("Can't remap registers\n");
151+
ret = -ENXIO;
152+
goto out_free;
153+
}
154+
155+
ep93xx_tcu = tcu;
156+
157+
irq = irq_of_parse_and_map(np, 0);
158+
if (irq == 0)
159+
irq = -EINVAL;
160+
if (irq < 0) {
161+
pr_err("EP93XX Timer Can't parse IRQ %d", irq);
162+
goto out_free;
163+
}
164+
165+
/* Enable and register clocksource and sched_clock on timer 4 */
166+
writel(EP93XX_TIMER4_VALUE_HIGH_ENABLE,
167+
tcu->base + EP93XX_TIMER4_VALUE_HIGH);
168+
clocksource_mmio_init(NULL, "timer4",
169+
EP93XX_TIMER4_RATE, 200, 40,
170+
ep93xx_clocksource_read);
171+
sched_clock_register(ep93xx_read_sched_clock, 40,
172+
EP93XX_TIMER4_RATE);
173+
174+
/* Set up clockevent on timer 3 */
175+
if (request_irq(irq, ep93xx_timer_interrupt, flags, "ep93xx timer",
176+
&ep93xx_clockevent))
177+
pr_err("Failed to request irq %d (ep93xx timer)\n", irq);
178+
179+
clockevents_config_and_register(&ep93xx_clockevent,
180+
EP93XX_TIMER123_RATE,
181+
1,
182+
UINT_MAX);
183+
184+
return 0;
185+
186+
out_free:
187+
kfree(tcu);
188+
return ret;
189+
}
190+
TIMER_OF_DECLARE(ep93xx_timer, "cirrus,ep9301-timer", ep93xx_timer_of_init);

0 commit comments

Comments
 (0)