1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2014-2018 Nuvoton Technologies tomer.maimon@nuvoton.com
4 * All rights reserved.
5 *
6 * Copyright 2017 Google, Inc.
7 */
8
9#include <linux/kernel.h>
10#include <linux/sched.h>
11#include <linux/init.h>
12#include <linux/interrupt.h>
13#include <linux/err.h>
14#include <linux/clk.h>
15#include <linux/io.h>
16#include <linux/clockchips.h>
17#include <linux/of_irq.h>
18#include <linux/of_address.h>
19#include "timer-of.h"
20
21/* Timers registers */
22#define NPCM7XX_REG_TCSR0	0x0 /* Timer 0 Control and Status Register */
23#define NPCM7XX_REG_TICR0	0x8 /* Timer 0 Initial Count Register */
24#define NPCM7XX_REG_TCSR1	0x4 /* Timer 1 Control and Status Register */
25#define NPCM7XX_REG_TICR1	0xc /* Timer 1 Initial Count Register */
26#define NPCM7XX_REG_TDR1	0x14 /* Timer 1 Data Register */
27#define NPCM7XX_REG_TISR	0x18 /* Timer Interrupt Status Register */
28
29/* Timers control */
30#define NPCM7XX_Tx_RESETINT		0x1f
31#define NPCM7XX_Tx_PERIOD		BIT(27)
32#define NPCM7XX_Tx_INTEN		BIT(29)
33#define NPCM7XX_Tx_COUNTEN		BIT(30)
34#define NPCM7XX_Tx_ONESHOT		0x0
35#define NPCM7XX_Tx_OPER			GENMASK(28, 27)
36#define NPCM7XX_Tx_MIN_PRESCALE		0x1
37#define NPCM7XX_Tx_TDR_MASK_BITS	24
38#define NPCM7XX_Tx_MAX_CNT		0xFFFFFF
39#define NPCM7XX_T0_CLR_INT		0x1
40#define NPCM7XX_Tx_CLR_CSR		0x0
41
42/* Timers operating mode */
43#define NPCM7XX_START_PERIODIC_Tx (NPCM7XX_Tx_PERIOD | NPCM7XX_Tx_COUNTEN | \
44					NPCM7XX_Tx_INTEN | \
45					NPCM7XX_Tx_MIN_PRESCALE)
46
47#define NPCM7XX_START_ONESHOT_Tx (NPCM7XX_Tx_ONESHOT | NPCM7XX_Tx_COUNTEN | \
48					NPCM7XX_Tx_INTEN | \
49					NPCM7XX_Tx_MIN_PRESCALE)
50
51#define NPCM7XX_START_Tx (NPCM7XX_Tx_COUNTEN | NPCM7XX_Tx_PERIOD | \
52				NPCM7XX_Tx_MIN_PRESCALE)
53
54#define NPCM7XX_DEFAULT_CSR (NPCM7XX_Tx_CLR_CSR | NPCM7XX_Tx_MIN_PRESCALE)
55
56static int npcm7xx_timer_resume(struct clock_event_device *evt)
57{
58	struct timer_of *to = to_timer_of(evt);
59	u32 val;
60
61	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
62	val |= NPCM7XX_Tx_COUNTEN;
63	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
64
65	return 0;
66}
67
68static int npcm7xx_timer_shutdown(struct clock_event_device *evt)
69{
70	struct timer_of *to = to_timer_of(evt);
71	u32 val;
72
73	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
74	val &= ~NPCM7XX_Tx_COUNTEN;
75	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
76
77	return 0;
78}
79
80static int npcm7xx_timer_oneshot(struct clock_event_device *evt)
81{
82	struct timer_of *to = to_timer_of(evt);
83	u32 val;
84
85	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
86	val &= ~NPCM7XX_Tx_OPER;
87	val |= NPCM7XX_START_ONESHOT_Tx;
88	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
89
90	return 0;
91}
92
93static int npcm7xx_timer_periodic(struct clock_event_device *evt)
94{
95	struct timer_of *to = to_timer_of(evt);
96	u32 val;
97
98	writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0);
99
100	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
101	val &= ~NPCM7XX_Tx_OPER;
102	val |= NPCM7XX_START_PERIODIC_Tx;
103	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
104
105	return 0;
106}
107
108static int npcm7xx_clockevent_set_next_event(unsigned long evt,
109		struct clock_event_device *clk)
110{
111	struct timer_of *to = to_timer_of(clk);
112	u32 val;
113
114	writel(evt, timer_of_base(to) + NPCM7XX_REG_TICR0);
115	val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
116	val |= NPCM7XX_START_Tx;
117	writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
118
119	return 0;
120}
121
122static irqreturn_t npcm7xx_timer0_interrupt(int irq, void *dev_id)
123{
124	struct clock_event_device *evt = (struct clock_event_device *)dev_id;
125	struct timer_of *to = to_timer_of(evt);
126
127	writel(NPCM7XX_T0_CLR_INT, timer_of_base(to) + NPCM7XX_REG_TISR);
128
129	evt->event_handler(evt);
130
131	return IRQ_HANDLED;
132}
133
134static struct timer_of npcm7xx_to = {
135	.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
136
137	.clkevt = {
138		.name		    = "npcm7xx-timer0",
139		.features	    = CLOCK_EVT_FEAT_PERIODIC |
140				      CLOCK_EVT_FEAT_ONESHOT,
141		.set_next_event	    = npcm7xx_clockevent_set_next_event,
142		.set_state_shutdown = npcm7xx_timer_shutdown,
143		.set_state_periodic = npcm7xx_timer_periodic,
144		.set_state_oneshot  = npcm7xx_timer_oneshot,
145		.tick_resume	    = npcm7xx_timer_resume,
146		.rating		    = 300,
147	},
148
149	.of_irq = {
150		.handler = npcm7xx_timer0_interrupt,
151		.flags = IRQF_TIMER | IRQF_IRQPOLL,
152	},
153};
154
155static void __init npcm7xx_clockevents_init(void)
156{
157	writel(NPCM7XX_DEFAULT_CSR,
158		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR0);
159
160	writel(NPCM7XX_Tx_RESETINT,
161		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TISR);
162
163	npcm7xx_to.clkevt.cpumask = cpumask_of(0);
164	clockevents_config_and_register(&npcm7xx_to.clkevt,
165					timer_of_rate(&npcm7xx_to),
166					0x1, NPCM7XX_Tx_MAX_CNT);
167}
168
169static void __init npcm7xx_clocksource_init(void)
170{
171	u32 val;
172
173	writel(NPCM7XX_DEFAULT_CSR,
174		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
175	writel(NPCM7XX_Tx_MAX_CNT,
176		timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TICR1);
177
178	val = readl(timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
179	val |= NPCM7XX_START_Tx;
180	writel(val, timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
181
182	clocksource_mmio_init(timer_of_base(&npcm7xx_to) +
183				NPCM7XX_REG_TDR1,
184				"npcm7xx-timer1", timer_of_rate(&npcm7xx_to),
185				200, (unsigned int)NPCM7XX_Tx_TDR_MASK_BITS,
186				clocksource_mmio_readl_down);
187}
188
189static int __init npcm7xx_timer_init(struct device_node *np)
190{
191	struct clk *clk;
192	int ret;
193
194	ret = timer_of_init(np, &npcm7xx_to);
195	if (ret)
196		return ret;
197
198	/* Clock input is divided by PRESCALE + 1 before it is fed */
199	/* to the counter */
200	npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate /
201		(NPCM7XX_Tx_MIN_PRESCALE + 1);
202
203	/* Enable the clock for timer1, if it exists */
204	clk = of_clk_get(np, 1);
205	if (clk) {
206		if (!IS_ERR(clk))
207			clk_prepare_enable(clk);
208		else
209			pr_warn("%pOF: Failed to get clock for timer1: %pe", np, clk);
210	}
211
212	npcm7xx_clocksource_init();
213	npcm7xx_clockevents_init();
214
215	pr_info("Enabling NPCM7xx clocksource timer base: %px, IRQ: %d ",
216		timer_of_base(&npcm7xx_to), timer_of_irq(&npcm7xx_to));
217
218	return 0;
219}
220
221TIMER_OF_DECLARE(wpcm450, "nuvoton,wpcm450-timer", npcm7xx_timer_init);
222TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init);
223
224