Blame view
drivers/clocksource/timer-of.c
5.24 KB
9952f6918 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
dc11bae78 clocksource/drive... |
2 3 4 5 |
/* * Copyright (c) 2017, Linaro Ltd. All rights reserved. * * Author: Daniel Lezcano <daniel.lezcano@linaro.org> |
dc11bae78 clocksource/drive... |
6 7 8 9 10 11 12 13 14 |
*/ #include <linux/clk.h> #include <linux/interrupt.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/slab.h> #include "timer-of.h" |
cf7f46b9b clocksource/drive... |
15 16 17 18 19 20 |
/** * timer_of_irq_exit - Release the interrupt * @of_irq: an of_timer_irq structure pointer * * Free the irq resource */ |
5bbf4ad94 clocksource/drive... |
21 |
static __init void timer_of_irq_exit(struct of_timer_irq *of_irq) |
dc11bae78 clocksource/drive... |
22 23 24 25 |
{ struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); struct clock_event_device *clkevt = &to->clkevt; |
0f1a7b3fa timer-of: don't u... |
26 27 28 |
if (of_irq->percpu) free_percpu_irq(of_irq->irq, clkevt); else |
dc11bae78 clocksource/drive... |
29 30 |
free_irq(of_irq->irq, clkevt); } |
cf7f46b9b clocksource/drive... |
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
/** * timer_of_irq_init - Request the interrupt * @np: a device tree node pointer * @of_irq: an of_timer_irq structure pointer * * Get the interrupt number from the DT from its definition and * request it. The interrupt is gotten by falling back the following way: * * - Get interrupt number by name * - Get interrupt number by index * * When the interrupt is per CPU, 'request_percpu_irq()' is called, * otherwise 'request_irq()' is used. * * Returns 0 on success, < 0 otherwise */ |
5bbf4ad94 clocksource/drive... |
47 48 |
static __init int timer_of_irq_init(struct device_node *np, struct of_timer_irq *of_irq) |
dc11bae78 clocksource/drive... |
49 50 51 52 |
{ int ret; struct timer_of *to = container_of(of_irq, struct timer_of, of_irq); struct clock_event_device *clkevt = &to->clkevt; |
32f2fea6e clocksource/drive... |
53 54 55 56 57 58 59 60 61 62 63 |
if (of_irq->name) { of_irq->irq = ret = of_irq_get_byname(np, of_irq->name); if (ret < 0) { pr_err("Failed to get interrupt %s for %s ", of_irq->name, np->full_name); return ret; } } else { of_irq->irq = irq_of_parse_and_map(np, of_irq->index); } |
dc11bae78 clocksource/drive... |
64 |
if (!of_irq->irq) { |
469869d18 clocksource: Conv... |
65 66 |
pr_err("Failed to map interrupt for %pOF ", np); |
dc11bae78 clocksource/drive... |
67 68 69 70 71 72 73 74 75 76 |
return -EINVAL; } ret = of_irq->percpu ? request_percpu_irq(of_irq->irq, of_irq->handler, np->full_name, clkevt) : request_irq(of_irq->irq, of_irq->handler, of_irq->flags ? of_irq->flags : IRQF_TIMER, np->full_name, clkevt); if (ret) { |
469869d18 clocksource: Conv... |
77 78 |
pr_err("Failed to request irq %d for %pOF ", of_irq->irq, np); |
dc11bae78 clocksource/drive... |
79 80 81 82 83 84 85 |
return ret; } clkevt->irq = of_irq->irq; return 0; } |
cf7f46b9b clocksource/drive... |
86 87 88 89 90 91 |
/** * timer_of_clk_exit - Release the clock resources * @of_clk: a of_timer_clk structure pointer * * Disables and releases the refcount on the clk */ |
5bbf4ad94 clocksource/drive... |
92 |
static __init void timer_of_clk_exit(struct of_timer_clk *of_clk) |
dc11bae78 clocksource/drive... |
93 94 95 96 97 |
{ of_clk->rate = 0; clk_disable_unprepare(of_clk->clk); clk_put(of_clk->clk); } |
cf7f46b9b clocksource/drive... |
98 99 100 101 102 103 104 105 106 |
/** * timer_of_clk_init - Initialize the clock resources * @np: a device tree node pointer * @of_clk: a of_timer_clk structure pointer * * Get the clock by name or by index, enable it and get the rate * * Returns 0 on success, < 0 otherwise */ |
5bbf4ad94 clocksource/drive... |
107 108 |
static __init int timer_of_clk_init(struct device_node *np, struct of_timer_clk *of_clk) |
dc11bae78 clocksource/drive... |
109 110 111 112 113 114 |
{ int ret; of_clk->clk = of_clk->name ? of_clk_get_by_name(np, of_clk->name) : of_clk_get(np, of_clk->index); if (IS_ERR(of_clk->clk)) { |
763719771 clocksource/drive... |
115 116 117 118 119 |
ret = PTR_ERR(of_clk->clk); if (ret != -EPROBE_DEFER) pr_err("Failed to get clock for %pOF ", np); goto out; |
dc11bae78 clocksource/drive... |
120 121 122 123 |
} ret = clk_prepare_enable(of_clk->clk); if (ret) { |
469869d18 clocksource: Conv... |
124 125 |
pr_err("Failed for enable clock for %pOF ", np); |
dc11bae78 clocksource/drive... |
126 127 128 129 130 131 |
goto out_clk_put; } of_clk->rate = clk_get_rate(of_clk->clk); if (!of_clk->rate) { ret = -EINVAL; |
469869d18 clocksource: Conv... |
132 133 |
pr_err("Failed to get clock rate for %pOF ", np); |
dc11bae78 clocksource/drive... |
134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
goto out_clk_disable; } of_clk->period = DIV_ROUND_UP(of_clk->rate, HZ); out: return ret; out_clk_disable: clk_disable_unprepare(of_clk->clk); out_clk_put: clk_put(of_clk->clk); goto out; } |
5bbf4ad94 clocksource/drive... |
148 |
static __init void timer_of_base_exit(struct of_timer_base *of_base) |
dc11bae78 clocksource/drive... |
149 150 151 |
{ iounmap(of_base->base); } |
5bbf4ad94 clocksource/drive... |
152 153 |
static __init int timer_of_base_init(struct device_node *np, struct of_timer_base *of_base) |
dc11bae78 clocksource/drive... |
154 |
{ |
9aea417af clocksource/drive... |
155 156 157 |
of_base->base = of_base->name ? of_io_request_and_map(np, of_base->index, of_base->name) : of_iomap(np, of_base->index); |
9e80dbd87 clocksource/drive... |
158 |
if (IS_ERR(of_base->base)) { |
9aea417af clocksource/drive... |
159 160 |
pr_err("Failed to iomap (%s) ", of_base->name); |
9e80dbd87 clocksource/drive... |
161 |
return PTR_ERR(of_base->base); |
dc11bae78 clocksource/drive... |
162 163 164 165 166 167 168 |
} return 0; } int __init timer_of_init(struct device_node *np, struct timer_of *to) { |
b7dcc4eac clocksource/drive... |
169 |
int ret = -EINVAL; |
dc11bae78 clocksource/drive... |
170 171 172 |
int flags = 0; if (to->flags & TIMER_OF_BASE) { |
5bbf4ad94 clocksource/drive... |
173 |
ret = timer_of_base_init(np, &to->of_base); |
dc11bae78 clocksource/drive... |
174 175 176 177 178 179 |
if (ret) goto out_fail; flags |= TIMER_OF_BASE; } if (to->flags & TIMER_OF_CLOCK) { |
5bbf4ad94 clocksource/drive... |
180 |
ret = timer_of_clk_init(np, &to->of_clk); |
dc11bae78 clocksource/drive... |
181 182 183 184 185 186 |
if (ret) goto out_fail; flags |= TIMER_OF_CLOCK; } if (to->flags & TIMER_OF_IRQ) { |
5bbf4ad94 clocksource/drive... |
187 |
ret = timer_of_irq_init(np, &to->of_irq); |
dc11bae78 clocksource/drive... |
188 189 190 191 192 193 |
if (ret) goto out_fail; flags |= TIMER_OF_IRQ; } if (!to->clkevt.name) |
139ca605c clocksource/drive... |
194 |
to->clkevt.name = np->full_name; |
1c63c1c08 clocksource/drive... |
195 196 |
to->np = np; |
dc11bae78 clocksource/drive... |
197 198 199 200 |
return ret; out_fail: if (flags & TIMER_OF_IRQ) |
5bbf4ad94 clocksource/drive... |
201 |
timer_of_irq_exit(&to->of_irq); |
dc11bae78 clocksource/drive... |
202 203 |
if (flags & TIMER_OF_CLOCK) |
5bbf4ad94 clocksource/drive... |
204 |
timer_of_clk_exit(&to->of_clk); |
dc11bae78 clocksource/drive... |
205 206 |
if (flags & TIMER_OF_BASE) |
5bbf4ad94 clocksource/drive... |
207 |
timer_of_base_exit(&to->of_base); |
b7dcc4eac clocksource/drive... |
208 |
return ret; |
dc11bae78 clocksource/drive... |
209 |
} |
f48729a99 clocksource/drive... |
210 |
|
558de2824 clocksource/timer... |
211 212 213 214 215 216 217 218 |
/** * timer_of_cleanup - release timer_of ressources * @to: timer_of structure * * Release the ressources that has been used in timer_of_init(). * This function should be called in init error cases */ void __init timer_of_cleanup(struct timer_of *to) |
f48729a99 clocksource/drive... |
219 220 |
{ if (to->flags & TIMER_OF_IRQ) |
5bbf4ad94 clocksource/drive... |
221 |
timer_of_irq_exit(&to->of_irq); |
f48729a99 clocksource/drive... |
222 223 |
if (to->flags & TIMER_OF_CLOCK) |
5bbf4ad94 clocksource/drive... |
224 |
timer_of_clk_exit(&to->of_clk); |
f48729a99 clocksource/drive... |
225 226 |
if (to->flags & TIMER_OF_BASE) |
5bbf4ad94 clocksource/drive... |
227 |
timer_of_base_exit(&to->of_base); |
f48729a99 clocksource/drive... |
228 |
} |