Blame view
drivers/clocksource/h8300_timer16.c
3.96 KB
618b902d8 h8300: clocksource |
1 2 3 4 5 |
/* * H8/300 16bit Timer driver * * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp> */ |
618b902d8 h8300: clocksource |
6 7 |
#include <linux/interrupt.h> #include <linux/init.h> |
618b902d8 h8300: clocksource |
8 |
#include <linux/clocksource.h> |
618b902d8 h8300: clocksource |
9 10 11 |
#include <linux/clk.h> #include <linux/io.h> #include <linux/of.h> |
4633f4cac clocksource/drive... |
12 13 |
#include <linux/of_address.h> #include <linux/of_irq.h> |
618b902d8 h8300: clocksource |
14 |
|
618b902d8 h8300: clocksource |
15 |
#define TSTR 0 |
618b902d8 h8300: clocksource |
16 17 18 |
#define TISRC 6 #define TCR 0 |
618b902d8 h8300: clocksource |
19 |
#define TCNT 2 |
618b902d8 h8300: clocksource |
20 |
|
d33f250af clocksource/drive... |
21 22 |
#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a)) #define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a)) |
618b902d8 h8300: clocksource |
23 |
struct timer16_priv { |
618b902d8 h8300: clocksource |
24 |
struct clocksource cs; |
618b902d8 h8300: clocksource |
25 |
unsigned long total_cycles; |
751605152 h8300: Rename ctl... |
26 27 |
void __iomem *mapbase; void __iomem *mapcommon; |
618b902d8 h8300: clocksource |
28 29 |
unsigned short cs_enabled; unsigned char enb; |
618b902d8 h8300: clocksource |
30 |
unsigned char ovf; |
2a0ff8777 clocksource/drive... |
31 |
unsigned char ovie; |
618b902d8 h8300: clocksource |
32 33 34 35 |
}; static unsigned long timer16_get_counter(struct timer16_priv *p) { |
d33f250af clocksource/drive... |
36 37 |
unsigned short v1, v2, v3; unsigned char o1, o2; |
618b902d8 h8300: clocksource |
38 |
|
d33f250af clocksource/drive... |
39 |
o1 = ioread8(p->mapcommon + TISRC) & p->ovf; |
618b902d8 h8300: clocksource |
40 41 42 43 |
/* Make sure the timer value is stable. Stolen from acpi_pm.c */ do { o2 = o1; |
d33f250af clocksource/drive... |
44 45 46 47 |
v1 = ioread16be(p->mapbase + TCNT); v2 = ioread16be(p->mapbase + TCNT); v3 = ioread16be(p->mapbase + TCNT); o1 = ioread8(p->mapcommon + TISRC) & p->ovf; |
618b902d8 h8300: clocksource |
48 49 |
} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); |
2f445e0aa clocksource/drive... |
50 51 52 53 |
if (likely(!o1)) return v2; else return v2 + 0x10000; |
618b902d8 h8300: clocksource |
54 55 56 57 58 59 |
} static irqreturn_t timer16_interrupt(int irq, void *dev_id) { struct timer16_priv *p = (struct timer16_priv *)dev_id; |
d33f250af clocksource/drive... |
60 |
bclr(p->ovf, p->mapcommon + TISRC); |
618b902d8 h8300: clocksource |
61 62 63 64 65 66 67 68 69 70 71 72 73 |
p->total_cycles += 0x10000; return IRQ_HANDLED; } static inline struct timer16_priv *cs_to_priv(struct clocksource *cs) { return container_of(cs, struct timer16_priv, cs); } static cycle_t timer16_clocksource_read(struct clocksource *cs) { struct timer16_priv *p = cs_to_priv(cs); |
05de7ed67 clocksource/drive... |
74 |
unsigned long raw, value; |
618b902d8 h8300: clocksource |
75 |
|
618b902d8 h8300: clocksource |
76 77 |
value = p->total_cycles; raw = timer16_get_counter(p); |
618b902d8 h8300: clocksource |
78 79 80 81 82 83 84 85 86 87 88 |
return value + raw; } static int timer16_enable(struct clocksource *cs) { struct timer16_priv *p = cs_to_priv(cs); WARN_ON(p->cs_enabled); p->total_cycles = 0; |
d33f250af clocksource/drive... |
89 90 91 92 |
iowrite16be(0x0000, p->mapbase + TCNT); iowrite8(0x83, p->mapbase + TCR); bset(p->ovie, p->mapcommon + TISRC); bset(p->enb, p->mapcommon + TSTR); |
618b902d8 h8300: clocksource |
93 94 95 96 97 98 99 100 101 102 |
p->cs_enabled = true; return 0; } static void timer16_disable(struct clocksource *cs) { struct timer16_priv *p = cs_to_priv(cs); WARN_ON(!p->cs_enabled); |
d33f250af clocksource/drive... |
103 104 |
bclr(p->ovie, p->mapcommon + TISRC); bclr(p->enb, p->mapcommon + TSTR); |
618b902d8 h8300: clocksource |
105 106 107 |
p->cs_enabled = false; } |
4633f4cac clocksource/drive... |
108 109 110 111 112 113 114 115 116 117 118 |
static struct timer16_priv timer16_priv = { .cs = { .name = "h8300_16timer", .rating = 200, .read = timer16_clocksource_read, .enable = timer16_enable, .disable = timer16_disable, .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }, }; |
618b902d8 h8300: clocksource |
119 120 |
#define REG_CH 0 #define REG_COMM 1 |
4633f4cac clocksource/drive... |
121 |
static void __init h8300_16timer_init(struct device_node *node) |
618b902d8 h8300: clocksource |
122 |
{ |
4633f4cac clocksource/drive... |
123 |
void __iomem *base[2]; |
618b902d8 h8300: clocksource |
124 125 |
int ret, irq; unsigned int ch; |
4633f4cac clocksource/drive... |
126 |
struct clk *clk; |
618b902d8 h8300: clocksource |
127 |
|
4633f4cac clocksource/drive... |
128 129 130 131 132 |
clk = of_clk_get(node, 0); if (IS_ERR(clk)) { pr_err("failed to get clock for clocksource "); return; |
618b902d8 h8300: clocksource |
133 |
} |
4633f4cac clocksource/drive... |
134 135 136 137 138 |
base[REG_CH] = of_iomap(node, 0); if (!base[REG_CH]) { pr_err("failed to map registers for clocksource "); goto free_clk; |
618b902d8 h8300: clocksource |
139 |
} |
618b902d8 h8300: clocksource |
140 |
|
4633f4cac clocksource/drive... |
141 142 143 144 145 |
base[REG_COMM] = of_iomap(node, 1); if (!base[REG_COMM]) { pr_err("failed to map registers for clocksource "); goto unmap_ch; |
618b902d8 h8300: clocksource |
146 |
} |
4633f4cac clocksource/drive... |
147 |
irq = irq_of_parse_and_map(node, 0); |
5019c9023 clocksource/drive... |
148 |
if (!irq) { |
4633f4cac clocksource/drive... |
149 150 151 |
pr_err("failed to get irq for clockevent "); goto unmap_comm; |
618b902d8 h8300: clocksource |
152 |
} |
4633f4cac clocksource/drive... |
153 |
of_property_read_u32(node, "renesas,channel", &ch); |
618b902d8 h8300: clocksource |
154 |
|
751605152 h8300: Rename ctl... |
155 156 |
timer16_priv.mapbase = base[REG_CH]; timer16_priv.mapcommon = base[REG_COMM]; |
d33f250af clocksource/drive... |
157 158 159 |
timer16_priv.enb = ch; timer16_priv.ovf = ch; timer16_priv.ovie = 4 + ch; |
618b902d8 h8300: clocksource |
160 |
|
4633f4cac clocksource/drive... |
161 162 163 164 165 166 |
ret = request_irq(irq, timer16_interrupt, IRQF_TIMER, timer16_priv.cs.name, &timer16_priv); if (ret < 0) { pr_err("failed to request irq %d of clocksource ", irq); goto unmap_comm; |
618b902d8 h8300: clocksource |
167 |
} |
618b902d8 h8300: clocksource |
168 |
|
4633f4cac clocksource/drive... |
169 |
clocksource_register_hz(&timer16_priv.cs, |
d33f250af clocksource/drive... |
170 |
clk_get_rate(clk) / 8); |
4633f4cac clocksource/drive... |
171 |
return; |
618b902d8 h8300: clocksource |
172 |
|
4633f4cac clocksource/drive... |
173 174 175 176 177 178 |
unmap_comm: iounmap(base[REG_COMM]); unmap_ch: iounmap(base[REG_CH]); free_clk: clk_put(clk); |
618b902d8 h8300: clocksource |
179 |
} |
4633f4cac clocksource/drive... |
180 |
CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init); |