diff options
Diffstat (limited to 'drivers/clocksource/h8300_timer16.c')
-rw-r--r-- | drivers/clocksource/h8300_timer16.c | 141 |
1 files changed, 54 insertions, 87 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"); | ||