diff options
author | Jon Hunter <jon-hunter@ti.com> | 2013-03-19 13:38:17 -0400 |
---|---|---|
committer | Benoit Cousson <benoit.cousson@linaro.org> | 2013-04-08 18:21:31 -0400 |
commit | 8fc7fcb593ac3c5730c8391c2d7db5b87e2d0bf2 (patch) | |
tree | 4863953406205f2ee04499d01b8561a72537cd6b /arch | |
parent | 385c4c7b7c2f6829048d8b041b31f9da10a8202e (diff) |
ARM: OMAP: Add function to request timer by node
Add a function so that OMAP dmtimers can be requested by device-tree
node. This allows for devices, such as the internal DSP, or drivers,
such as PWM, to reference a specific dmtimer node via the device-tree.
Given that there are several APIs available for requesting dmtimers
(by ID, by capability or by node) consolidate the code for all these
functions into a single helper function that can be used by these
request functions.
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Benoit Cousson <benoit.cousson@linaro.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 167 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/dmtimer.h | 1 |
2 files changed, 94 insertions, 74 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 725d9720dd2b..05efb370a2bd 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c | |||
@@ -52,6 +52,13 @@ static u32 omap_reserved_systimers; | |||
52 | static LIST_HEAD(omap_timer_list); | 52 | static LIST_HEAD(omap_timer_list); |
53 | static DEFINE_SPINLOCK(dm_timer_lock); | 53 | static DEFINE_SPINLOCK(dm_timer_lock); |
54 | 54 | ||
55 | enum { | ||
56 | REQUEST_ANY = 0, | ||
57 | REQUEST_BY_ID, | ||
58 | REQUEST_BY_CAP, | ||
59 | REQUEST_BY_NODE, | ||
60 | }; | ||
61 | |||
55 | /** | 62 | /** |
56 | * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode | 63 | * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode |
57 | * @timer: timer pointer over which read operation to perform | 64 | * @timer: timer pointer over which read operation to perform |
@@ -178,29 +185,82 @@ int omap_dm_timer_reserve_systimer(int id) | |||
178 | return 0; | 185 | return 0; |
179 | } | 186 | } |
180 | 187 | ||
181 | struct omap_dm_timer *omap_dm_timer_request(void) | 188 | static struct omap_dm_timer *_omap_dm_timer_request(int req_type, void *data) |
182 | { | 189 | { |
183 | struct omap_dm_timer *timer = NULL, *t; | 190 | struct omap_dm_timer *timer = NULL, *t; |
191 | struct device_node *np = NULL; | ||
184 | unsigned long flags; | 192 | unsigned long flags; |
185 | int ret = 0; | 193 | u32 cap = 0; |
194 | int id = 0; | ||
195 | |||
196 | switch (req_type) { | ||
197 | case REQUEST_BY_ID: | ||
198 | id = *(int *)data; | ||
199 | break; | ||
200 | case REQUEST_BY_CAP: | ||
201 | cap = *(u32 *)data; | ||
202 | break; | ||
203 | case REQUEST_BY_NODE: | ||
204 | np = (struct device_node *)data; | ||
205 | break; | ||
206 | default: | ||
207 | /* REQUEST_ANY */ | ||
208 | break; | ||
209 | } | ||
186 | 210 | ||
187 | spin_lock_irqsave(&dm_timer_lock, flags); | 211 | spin_lock_irqsave(&dm_timer_lock, flags); |
188 | list_for_each_entry(t, &omap_timer_list, node) { | 212 | list_for_each_entry(t, &omap_timer_list, node) { |
189 | if (t->reserved) | 213 | if (t->reserved) |
190 | continue; | 214 | continue; |
191 | 215 | ||
192 | timer = t; | 216 | switch (req_type) { |
193 | timer->reserved = 1; | 217 | case REQUEST_BY_ID: |
194 | break; | 218 | if (id == t->pdev->id) { |
219 | timer = t; | ||
220 | timer->reserved = 1; | ||
221 | goto found; | ||
222 | } | ||
223 | break; | ||
224 | case REQUEST_BY_CAP: | ||
225 | if (cap == (t->capability & cap)) { | ||
226 | /* | ||
227 | * If timer is not NULL, we have already found | ||
228 | * one timer but it was not an exact match | ||
229 | * because it had more capabilites that what | ||
230 | * was required. Therefore, unreserve the last | ||
231 | * timer found and see if this one is a better | ||
232 | * match. | ||
233 | */ | ||
234 | if (timer) | ||
235 | timer->reserved = 0; | ||
236 | timer = t; | ||
237 | timer->reserved = 1; | ||
238 | |||
239 | /* Exit loop early if we find an exact match */ | ||
240 | if (t->capability == cap) | ||
241 | goto found; | ||
242 | } | ||
243 | break; | ||
244 | case REQUEST_BY_NODE: | ||
245 | if (np == t->pdev->dev.of_node) { | ||
246 | timer = t; | ||
247 | timer->reserved = 1; | ||
248 | goto found; | ||
249 | } | ||
250 | break; | ||
251 | default: | ||
252 | /* REQUEST_ANY */ | ||
253 | timer = t; | ||
254 | timer->reserved = 1; | ||
255 | goto found; | ||
256 | } | ||
195 | } | 257 | } |
258 | found: | ||
196 | spin_unlock_irqrestore(&dm_timer_lock, flags); | 259 | spin_unlock_irqrestore(&dm_timer_lock, flags); |
197 | 260 | ||
198 | if (timer) { | 261 | if (timer && omap_dm_timer_prepare(timer)) { |
199 | ret = omap_dm_timer_prepare(timer); | 262 | timer->reserved = 0; |
200 | if (ret) { | 263 | timer = NULL; |
201 | timer->reserved = 0; | ||
202 | timer = NULL; | ||
203 | } | ||
204 | } | 264 | } |
205 | 265 | ||
206 | if (!timer) | 266 | if (!timer) |
@@ -208,43 +268,23 @@ struct omap_dm_timer *omap_dm_timer_request(void) | |||
208 | 268 | ||
209 | return timer; | 269 | return timer; |
210 | } | 270 | } |
271 | |||
272 | struct omap_dm_timer *omap_dm_timer_request(void) | ||
273 | { | ||
274 | return _omap_dm_timer_request(REQUEST_ANY, NULL); | ||
275 | } | ||
211 | EXPORT_SYMBOL_GPL(omap_dm_timer_request); | 276 | EXPORT_SYMBOL_GPL(omap_dm_timer_request); |
212 | 277 | ||
213 | struct omap_dm_timer *omap_dm_timer_request_specific(int id) | 278 | struct omap_dm_timer *omap_dm_timer_request_specific(int id) |
214 | { | 279 | { |
215 | struct omap_dm_timer *timer = NULL, *t; | ||
216 | unsigned long flags; | ||
217 | int ret = 0; | ||
218 | |||
219 | /* Requesting timer by ID is not supported when device tree is used */ | 280 | /* Requesting timer by ID is not supported when device tree is used */ |
220 | if (of_have_populated_dt()) { | 281 | if (of_have_populated_dt()) { |
221 | pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n", | 282 | pr_warn("%s: Please use omap_dm_timer_request_by_cap/node()\n", |
222 | __func__); | 283 | __func__); |
223 | return NULL; | 284 | return NULL; |
224 | } | 285 | } |
225 | 286 | ||
226 | spin_lock_irqsave(&dm_timer_lock, flags); | 287 | return _omap_dm_timer_request(REQUEST_BY_ID, &id); |
227 | list_for_each_entry(t, &omap_timer_list, node) { | ||
228 | if (t->pdev->id == id && !t->reserved) { | ||
229 | timer = t; | ||
230 | timer->reserved = 1; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
235 | |||
236 | if (timer) { | ||
237 | ret = omap_dm_timer_prepare(timer); | ||
238 | if (ret) { | ||
239 | timer->reserved = 0; | ||
240 | timer = NULL; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | if (!timer) | ||
245 | pr_debug("%s: timer%d request failed!\n", __func__, id); | ||
246 | |||
247 | return timer; | ||
248 | } | 288 | } |
249 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); | 289 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); |
250 | 290 | ||
@@ -259,46 +299,25 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); | |||
259 | */ | 299 | */ |
260 | struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap) | 300 | struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap) |
261 | { | 301 | { |
262 | struct omap_dm_timer *timer = NULL, *t; | 302 | return _omap_dm_timer_request(REQUEST_BY_CAP, &cap); |
263 | unsigned long flags; | 303 | } |
304 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap); | ||
264 | 305 | ||
265 | if (!cap) | 306 | /** |
307 | * omap_dm_timer_request_by_node - Request a timer by device-tree node | ||
308 | * @np: Pointer to device-tree timer node | ||
309 | * | ||
310 | * Request a timer based upon a device node pointer. Returns pointer to | ||
311 | * timer handle on success and a NULL pointer on failure. | ||
312 | */ | ||
313 | struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np) | ||
314 | { | ||
315 | if (!np) | ||
266 | return NULL; | 316 | return NULL; |
267 | 317 | ||
268 | spin_lock_irqsave(&dm_timer_lock, flags); | 318 | return _omap_dm_timer_request(REQUEST_BY_NODE, np); |
269 | list_for_each_entry(t, &omap_timer_list, node) { | ||
270 | if ((!t->reserved) && ((t->capability & cap) == cap)) { | ||
271 | /* | ||
272 | * If timer is not NULL, we have already found one timer | ||
273 | * but it was not an exact match because it had more | ||
274 | * capabilites that what was required. Therefore, | ||
275 | * unreserve the last timer found and see if this one | ||
276 | * is a better match. | ||
277 | */ | ||
278 | if (timer) | ||
279 | timer->reserved = 0; | ||
280 | |||
281 | timer = t; | ||
282 | timer->reserved = 1; | ||
283 | |||
284 | /* Exit loop early if we find an exact match */ | ||
285 | if (t->capability == cap) | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | spin_unlock_irqrestore(&dm_timer_lock, flags); | ||
290 | |||
291 | if (timer && omap_dm_timer_prepare(timer)) { | ||
292 | timer->reserved = 0; | ||
293 | timer = NULL; | ||
294 | } | ||
295 | |||
296 | if (!timer) | ||
297 | pr_debug("%s: timer request failed!\n", __func__); | ||
298 | |||
299 | return timer; | ||
300 | } | 319 | } |
301 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap); | 320 | EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_node); |
302 | 321 | ||
303 | int omap_dm_timer_free(struct omap_dm_timer *timer) | 322 | int omap_dm_timer_free(struct omap_dm_timer *timer) |
304 | { | 323 | { |
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index a3fbc48c332e..fb92abb91628 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h | |||
@@ -128,6 +128,7 @@ int omap_dm_timer_reserve_systimer(int id); | |||
128 | struct omap_dm_timer *omap_dm_timer_request(void); | 128 | struct omap_dm_timer *omap_dm_timer_request(void); |
129 | struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); | 129 | struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); |
130 | struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap); | 130 | struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap); |
131 | struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np); | ||
131 | int omap_dm_timer_free(struct omap_dm_timer *timer); | 132 | int omap_dm_timer_free(struct omap_dm_timer *timer); |
132 | void omap_dm_timer_enable(struct omap_dm_timer *timer); | 133 | void omap_dm_timer_enable(struct omap_dm_timer *timer); |
133 | void omap_dm_timer_disable(struct omap_dm_timer *timer); | 134 | void omap_dm_timer_disable(struct omap_dm_timer *timer); |