timer-atmel-pit.c 7.0 KB
Newer Older
1
/*
2
 * at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x
3 4 5
 *
 * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France
 * Revision	 2005 M. Nicolas Diremdjian, ATMEL Rousset, France
6
 * Converted to ClockSource/ClockEvents by David Brownell.
7 8 9 10 11
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
12

M
Maxime Ripard 已提交
13 14
#define pr_fmt(fmt)	"AT91: PIT: " fmt

15 16
#include <linux/clk.h>
#include <linux/clockchips.h>
17 18 19
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
20 21 22
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
23
#include <linux/slab.h>
24

25
#define AT91_PIT_MR		0x00			/* Mode Register */
26 27 28
#define AT91_PIT_PITIEN			BIT(25)			/* Timer Interrupt Enable */
#define AT91_PIT_PITEN			BIT(24)			/* Timer Enabled */
#define AT91_PIT_PIV			GENMASK(19, 0)		/* Periodic Interval Value */
29 30

#define AT91_PIT_SR		0x04			/* Status Register */
31
#define AT91_PIT_PITS			BIT(0)			/* Timer Status */
32 33 34

#define AT91_PIT_PIVR		0x08			/* Periodic Interval Value Register */
#define AT91_PIT_PIIR		0x0c			/* Periodic Interval Image Register */
35 36
#define AT91_PIT_PICNT			GENMASK(31, 20)		/* Interval Counter */
#define AT91_PIT_CPIV			GENMASK(19, 0)		/* Inverval Value */
37 38 39 40

#define PIT_CPIV(x)	((x) & AT91_PIT_CPIV)
#define PIT_PICNT(x)	(((x) & AT91_PIT_PICNT) >> 20)

41 42 43
struct pit_data {
	struct clock_event_device	clkevt;
	struct clocksource		clksrc;
44

45 46 47 48 49 50 51 52
	void __iomem	*base;
	u32		cycle;
	u32		cnt;
	unsigned int	irq;
	struct clk	*mck;
};

static inline struct pit_data *clksrc_to_pit_data(struct clocksource *clksrc)
53
{
54
	return container_of(clksrc, struct pit_data, clksrc);
55 56
}

57
static inline struct pit_data *clkevt_to_pit_data(struct clock_event_device *clkevt)
58
{
59 60 61 62 63
	return container_of(clkevt, struct pit_data, clkevt);
}

static inline unsigned int pit_read(void __iomem *base, unsigned int reg_offset)
{
64
	return readl_relaxed(base + reg_offset);
65 66 67 68
}

static inline void pit_write(void __iomem *base, unsigned int reg_offset, unsigned long value)
{
69
	writel_relaxed(value, base + reg_offset);
70
}
71

72
/*
73 74
 * Clocksource:  just a monotonic counter of MCK/16 cycles.
 * We don't care whether or not PIT irqs are enabled.
75
 */
76
static u64 read_pit_clk(struct clocksource *cs)
77
{
78
	struct pit_data *data = clksrc_to_pit_data(cs);
79 80 81 82 83
	unsigned long flags;
	u32 elapsed;
	u32 t;

	raw_local_irq_save(flags);
84 85
	elapsed = data->cnt;
	t = pit_read(data->base, AT91_PIT_PIIR);
86 87
	raw_local_irq_restore(flags);

88
	elapsed += PIT_PICNT(t) * data->cycle;
89 90 91 92
	elapsed += PIT_CPIV(t);
	return elapsed;
}

93 94 95 96 97 98 99 100 101
static int pit_clkevt_shutdown(struct clock_event_device *dev)
{
	struct pit_data *data = clkevt_to_pit_data(dev);

	/* disable irq, leaving the clocksource active */
	pit_write(data->base, AT91_PIT_MR, (data->cycle - 1) | AT91_PIT_PITEN);
	return 0;
}

102 103 104
/*
 * Clockevent device:  interrupts every 1/HZ (== pit_cycles * MCK/16)
 */
105
static int pit_clkevt_set_periodic(struct clock_event_device *dev)
106
{
107 108
	struct pit_data *data = clkevt_to_pit_data(dev);

109 110 111 112 113
	/* update clocksource counter */
	data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR));
	pit_write(data->base, AT91_PIT_MR,
		  (data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN);
	return 0;
114 115
}

116 117
static void at91sam926x_pit_suspend(struct clock_event_device *cedev)
{
118 119
	struct pit_data *data = clkevt_to_pit_data(cedev);

120
	/* Disable timer */
121
	pit_write(data->base, AT91_PIT_MR, 0);
122 123
}

