diff options
-rw-r--r-- | drivers/clocksource/h8300_timer16.c | 141 | ||||
-rw-r--r-- | drivers/clocksource/h8300_timer8.c | 150 | ||||
-rw-r--r-- | drivers/clocksource/h8300_tpu.c | 117 |
3 files changed, 144 insertions, 264 deletions
diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c index 0e076c6fc006..cdf0d83a91be 100644 --- a/drivers/clocksource/h8300_timer16.c +++ b/drivers/clocksource/h8300_timer16.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_address.h> | ||
21 | #include <linux/of_irq.h> | ||
20 | 22 | ||
21 | #include <asm/segment.h> | 23 | #include <asm/segment.h> |
22 | #include <asm/irq.h> | 24 | #include <asm/irq.h> |
@@ -47,9 +49,7 @@ | |||
47 | #define ABSOLUTE 1 | 49 | #define ABSOLUTE 1 |
48 | 50 | ||
49 | struct timer16_priv { | 51 | struct timer16_priv { |
50 | struct platform_device *pdev; | ||
51 | struct clocksource cs; | 52 | struct clocksource cs; |
52 | struct irqaction irqaction; | ||
53 | unsigned long total_cycles; | 53 | unsigned long total_cycles; |
54 | unsigned long mapbase; | 54 | unsigned long mapbase; |
55 | unsigned long mapcommon; | 55 | unsigned long mapcommon; |
@@ -144,110 +144,77 @@ static void timer16_disable(struct clocksource *cs) | |||
144 | p->cs_enabled = false; | 144 | p->cs_enabled = false; |
145 | } | 145 | } |
146 | 146 | ||
147 | static struct timer16_priv timer16_priv = { | ||
148 | .cs = { | ||
149 | .name = "h8300_16timer", | ||
150 | .rating = 200, | ||
151 | .read = timer16_clocksource_read, | ||
152 | .enable = timer16_enable, | ||
153 | .disable = timer16_disable, | ||
154 | .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8), | ||
155 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
156 | }, | ||
157 | }; | ||
158 | |||
147 | #define REG_CH 0 | 159 | #define REG_CH 0 |
148 | #define REG_COMM 1 | 160 | #define REG_COMM 1 |
149 | 161 | ||
150 | static int timer16_setup(struct timer16_priv *p, struct platform_device *pdev) | 162 | static void __init h8300_16timer_init(struct device_node *node) |
151 | { | 163 | { |
152 | struct resource *res[2]; | 164 | void __iomem *base[2]; |
153 | int ret, irq; | 165 | int ret, irq; |
154 | unsigned int ch; | 166 | unsigned int ch; |
167 | struct clk *clk; | ||
155 | 168 | ||
156 | p->pdev = pdev; | 169 | clk = of_clk_get(node, 0); |
157 | 170 | if (IS_ERR(clk)) { | |
158 | res[REG_CH] = platform_get_resource(p->pdev, | 171 | pr_err("failed to get clock for clocksource\n"); |
159 | IORESOURCE_MEM, REG_CH); | 172 | return; |
160 | res[REG_COMM] = platform_get_resource(p->pdev, | ||
161 | IORESOURCE_MEM, REG_COMM); | ||
162 | if (!res[REG_CH] || !res[REG_COMM]) { | ||
163 | dev_err(&p->pdev->dev, "failed to get I/O memory\n"); | ||
164 | return -ENXIO; | ||
165 | } | ||
166 | irq = platform_get_irq(p->pdev, 0); | ||
167 | if (irq < 0) { | ||
168 | dev_err(&p->pdev->dev, "failed to get irq\n"); | ||
169 | return irq; | ||
170 | } | 173 | } |
171 | 174 | ||
172 | p->clk = clk_get(&p->pdev->dev, "fck"); | 175 | base[REG_CH] = of_iomap(node, 0); |
173 | if (IS_ERR(p->clk)) { | 176 | if (!base[REG_CH]) { |
174 | dev_err(&p->pdev->dev, "can't get clk\n"); | 177 | pr_err("failed to map registers for clocksource\n"); |
175 | return PTR_ERR(p->clk); | 178 | goto free_clk; |
176 | } | 179 | } |
177 | of_property_read_u32(p->pdev->dev.of_node, "renesas,channel", &ch); | ||
178 | |||
179 | p->pdev = pdev; | ||
180 | p->mapbase = res[REG_CH]->start; | ||
181 | p->mapcommon = res[REG_COMM]->start; | ||
182 | p->enb = 1 << ch; | ||
183 | p->imfa = 1 << ch; | ||
184 | p->imiea = 1 << (4 + ch); | ||
185 | p->cs.name = pdev->name; | ||
186 | p->cs.rating = 200; | ||
187 | p->cs.read = timer16_clocksource_read; | ||
188 | p->cs.enable = timer16_enable; | ||
189 | p->cs.disable = timer16_disable; | ||
190 | p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); | ||
191 | p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
192 | 180 | ||
193 | ret = request_irq(irq, timer16_interrupt, | 181 | base[REG_COMM] = of_iomap(node, 1); |
194 | IRQF_TIMER, pdev->name, p); | 182 | if (!base[REG_COMM]) { |
195 | if (ret < 0) { | 183 | pr_err("failed to map registers for clocksource\n"); |
196 | dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); | 184 | goto unmap_ch; |
197 | return ret; | ||
198 | } | 185 | } |
199 | 186 | ||
200 | clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 8); | 187 | irq = irq_of_parse_and_map(node, 0); |
201 | 188 | if (irq < 0) { | |
202 | return 0; | 189 | pr_err("failed to get irq for clockevent\n"); |
203 | } | 190 | goto unmap_comm; |
204 | |||
205 | static int timer16_probe(struct platform_device *pdev) | ||
206 | { | ||
207 | struct timer16_priv *p = platform_get_drvdata(pdev); | ||
208 | |||
209 | if (p) { | ||
210 | dev_info(&pdev->dev, "kept as earlytimer\n"); | ||
211 | return 0; | ||
212 | } | 191 | } |
213 | 192 | ||
214 | p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); | 193 | of_property_read_u32(node, "renesas,channel", &ch); |
215 | if (!p) | ||
216 | return -ENOMEM; | ||
217 | 194 | ||
218 | return timer16_setup(p, pdev); | 195 | timer16_priv.mapbase = (unsigned long)base[REG_CH]; |
219 | } | 196 | timer16_priv.mapcommon = (unsigned long)base[REG_COMM]; |
197 | timer16_priv.enb = 1 << ch; | ||
198 | timer16_priv.imfa = 1 << ch; | ||
199 | timer16_priv.imiea = 1 << (4 + ch); | ||
220 | 200 | ||
221 | static int timer16_remove(struct platform_device *pdev) | 201 | ret = request_irq(irq, timer16_interrupt, |
222 | { | 202 | IRQF_TIMER, timer16_priv.cs.name, &timer16_priv); |
223 | return -EBUSY; | 203 | if (ret < 0) { |
224 | } | 204 | pr_err("failed to request irq %d of clocksource\n", irq); |
225 | 205 | goto unmap_comm; | |
226 | static const struct of_device_id timer16_of_table[] = { | ||
227 | { .compatible = "renesas,16bit-timer" }, | ||
228 | { } | ||
229 | }; | ||
230 | static struct platform_driver timer16_driver = { | ||
231 | .probe = timer16_probe, | ||
232 | .remove = timer16_remove, | ||
233 | .driver = { | ||
234 | .name = "h8300h-16timer", | ||
235 | .of_match_table = of_match_ptr(timer16_of_table), | ||
236 | } | 206 | } |
237 | }; | ||
238 | 207 | ||
239 | static int __init timer16_init(void) | 208 | clocksource_register_hz(&timer16_priv.cs, |
240 | { | 209 | clk_get_rate(timer16_priv.clk) / 8); |
241 | return platform_driver_register(&timer16_driver); | 210 | return; |
242 | } | ||
243 | 211 | ||
244 | static void __exit timer16_exit(void) | 212 | unmap_comm: |
245 | { | 213 | iounmap(base[REG_COMM]); |
246 | platform_driver_unregister(&timer16_driver); | 214 | unmap_ch: |
215 | iounmap(base[REG_CH]); | ||
216 | free_clk: | ||
217 | clk_put(clk); | ||
247 | } | 218 | } |
248 | 219 | ||
249 | subsys_initcall(timer16_init); | 220 | CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init); |
250 | module_exit(timer16_exit); | ||
251 | MODULE_AUTHOR("Yoshinori Sato"); | ||
252 | MODULE_DESCRIPTION("H8/300H 16bit Timer Driver"); | ||
253 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index 44375d8b9bc4..f0680eb4f93d 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c | |||
@@ -12,13 +12,14 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
17 | #include <linux/clockchips.h> | 16 | #include <linux/clockchips.h> |
18 | #include <linux/module.h> | 17 | #include <linux/module.h> |
19 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
20 | #include <linux/io.h> | 19 | #include <linux/io.h> |
21 | #include <linux/of.h> | 20 | #include <linux/of.h> |
21 | #include <linux/of_address.h> | ||
22 | #include <linux/of_irq.h> | ||
22 | 23 | ||
23 | #include <asm/irq.h> | 24 | #include <asm/irq.h> |
24 | 25 | ||
@@ -39,10 +40,10 @@ | |||
39 | #define RELATIVE 0 | 40 | #define RELATIVE 0 |
40 | #define ABSOLUTE 1 | 41 | #define ABSOLUTE 1 |
41 | 42 | ||
43 | #define SCALE 64 | ||
44 | |||
42 | struct timer8_priv { | 45 | struct timer8_priv { |
43 | struct platform_device *pdev; | ||
44 | struct clock_event_device ced; | 46 | struct clock_event_device ced; |
45 | struct irqaction irqaction; | ||
46 | unsigned long mapbase; | 47 | unsigned long mapbase; |
47 | raw_spinlock_t lock; | 48 | raw_spinlock_t lock; |
48 | unsigned long flags; | 49 | unsigned long flags; |
@@ -111,7 +112,7 @@ static void timer8_set_next(struct timer8_priv *p, unsigned long delta) | |||
111 | 112 | ||
112 | static int timer8_enable(struct timer8_priv *p) | 113 | static int timer8_enable(struct timer8_priv *p) |
113 | { | 114 | { |
114 | p->rate = clk_get_rate(p->pclk) / 64; | 115 | p->rate = clk_get_rate(p->pclk) / SCALE; |
115 | ctrl_outw(0xffff, p->mapbase + TCORA); | 116 | ctrl_outw(0xffff, p->mapbase + TCORA); |
116 | ctrl_outw(0x0000, p->mapbase + _8TCNT); | 117 | ctrl_outw(0x0000, p->mapbase + _8TCNT); |
117 | ctrl_outw(0x0c02, p->mapbase + _8TCR); | 118 | ctrl_outw(0x0c02, p->mapbase + _8TCR); |
@@ -179,7 +180,7 @@ static int timer8_clock_event_periodic(struct clock_event_device *ced) | |||
179 | { | 180 | { |
180 | struct timer8_priv *p = ced_to_priv(ced); | 181 | struct timer8_priv *p = ced_to_priv(ced); |
181 | 182 | ||
182 | dev_info(&p->pdev->dev, "used for periodic clock events\n"); | 183 | pr_info("%s: used for periodic clock events\n", ced->name); |
183 | timer8_stop(p); | 184 | timer8_stop(p); |
184 | timer8_clock_event_start(p, PERIODIC); | 185 | timer8_clock_event_start(p, PERIODIC); |
185 | 186 | ||
@@ -190,7 +191,7 @@ static int timer8_clock_event_oneshot(struct clock_event_device *ced) | |||
190 | { | 191 | { |
191 | struct timer8_priv *p = ced_to_priv(ced); | 192 | struct timer8_priv *p = ced_to_priv(ced); |
192 | 193 | ||
193 | dev_info(&p->pdev->dev, "used for oneshot clock events\n"); | 194 | pr_info("%s: used for oneshot clock events\n", ced->name); |
194 | timer8_stop(p); | 195 | timer8_stop(p); |
195 | timer8_clock_event_start(p, ONESHOT); | 196 | timer8_clock_event_start(p, ONESHOT); |
196 | 197 | ||
@@ -208,110 +209,61 @@ static int timer8_clock_event_next(unsigned long delta, | |||
208 | return 0; | 209 | return 0; |
209 | } | 210 | } |
210 | 211 | ||
211 | static int timer8_setup(struct timer8_priv *p, | 212 | static struct timer8_priv timer8_priv = { |
212 | struct platform_device *pdev) | 213 | .ced = { |
214 | .name = "h8300_8timer", | ||
215 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
216 | .rating = 200, | ||
217 | .set_next_event = timer8_clock_event_next, | ||
218 | .set_state_shutdown = timer8_clock_event_shutdown, | ||
219 | .set_state_periodic = timer8_clock_event_periodic, | ||
220 | .set_state_oneshot = timer8_clock_event_oneshot, | ||
221 | }, | ||
222 | }; | ||
223 | |||
224 | static void __init h8300_8timer_init(struct device_node *node) | ||
213 | { | 225 | { |
214 | struct resource *res; | 226 | void __iomem *base; |
215 | int irq; | 227 | int irq; |
216 | int ret; | 228 | int ret = 0; |
229 | int rate; | ||
230 | struct clk *clk; | ||
217 | 231 | ||
218 | p->pdev = pdev; | 232 | clk = of_clk_get(node, 0); |
233 | if (IS_ERR(clk)) { | ||
234 | pr_err("failed to get clock for clockevent\n"); | ||
235 | return; | ||
236 | } | ||
219 | 237 | ||
220 | res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); | 238 | base = of_iomap(node, 0); |
221 | if (!res) { | 239 | if (!base) { |
222 | dev_err(&p->pdev->dev, "failed to get I/O memory\n"); | 240 | pr_err("failed to map registers for clockevent\n"); |
223 | return -ENXIO; | 241 | goto free_clk; |
224 | } | 242 | } |
225 | 243 | ||
226 | irq = platform_get_irq(p->pdev, 0); | 244 | irq = irq_of_parse_and_map(node, 0); |
227 | if (irq < 0) { | 245 | if (irq < 0) { |
228 | dev_err(&p->pdev->dev, "failed to get irq\n"); | 246 | pr_err("failed to get irq for clockevent\n"); |
229 | return -ENXIO; | 247 | goto unmap_reg; |
230 | } | 248 | } |
231 | 249 | ||
232 | p->mapbase = res->start; | 250 | timer8_priv.mapbase = (unsigned long)base; |
233 | 251 | timer8_priv.pclk = clk; | |
234 | p->irqaction.name = dev_name(&p->pdev->dev); | ||
235 | p->irqaction.handler = timer8_interrupt; | ||
236 | p->irqaction.dev_id = p; | ||
237 | p->irqaction.flags = IRQF_TIMER; | ||
238 | |||
239 | p->pclk = clk_get(&p->pdev->dev, "fck"); | ||
240 | if (IS_ERR(p->pclk)) { | ||
241 | dev_err(&p->pdev->dev, "can't get clk\n"); | ||
242 | return PTR_ERR(p->pclk); | ||
243 | } | ||
244 | 252 | ||
245 | p->ced.name = pdev->name; | 253 | ret = request_irq(irq, timer8_interrupt, |
246 | p->ced.features = CLOCK_EVT_FEAT_PERIODIC | | 254 | IRQF_TIMER, timer8_priv.ced.name, &timer8_priv); |
247 | CLOCK_EVT_FEAT_ONESHOT; | ||
248 | p->ced.rating = 200; | ||
249 | p->ced.cpumask = cpumask_of(0); | ||
250 | p->ced.set_next_event = timer8_clock_event_next; | ||
251 | p->ced.set_state_shutdown = timer8_clock_event_shutdown; | ||
252 | p->ced.set_state_periodic = timer8_clock_event_periodic; | ||
253 | p->ced.set_state_oneshot = timer8_clock_event_oneshot; | ||
254 | |||
255 | ret = setup_irq(irq, &p->irqaction); | ||
256 | if (ret < 0) { | 255 | if (ret < 0) { |
257 | dev_err(&p->pdev->dev, | 256 | pr_err("failed to request irq %d for clockevent\n", irq); |
258 | "failed to request irq %d\n", irq); | 257 | goto unmap_reg; |
259 | return ret; | ||
260 | } | 258 | } |
261 | clockevents_register_device(&p->ced); | 259 | rate = clk_get_rate(clk) / SCALE; |
262 | platform_set_drvdata(pdev, p); | 260 | clockevents_config_and_register(&timer8_priv.ced, rate, 1, 0x0000ffff); |
263 | 261 | return; | |
264 | return 0; | 262 | |
265 | } | 263 | unmap_reg: |
266 | 264 | iounmap(base); | |
267 | static int timer8_probe(struct platform_device *pdev) | 265 | free_clk: |
268 | { | 266 | clk_put(clk); |
269 | struct timer8_priv *p = platform_get_drvdata(pdev); | ||
270 | |||
271 | if (p) { | ||
272 | dev_info(&pdev->dev, "kept as earlytimer\n"); | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); | ||
277 | if (!p) | ||
278 | return -ENOMEM; | ||
279 | |||
280 | return timer8_setup(p, pdev); | ||
281 | } | ||
282 | |||
283 | static int timer8_remove(struct platform_device *pdev) | ||
284 | { | ||
285 | return -EBUSY; | ||
286 | } | ||
287 | |||
288 | static const struct of_device_id timer8_of_table[] __maybe_unused = { | ||
289 | { .compatible = "renesas,8bit-timer" }, | ||
290 | { } | ||
291 | }; | ||
292 | |||
293 | MODULE_DEVICE_TABLE(of, timer8_of_table); | ||
294 | static struct platform_driver timer8_driver = { | ||
295 | .probe = timer8_probe, | ||
296 | .remove = timer8_remove, | ||
297 | .driver = { | ||
298 | .name = "h8300-8timer", | ||
299 | .of_match_table = of_match_ptr(timer8_of_table), | ||
300 | } | ||
301 | }; | ||
302 | |||
303 | static int __init timer8_init(void) | ||
304 | { | ||
305 | return platform_driver_register(&timer8_driver); | ||
306 | } | ||
307 | |||
308 | static void __exit timer8_exit(void) | ||
309 | { | ||
310 | platform_driver_unregister(&timer8_driver); | ||
311 | } | 267 | } |
312 | 268 | ||
313 | subsys_initcall(timer8_init); | 269 | CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init); |
314 | module_exit(timer8_exit); | ||
315 | MODULE_AUTHOR("Yoshinori Sato"); | ||
316 | MODULE_DESCRIPTION("H8/300 8bit Timer Driver"); | ||
317 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c index 5487410bfabb..ed0b49344577 100644 --- a/drivers/clocksource/h8300_tpu.c +++ b/drivers/clocksource/h8300_tpu.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * H8/300 TPU Driver | 2 | * H8S TPU Driver |
3 | * | 3 | * |
4 | * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp> | 4 | * Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp> |
5 | * | 5 | * |
@@ -17,8 +17,8 @@ | |||
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | 20 | #include <linux/of_address.h> | |
21 | #include <asm/irq.h> | 21 | #include <linux/of_irq.h> |
22 | 22 | ||
23 | #define TCR 0 | 23 | #define TCR 0 |
24 | #define TMDR 1 | 24 | #define TMDR 1 |
@@ -32,9 +32,7 @@ | |||
32 | #define TGRD 14 | 32 | #define TGRD 14 |
33 | 33 | ||
34 | struct tpu_priv { | 34 | struct tpu_priv { |
35 | struct platform_device *pdev; | ||
36 | struct clocksource cs; | 35 | struct clocksource cs; |
37 | struct clk *clk; | ||
38 | unsigned long mapbase1; | 36 | unsigned long mapbase1; |
39 | unsigned long mapbase2; | 37 | unsigned long mapbase2; |
40 | raw_spinlock_t lock; | 38 | raw_spinlock_t lock; |
@@ -116,91 +114,54 @@ static void tpu_clocksource_disable(struct clocksource *cs) | |||
116 | p->cs_enabled = false; | 114 | p->cs_enabled = false; |
117 | } | 115 | } |
118 | 116 | ||
117 | static struct tpu_priv tpu_priv = { | ||
118 | .cs = { | ||
119 | .name = "H8S_TPU", | ||
120 | .rating = 200, | ||
121 | .read = tpu_clocksource_read, | ||
122 | .enable = tpu_clocksource_enable, | ||
123 | .disable = tpu_clocksource_disable, | ||
124 | .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8), | ||
125 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
126 | }, | ||
127 | }; | ||
128 | |||
119 | #define CH_L 0 | 129 | #define CH_L 0 |
120 | #define CH_H 1 | 130 | #define CH_H 1 |
121 | 131 | ||
122 | static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev) | 132 | static void __init h8300_tpu_init(struct device_node *node) |
123 | { | 133 | { |
124 | struct resource *res[2]; | 134 | void __iomem *base[2]; |
125 | 135 | struct clk *clk; | |
126 | p->pdev = pdev; | ||
127 | 136 | ||
128 | res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L); | 137 | clk = of_clk_get(node, 0); |
129 | res[CH_H] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_H); | 138 | if (IS_ERR(clk)) { |
130 | if (!res[CH_L] || !res[CH_H]) { | 139 | pr_err("failed to get clock for clocksource\n"); |
131 | dev_err(&p->pdev->dev, "failed to get I/O memory\n"); | 140 | return; |
132 | return -ENXIO; | ||
133 | } | 141 | } |
134 | 142 | ||
135 | p->clk = clk_get(&p->pdev->dev, "fck"); | 143 | base[CH_L] = of_iomap(node, CH_L); |
136 | if (IS_ERR(p->clk)) { | 144 | if (!base[CH_L]) { |
137 | dev_err(&p->pdev->dev, "can't get clk\n"); | 145 | pr_err("failed to map registers for clocksource\n"); |
138 | return PTR_ERR(p->clk); | 146 | goto free_clk; |
139 | } | 147 | } |
140 | 148 | base[CH_H] = of_iomap(node, CH_H); | |
141 | p->mapbase1 = res[CH_L]->start; | 149 | if (!base[CH_H]) { |
142 | p->mapbase2 = res[CH_H]->start; | 150 | pr_err("failed to map registers for clocksource\n"); |
143 | 151 | goto unmap_L; | |
144 | p->cs.name = pdev->name; | ||
145 | p->cs.rating = 200; | ||
146 | p->cs.read = tpu_clocksource_read; | ||
147 | p->cs.enable = tpu_clocksource_enable; | ||
148 | p->cs.disable = tpu_clocksource_disable; | ||
149 | p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); | ||
150 | p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
151 | clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 64); | ||
152 | platform_set_drvdata(pdev, p); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int tpu_probe(struct platform_device *pdev) | ||
158 | { | ||
159 | struct tpu_priv *p = platform_get_drvdata(pdev); | ||
160 | |||
161 | if (p) { | ||
162 | dev_info(&pdev->dev, "kept as earlytimer\n"); | ||
163 | return 0; | ||
164 | } | 152 | } |
165 | 153 | ||
166 | p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); | 154 | tpu_priv.mapbase1 = (unsigned long)base[CH_L]; |
167 | if (!p) | 155 | tpu_priv.mapbase2 = (unsigned long)base[CH_H]; |
168 | return -ENOMEM; | ||
169 | 156 | ||
170 | return tpu_setup(p, pdev); | 157 | clocksource_register_hz(&tpu_priv.cs, clk_get_rate(clk) / 64); |
171 | } | ||
172 | 158 | ||
173 | static int tpu_remove(struct platform_device *pdev) | 159 | return; |
174 | { | ||
175 | return -EBUSY; | ||
176 | } | ||
177 | 160 | ||
178 | static const struct of_device_id tpu_of_table[] = { | 161 | unmap_L: |
179 | { .compatible = "renesas,tpu" }, | 162 | iounmap(base[CH_H]); |
180 | { } | 163 | free_clk: |
181 | }; | 164 | clk_put(clk); |
182 | |||
183 | static struct platform_driver tpu_driver = { | ||
184 | .probe = tpu_probe, | ||
185 | .remove = tpu_remove, | ||
186 | .driver = { | ||
187 | .name = "h8s-tpu", | ||
188 | .of_match_table = of_match_ptr(tpu_of_table), | ||
189 | } | ||
190 | }; | ||
191 | |||
192 | static int __init tpu_init(void) | ||
193 | { | ||
194 | return platform_driver_register(&tpu_driver); | ||
195 | } | ||
196 | |||
197 | static void __exit tpu_exit(void) | ||
198 | { | ||
199 | platform_driver_unregister(&tpu_driver); | ||
200 | } | 165 | } |
201 | 166 | ||
202 | subsys_initcall(tpu_init); | 167 | CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init); |
203 | module_exit(tpu_exit); | ||
204 | MODULE_AUTHOR("Yoshinori Sato"); | ||
205 | MODULE_DESCRIPTION("H8S Timer Pulse Unit Driver"); | ||
206 | MODULE_LICENSE("GPL v2"); | ||