Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * arch/arm/mach-pxa/time.c
  3 *
  4 * PXA clocksource, clockevents, and OST interrupt handlers.
  5 * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
  6 *
  7 * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
  8 * by MontaVista Software, Inc.  (Nico, your code rocks!)
  9 *
 10 * This program is free software; you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License version 2 as
 12 * published by the Free Software Foundation.
 13 */
 14
 15#include <linux/kernel.h>
 16#include <linux/init.h>
 17#include <linux/interrupt.h>
 18#include <linux/clk.h>
 19#include <linux/clockchips.h>
 20#include <linux/of_address.h>
 21#include <linux/of_irq.h>
 22#include <linux/sched/clock.h>
 23#include <linux/sched_clock.h>
 24
 25#include <clocksource/pxa.h>
 26
 27#include <asm/div64.h>
 28
 29#define OSMR0		0x00	/* OS Timer 0 Match Register */
 30#define OSMR1		0x04	/* OS Timer 1 Match Register */
 31#define OSMR2		0x08	/* OS Timer 2 Match Register */
 32#define OSMR3		0x0C	/* OS Timer 3 Match Register */
 33
 34#define OSCR		0x10	/* OS Timer Counter Register */
 35#define OSSR		0x14	/* OS Timer Status Register */
 36#define OWER		0x18	/* OS Timer Watchdog Enable Register */
 37#define OIER		0x1C	/* OS Timer Interrupt Enable Register */
 38
 39#define OSSR_M3		(1 << 3)	/* Match status channel 3 */
 40#define OSSR_M2		(1 << 2)	/* Match status channel 2 */
 41#define OSSR_M1		(1 << 1)	/* Match status channel 1 */
 42#define OSSR_M0		(1 << 0)	/* Match status channel 0 */
 43
 44#define OIER_E0		(1 << 0)	/* Interrupt enable channel 0 */
 45
 46/*
 47 * This is PXA's sched_clock implementation. This has a resolution
 48 * of at least 308 ns and a maximum value of 208 days.
 49 *
 50 * The return value is guaranteed to be monotonic in that range as
 51 * long as there is always less than 582 seconds between successive
 52 * calls to sched_clock() which should always be the case in practice.
 53 */
 54
 55#define timer_readl(reg) readl_relaxed(timer_base + (reg))
 56#define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg))
 57
 58static void __iomem *timer_base;
 59
 60static u64 notrace pxa_read_sched_clock(void)
 61{
 62	return timer_readl(OSCR);
 63}
 64
 65
 66#define MIN_OSCR_DELTA 16
 67
 68static irqreturn_t
 69pxa_ost0_interrupt(int irq, void *dev_id)
 70{
 71	struct clock_event_device *c = dev_id;
 72
 73	/* Disarm the compare/match, signal the event. */
 74	timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
 75	timer_writel(OSSR_M0, OSSR);
 76	c->event_handler(c);
 77
 78	return IRQ_HANDLED;
 79}
 80
 81static int
 82pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
 83{
 84	unsigned long next, oscr;
 85
 86	timer_writel(timer_readl(OIER) | OIER_E0, OIER);
 87	next = timer_readl(OSCR) + delta;
 88	timer_writel(next, OSMR0);
 89	oscr = timer_readl(OSCR);
 90
 91	return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
 92}
 93
 94static int pxa_osmr0_shutdown(struct clock_event_device *evt)
 95{
 96	/* initializing, released, or preparing for suspend */
 97	timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
 98	timer_writel(OSSR_M0, OSSR);
 99	return 0;
100}
101
102#ifdef CONFIG_PM
103static unsigned long osmr[4], oier, oscr;
104
105static void pxa_timer_suspend(struct clock_event_device *cedev)
106{
107	osmr[0] = timer_readl(OSMR0);
108	osmr[1] = timer_readl(OSMR1);
109	osmr[2] = timer_readl(OSMR2);
110	osmr[3] = timer_readl(OSMR3);
111	oier = timer_readl(OIER);
112	oscr = timer_readl(OSCR);
113}
114
115static void pxa_timer_resume(struct clock_event_device *cedev)
116{
117	/*
118	 * Ensure that we have at least MIN_OSCR_DELTA between match
119	 * register 0 and the OSCR, to guarantee that we will receive
120	 * the one-shot timer interrupt.  We adjust OSMR0 in preference
121	 * to OSCR to guarantee that OSCR is monotonically incrementing.
122	 */
123	if (osmr[0] - oscr < MIN_OSCR_DELTA)
124		osmr[0] += MIN_OSCR_DELTA;
125
126	timer_writel(osmr[0], OSMR0);
127	timer_writel(osmr[1], OSMR1);
128	timer_writel(osmr[2], OSMR2);
129	timer_writel(osmr[3], OSMR3);
130	timer_writel(oier, OIER);
131	timer_writel(oscr, OSCR);
132}
133#else
134#define pxa_timer_suspend NULL
135#define pxa_timer_resume NULL
136#endif
137
138static struct clock_event_device ckevt_pxa_osmr0 = {
139	.name			= "osmr0",
140	.features		= CLOCK_EVT_FEAT_ONESHOT,
141	.rating			= 200,
142	.set_next_event		= pxa_osmr0_set_next_event,
143	.set_state_shutdown	= pxa_osmr0_shutdown,
144	.set_state_oneshot	= pxa_osmr0_shutdown,
145	.suspend		= pxa_timer_suspend,
146	.resume			= pxa_timer_resume,
147};
148
149static struct irqaction pxa_ost0_irq = {
150	.name		= "ost0",
151	.flags		= IRQF_TIMER | IRQF_IRQPOLL,
152	.handler	= pxa_ost0_interrupt,
153	.dev_id		= &ckevt_pxa_osmr0,
154};
155
156static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
157{
158	int ret;
159
160	timer_writel(0, OIER);
161	timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
162
163	sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate);
164
165	ckevt_pxa_osmr0.cpumask = cpumask_of(0);
166
167	ret = setup_irq(irq, &pxa_ost0_irq);
168	if (ret) {
169		pr_err("Failed to setup irq\n");
170		return ret;
171	}
172
173	ret = clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200,
174				    32, clocksource_mmio_readl_up);
175	if (ret) {
176		pr_err("Failed to init clocksource\n");
177		return ret;
178	}
179
180	clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate,
181					MIN_OSCR_DELTA * 2, 0x7fffffff);
182
183	return 0;
184}
185
186static int __init pxa_timer_dt_init(struct device_node *np)
187{
188	struct clk *clk;
189	int irq, ret;
190
191	/* timer registers are shared with watchdog timer */
192	timer_base = of_iomap(np, 0);
193	if (!timer_base) {
194		pr_err("%s: unable to map resource\n", np->name);
195		return -ENXIO;
196	}
197
198	clk = of_clk_get(np, 0);
199	if (IS_ERR(clk)) {
200		pr_crit("%s: unable to get clk\n", np->name);
201		return PTR_ERR(clk);
202	}
203
204	ret = clk_prepare_enable(clk);
205	if (ret) {
206		pr_crit("Failed to prepare clock\n");
207		return ret;
208	}
209
210	/* we are only interested in OS-timer0 irq */
211	irq = irq_of_parse_and_map(np, 0);
212	if (irq <= 0) {
213		pr_crit("%s: unable to parse OS-timer0 irq\n", np->name);
214		return -EINVAL;
215	}
216
217	return pxa_timer_common_init(irq, clk_get_rate(clk));
218}
219TIMER_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init);
220
221/*
222 * Legacy timer init for non device-tree boards.
223 */
224void __init pxa_timer_nodt_init(int irq, void __iomem *base)
225{
226	struct clk *clk;
227
228	timer_base = base;
229	clk = clk_get(NULL, "OSTIMER0");
230	if (clk && !IS_ERR(clk)) {
231		clk_prepare_enable(clk);
232		pxa_timer_common_init(irq, clk_get_rate(clk));
233	} else {
234		pr_crit("%s: unable to get clk\n", __func__);
235	}
236}