124
static void at91sam926x_pit_reset(struct pit_data *data)
125 126
{
	/* Disable timer and irqs */
127
	pit_write(data->base, AT91_PIT_MR, 0);
128 129

	/* Clear any pending interrupts, wait for PIT to stop counting */
130
	while (PIT_CPIV(pit_read(data->base, AT91_PIT_PIVR)) != 0)
131 132 133
		cpu_relax();

	/* Start PIT but don't enable IRQ */
134 135
	pit_write(data->base, AT91_PIT_MR,
		  (data->cycle - 1) | AT91_PIT_PITEN);
136 137 138 139
}

static void at91sam926x_pit_resume(struct clock_event_device *cedev)
{
140
	struct pit_data *data = clkevt_to_pit_data(cedev);
141

142 143
	at91sam926x_pit_reset(data);
}
144

145 146 147
/*
 * IRQ handler for the timer.
 */
148
static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
149
{
150 151
	struct pit_data *data = dev_id;

152
	/* The PIT interrupt may be disabled, and is shared */
153
	if (clockevent_state_periodic(&data->clkevt) &&
154
	    (pit_read(data->base, AT91_PIT_SR) & AT91_PIT_PITS)) {
155
		/* Get number of ticks performed before irq, and ack it */
156 157 158
		data->cnt += data->cycle * PIT_PICNT(pit_read(data->base,
							      AT91_PIT_PIVR));
		data->clkevt.event_handler(&data->clkevt);
159 160

		return IRQ_HANDLED;
161 162 163
	}

	return IRQ_NONE;
164 165 166
}

/*
167
 * Set up both clocksource and clockevent support.
168
 */
169
static int __init at91sam926x_pit_dt_init(struct device_node *node)
170
{
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
	unsigned long   pit_rate;
	unsigned        bits;
	int             ret;
	struct pit_data *data;

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	data->base = of_iomap(node, 0);
	if (!data->base) {
		pr_err("Could not map PIT address\n");
		return -ENXIO;
	}

	data->mck = of_clk_get(node, 0);
	if (IS_ERR(data->mck)) {
		pr_err("Unable to get mck clk\n");
		return PTR_ERR(data->mck);
	}

	ret = clk_prepare_enable(data->mck);
	if (ret) {
		pr_err("Unable to enable mck\n");
		return ret;
	}

	/* Get the interrupts property */
	data->irq = irq_of_parse_and_map(node, 0);
	if (!data->irq) {
		pr_err("Unable to get IRQ from DT\n");
		return -EINVAL;
	}
204 205 206 207 208

	/*
	 * Use our actual MCK to figure out how many MCK/16 ticks per
	 * 1/HZ period (instead of a compile-time constant LATCH).
	 */
209 210 211
	pit_rate = clk_get_rate(data->mck) / 16;
	data->cycle = DIV_ROUND_CLOSEST(pit_rate, HZ);
	WARN_ON(((data->cycle - 1) & ~AT91_PIT_PIV) != 0);
212

213
	/* Initialize and enable the timer */
214
	at91sam926x_pit_reset(data);
215 216 217 218 219

	/*
	 * Register clocksource.  The high order bits of PIV are unused,
	 * so this isn't a 32-bit counter unless we get clockevent irqs.
	 */
220 221 222 223
	bits = 12 /* PICNT */ + ilog2(data->cycle) /* PIV */;
	data->clksrc.mask = CLOCKSOURCE_MASK(bits);
	data->clksrc.name = "pit";
	data->clksrc.rating = 175;
224 225
	data->clksrc.read = read_pit_clk;
	data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
226 227 228
	
	ret = clocksource_register_hz(&data->clksrc, pit_rate);
	if (ret) {
229
		pr_err("Failed to register clocksource\n");
230 231
		return ret;
	}
232 233

	/* Set up irq handler */
234
	ret = request_irq(data->irq, at91sam926x_pit_interrupt,
235
			  IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
236
			  "at91_tick", data);
237 238 239 240
	if (ret) {
		pr_err("Unable to setup IRQ\n");
		return ret;
	}
241 242

	/* Set up and register clockevents */
243 244 245 246 247 248 249
	data->clkevt.name = "pit";
	data->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
	data->clkevt.shift = 32;
	data->clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, data->clkevt.shift);
	data->clkevt.rating = 100;
	data->clkevt.cpumask = cpumask_of(0);

250 251
	data->clkevt.set_state_shutdown = pit_clkevt_shutdown;
	data->clkevt.set_state_periodic = pit_clkevt_set_periodic;
252 253 254
	data->clkevt.resume = at91sam926x_pit_resume;
	data->clkevt.suspend = at91sam926x_pit_suspend;
	clockevents_register_device(&data->clkevt);
255 256

	return 0;
257
}
258
TIMER_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit",
259
		       at91sam926x_pit_dt_init);