Linux Audio

Check our new training course

Yocto / OpenEmbedded training

Mar 24-27, 2025, special US time zones
Register
Loading...
Note: File does not exist in v6.8.
  1/*
  2 * MOXA ART SoCs timer handling.
  3 *
  4 * Copyright (C) 2013 Jonas Jensen
  5 *
  6 * Jonas Jensen <jonas.jensen@gmail.com>
  7 *
  8 * This file is licensed under the terms of the GNU General Public
  9 * License version 2.  This program is licensed "as is" without any
 10 * warranty of any kind, whether express or implied.
 11 */
 12
 13#include <linux/clk.h>
 14#include <linux/clockchips.h>
 15#include <linux/interrupt.h>
 16#include <linux/irq.h>
 17#include <linux/irqreturn.h>
 18#include <linux/of.h>
 19#include <linux/of_address.h>
 20#include <linux/of_irq.h>
 21#include <linux/io.h>
 22#include <linux/clocksource.h>
 23#include <linux/bitops.h>
 24#include <linux/slab.h>
 25
 26#define TIMER1_BASE		0x00
 27#define TIMER2_BASE		0x10
 28#define TIMER3_BASE		0x20
 29
 30#define REG_COUNT		0x0 /* writable */
 31#define REG_LOAD		0x4
 32#define REG_MATCH1		0x8
 33#define REG_MATCH2		0xC
 34
 35#define TIMER_CR		0x30
 36#define TIMER_INTR_STATE	0x34
 37#define TIMER_INTR_MASK		0x38
 38
 39/*
 40 * Moxart TIMER_CR flags:
 41 *
 42 * MOXART_CR_*_CLOCK	0: PCLK, 1: EXT1CLK
 43 * MOXART_CR_*_INT	overflow interrupt enable bit
 44 */
 45#define MOXART_CR_1_ENABLE	BIT(0)
 46#define MOXART_CR_1_CLOCK	BIT(1)
 47#define MOXART_CR_1_INT	BIT(2)
 48#define MOXART_CR_2_ENABLE	BIT(3)
 49#define MOXART_CR_2_CLOCK	BIT(4)
 50#define MOXART_CR_2_INT	BIT(5)
 51#define MOXART_CR_3_ENABLE	BIT(6)
 52#define MOXART_CR_3_CLOCK	BIT(7)
 53#define MOXART_CR_3_INT	BIT(8)
 54#define MOXART_CR_COUNT_UP	BIT(9)
 55
 56#define MOXART_TIMER1_ENABLE	(MOXART_CR_2_ENABLE | MOXART_CR_1_ENABLE)
 57#define MOXART_TIMER1_DISABLE	(MOXART_CR_2_ENABLE)
 58
 59/*
 60 * The ASpeed variant of the IP block has a different layout
 61 * for the control register
 62 */
 63#define ASPEED_CR_1_ENABLE	BIT(0)
 64#define ASPEED_CR_1_CLOCK	BIT(1)
 65#define ASPEED_CR_1_INT		BIT(2)
 66#define ASPEED_CR_2_ENABLE	BIT(4)
 67#define ASPEED_CR_2_CLOCK	BIT(5)
 68#define ASPEED_CR_2_INT		BIT(6)
 69#define ASPEED_CR_3_ENABLE	BIT(8)
 70#define ASPEED_CR_3_CLOCK	BIT(9)
 71#define ASPEED_CR_3_INT		BIT(10)
 72
 73#define ASPEED_TIMER1_ENABLE   (ASPEED_CR_2_ENABLE | ASPEED_CR_1_ENABLE)
 74#define ASPEED_TIMER1_DISABLE  (ASPEED_CR_2_ENABLE)
 75
 76struct moxart_timer {
 77	void __iomem *base;
 78	unsigned int t1_disable_val;
 79	unsigned int t1_enable_val;
 80	unsigned int count_per_tick;
 81	struct clock_event_device clkevt;
 82};
 83
 84static inline struct moxart_timer *to_moxart(struct clock_event_device *evt)
 85{
 86	return container_of(evt, struct moxart_timer, clkevt);
 87}
 88
 89static inline void moxart_disable(struct clock_event_device *evt)
 90{
 91	struct moxart_timer *timer = to_moxart(evt);
 92
 93	writel(timer->t1_disable_val, timer->base + TIMER_CR);
 94}
 95
 96static inline void moxart_enable(struct clock_event_device *evt)
 97{
 98	struct moxart_timer *timer = to_moxart(evt);
 99
100	writel(timer->t1_enable_val, timer->base + TIMER_CR);
101}
102
103static int moxart_shutdown(struct clock_event_device *evt)
104{
105	moxart_disable(evt);
106	return 0;
107}
108
109static int moxart_set_oneshot(struct clock_event_device *evt)
110{
111	moxart_disable(evt);
112	writel(~0, to_moxart(evt)->base + TIMER1_BASE + REG_LOAD);
113	return 0;
114}
115
116static int moxart_set_periodic(struct clock_event_device *evt)
117{
118	struct moxart_timer *timer = to_moxart(evt);
119
120	moxart_disable(evt);
121	writel(timer->count_per_tick, timer->base + TIMER1_BASE + REG_LOAD);
122	writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
123	moxart_enable(evt);
124	return 0;
125}
126
127static int moxart_clkevt_next_event(unsigned long cycles,
128				    struct clock_event_device *evt)
129{
130	struct moxart_timer *timer = to_moxart(evt);
131	u32 u;
132
133	moxart_disable(evt);
134
135	u = readl(timer->base + TIMER1_BASE + REG_COUNT) - cycles;
136	writel(u, timer->base + TIMER1_BASE + REG_MATCH1);
137
138	moxart_enable(evt);
139
140	return 0;
141}
142
143static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id)
144{
145	struct clock_event_device *evt = dev_id;
146	evt->event_handler(evt);
147	return IRQ_HANDLED;
148}
149
150static int __init moxart_timer_init(struct device_node *node)
151{
152	int ret, irq;
153	unsigned long pclk;
154	struct clk *clk;
155	struct moxart_timer *timer;
156
157	timer = kzalloc(sizeof(*timer), GFP_KERNEL);
158	if (!timer)
159		return -ENOMEM;
160
161	timer->base = of_iomap(node, 0);
162	if (!timer->base) {
163		pr_err("%s: of_iomap failed\n", node->full_name);
164		ret = -ENXIO;
165		goto out_free;
166	}
167
168	irq = irq_of_parse_and_map(node, 0);
169	if (irq <= 0) {
170		pr_err("%s: irq_of_parse_and_map failed\n", node->full_name);
171		ret = -EINVAL;
172		goto out_unmap;
173	}
174
175	clk = of_clk_get(node, 0);
176	if (IS_ERR(clk))  {
177		pr_err("%s: of_clk_get failed\n", node->full_name);
178		ret = PTR_ERR(clk);
179		goto out_unmap;
180	}
181
182	pclk = clk_get_rate(clk);
183
184	if (of_device_is_compatible(node, "moxa,moxart-timer")) {
185		timer->t1_enable_val = MOXART_TIMER1_ENABLE;
186		timer->t1_disable_val = MOXART_TIMER1_DISABLE;
187	} else if (of_device_is_compatible(node, "aspeed,ast2400-timer")) {
188		timer->t1_enable_val = ASPEED_TIMER1_ENABLE;
189		timer->t1_disable_val = ASPEED_TIMER1_DISABLE;
190	} else {
191		pr_err("%s: unknown platform\n", node->full_name);
192		ret = -EINVAL;
193		goto out_unmap;
194	}
195
196	timer->count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ);
197
198	timer->clkevt.name = node->name;
199	timer->clkevt.rating = 200;
200	timer->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
201					CLOCK_EVT_FEAT_ONESHOT;
202	timer->clkevt.set_state_shutdown = moxart_shutdown;
203	timer->clkevt.set_state_periodic = moxart_set_periodic;
204	timer->clkevt.set_state_oneshot = moxart_set_oneshot;
205	timer->clkevt.tick_resume = moxart_set_oneshot;
206	timer->clkevt.set_next_event = moxart_clkevt_next_event;
207	timer->clkevt.cpumask = cpumask_of(0);
208	timer->clkevt.irq = irq;
209
210	ret = clocksource_mmio_init(timer->base + TIMER2_BASE + REG_COUNT,
211				    "moxart_timer", pclk, 200, 32,
212				    clocksource_mmio_readl_down);
213	if (ret) {
214		pr_err("%s: clocksource_mmio_init failed\n", node->full_name);
215		goto out_unmap;
216	}
217
218	ret = request_irq(irq, moxart_timer_interrupt, IRQF_TIMER,
219			  node->name, &timer->clkevt);
220	if (ret) {
221		pr_err("%s: setup_irq failed\n", node->full_name);
222		goto out_unmap;
223	}
224
225	/* Clear match registers */
226	writel(0, timer->base + TIMER1_BASE + REG_MATCH1);
227	writel(0, timer->base + TIMER1_BASE + REG_MATCH2);
228	writel(0, timer->base + TIMER2_BASE + REG_MATCH1);
229	writel(0, timer->base + TIMER2_BASE + REG_MATCH2);
230
231	/*
232	 * Start timer 2 rolling as our main wall clock source, keep timer 1
233	 * disabled
234	 */
235	writel(0, timer->base + TIMER_CR);
236	writel(~0, timer->base + TIMER2_BASE + REG_LOAD);
237	writel(timer->t1_disable_val, timer->base + TIMER_CR);
238
239	/*
240	 * documentation is not publicly available:
241	 * min_delta / max_delta obtained by trial-and-error,
242	 * max_delta 0xfffffffe should be ok because count
243	 * register size is u32
244	 */
245	clockevents_config_and_register(&timer->clkevt, pclk, 0x4, 0xfffffffe);
246
247	return 0;
248
249out_unmap:
250	iounmap(timer->base);
251out_free:
252	kfree(timer);
253	return ret;
254}
255CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init);
256CLOCKSOURCE_OF_DECLARE(aspeed, "aspeed,ast2400-timer", moxart_timer_init);