~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/plat-omap/dmtimer.c

Version: ~ [ linux-5.4-rc7 ] ~ [ linux-5.3.10 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.83 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.153 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.200 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.200 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.76 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/arch/arm/plat-omap/dmtimer.c
  3  *
  4  * OMAP Dual-Mode Timers
  5  *
  6  * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
  7  * Tarun Kanti DebBarma <tarun.kanti@ti.com>
  8  * Thara Gopinath <thara@ti.com>
  9  *
 10  * dmtimer adaptation to platform_driver.
 11  *
 12  * Copyright (C) 2005 Nokia Corporation
 13  * OMAP2 support by Juha Yrjola
 14  * API improvements and OMAP2 clock framework support by Timo Teras
 15  *
 16  * Copyright (C) 2009 Texas Instruments
 17  * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
 18  *
 19  * This program is free software; you can redistribute it and/or modify it
 20  * under the terms of the GNU General Public License as published by the
 21  * Free Software Foundation; either version 2 of the License, or (at your
 22  * option) any later version.
 23  *
 24  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 25  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 27  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 29  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 32  *
 33  * You should have received a copy of the  GNU General Public License along
 34  * with this program; if not, write  to the Free Software Foundation, Inc.,
 35  * 675 Mass Ave, Cambridge, MA 02139, USA.
 36  */
 37 
 38 #include <linux/module.h>
 39 #include <linux/io.h>
 40 #include <linux/device.h>
 41 #include <linux/err.h>
 42 #include <linux/pm_runtime.h>
 43 
 44 #include <plat/dmtimer.h>
 45 #include <plat/omap-pm.h>
 46 
 47 #include <mach/hardware.h>
 48 
 49 static u32 omap_reserved_systimers;
 50 static LIST_HEAD(omap_timer_list);
 51 static DEFINE_SPINLOCK(dm_timer_lock);
 52 
 53 /**
 54  * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
 55  * @timer:      timer pointer over which read operation to perform
 56  * @reg:        lowest byte holds the register offset
 57  *
 58  * The posted mode bit is encoded in reg. Note that in posted mode write
 59  * pending bit must be checked. Otherwise a read of a non completed write
 60  * will produce an error.
 61  */
 62 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 63 {
 64         WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
 65         return __omap_dm_timer_read(timer, reg, timer->posted);
 66 }
 67 
 68 /**
 69  * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
 70  * @timer:      timer pointer over which write operation is to perform
 71  * @reg:        lowest byte holds the register offset
 72  * @value:      data to write into the register
 73  *
 74  * The posted mode bit is encoded in reg. Note that in posted mode the write
 75  * pending bit must be checked. Otherwise a write on a register which has a
 76  * pending write will be lost.
 77  */
 78 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 79                                                 u32 value)
 80 {
 81         WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
 82         __omap_dm_timer_write(timer, reg, value, timer->posted);
 83 }
 84 
 85 static void omap_timer_restore_context(struct omap_dm_timer *timer)
 86 {
 87         if (timer->revision == 1)
 88                 __raw_writel(timer->context.tistat, timer->sys_stat);
 89 
 90         __raw_writel(timer->context.tisr, timer->irq_stat);
 91         omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
 92                                 timer->context.twer);
 93         omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
 94                                 timer->context.tcrr);
 95         omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
 96                                 timer->context.tldr);
 97         omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
 98                                 timer->context.tmar);
 99         omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
100                                 timer->context.tsicr);
101         __raw_writel(timer->context.tier, timer->irq_ena);
102         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
103                                 timer->context.tclr);
104 }
105 
106 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
107 {
108         int c;
109 
110         if (!timer->sys_stat)
111                 return;
112 
113         c = 0;
114         while (!(__raw_readl(timer->sys_stat) & 1)) {
115                 c++;
116                 if (c > 100000) {
117                         printk(KERN_ERR "Timer failed to reset\n");
118                         return;
119                 }
120         }
121 }
122 
123 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
124 {
125         omap_dm_timer_enable(timer);
126         if (timer->pdev->id != 1) {
127                 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
128                 omap_dm_timer_wait_for_reset(timer);
129         }
130 
131         __omap_dm_timer_reset(timer, 0, 0);
132         omap_dm_timer_disable(timer);
133         timer->posted = 1;
134 }
135 
136 int omap_dm_timer_prepare(struct omap_dm_timer *timer)
137 {
138         int ret;
139 
140         /*
141          * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
142          * do not call clk_get() for these devices.
143          */
144         if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
145                 timer->fclk = clk_get(&timer->pdev->dev, "fck");
146                 if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
147                         timer->fclk = NULL;
148                         dev_err(&timer->pdev->dev, ": No fclk handle.\n");
149                         return -EINVAL;
150                 }
151         }
152 
153         if (timer->capability & OMAP_TIMER_NEEDS_RESET)
154                 omap_dm_timer_reset(timer);
155 
156         ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
157 
158         timer->posted = 1;
159         return ret;
160 }
161 
162 static inline u32 omap_dm_timer_reserved_systimer(int id)
163 {
164         return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
165 }
166 
167 int omap_dm_timer_reserve_systimer(int id)
168 {
169         if (omap_dm_timer_reserved_systimer(id))
170                 return -ENODEV;
171 
172         omap_reserved_systimers |= (1 << (id - 1));
173 
174         return 0;
175 }
176 
177 struct omap_dm_timer *omap_dm_timer_request(void)
178 {
179         struct omap_dm_timer *timer = NULL, *t;
180         unsigned long flags;
181         int ret = 0;
182 
183         spin_lock_irqsave(&dm_timer_lock, flags);
184         list_for_each_entry(t, &omap_timer_list, node) {
185                 if (t->reserved)
186                         continue;
187 
188                 timer = t;
189                 timer->reserved = 1;
190                 break;
191         }
192         spin_unlock_irqrestore(&dm_timer_lock, flags);
193 
194         if (timer) {
195                 ret = omap_dm_timer_prepare(timer);
196                 if (ret) {
197                         timer->reserved = 0;
198                         timer = NULL;
199                 }
200         }
201 
202         if (!timer)
203                 pr_debug("%s: timer request failed!\n", __func__);
204 
205         return timer;
206 }
207 EXPORT_SYMBOL_GPL(omap_dm_timer_request);
208 
209 struct omap_dm_timer *omap_dm_timer_request_specific(int id)
210 {
211         struct omap_dm_timer *timer = NULL, *t;
212         unsigned long flags;
213         int ret = 0;
214 
215         spin_lock_irqsave(&dm_timer_lock, flags);
216         list_for_each_entry(t, &omap_timer_list, node) {
217                 if (t->pdev->id == id && !t->reserved) {
218                         timer = t;
219                         timer->reserved = 1;
220                         break;
221                 }
222         }
223         spin_unlock_irqrestore(&dm_timer_lock, flags);
224 
225         if (timer) {
226                 ret = omap_dm_timer_prepare(timer);
227                 if (ret) {
228                         timer->reserved = 0;
229                         timer = NULL;
230                 }
231         }
232 
233         if (!timer)
234                 pr_debug("%s: timer%d request failed!\n", __func__, id);
235 
236         return timer;
237 }
238 EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
239 
240 int omap_dm_timer_free(struct omap_dm_timer *timer)
241 {
242         if (unlikely(!timer))
243                 return -EINVAL;
244 
245         clk_put(timer->fclk);
246 
247         WARN_ON(!timer->reserved);
248         timer->reserved = 0;
249         return 0;
250 }
251 EXPORT_SYMBOL_GPL(omap_dm_timer_free);
252 
253 void omap_dm_timer_enable(struct omap_dm_timer *timer)
254 {
255         pm_runtime_get_sync(&timer->pdev->dev);
256 }
257 EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
258 
259 void omap_dm_timer_disable(struct omap_dm_timer *timer)
260 {
261         pm_runtime_put_sync(&timer->pdev->dev);
262 }
263 EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
264 
265 int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
266 {
267         if (timer)
268                 return timer->irq;
269         return -EINVAL;
270 }
271 EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
272 
273 #if defined(CONFIG_ARCH_OMAP1)
274 
275 /**
276  * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
277  * @inputmask: current value of idlect mask
278  */
279 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
280 {
281         int i = 0;
282         struct omap_dm_timer *timer = NULL;
283         unsigned long flags;
284 
285         /* If ARMXOR cannot be idled this function call is unnecessary */
286         if (!(inputmask & (1 << 1)))
287                 return inputmask;
288 
289         /* If any active timer is using ARMXOR return modified mask */
290         spin_lock_irqsave(&dm_timer_lock, flags);
291         list_for_each_entry(timer, &omap_timer_list, node) {
292                 u32 l;
293 
294                 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
295                 if (l & OMAP_TIMER_CTRL_ST) {
296                         if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
297                                 inputmask &= ~(1 << 1);
298                         else
299                                 inputmask &= ~(1 << 2);
300                 }
301                 i++;
302         }
303         spin_unlock_irqrestore(&dm_timer_lock, flags);
304 
305         return inputmask;
306 }
307 EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
308 
309 #else
310 
311 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
312 {
313         if (timer)
314                 return timer->fclk;
315         return NULL;
316 }
317 EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
318 
319 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
320 {
321         BUG();
322 
323         return 0;
324 }
325 EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
326 
327 #endif
328 
329 int omap_dm_timer_trigger(struct omap_dm_timer *timer)
330 {
331         if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
332                 pr_err("%s: timer not available or enabled.\n", __func__);
333                 return -EINVAL;
334         }
335 
336         omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
337         return 0;
338 }
339 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
340 
341 int omap_dm_timer_start(struct omap_dm_timer *timer)
342 {
343         u32 l;
344 
345         if (unlikely(!timer))
346                 return -EINVAL;
347 
348         omap_dm_timer_enable(timer);
349 
350         if (!(timer->capability & OMAP_TIMER_ALWON)) {
351                 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
352                                 timer->ctx_loss_count)
353                         omap_timer_restore_context(timer);
354         }
355 
356         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
357         if (!(l & OMAP_TIMER_CTRL_ST)) {
358                 l |= OMAP_TIMER_CTRL_ST;
359                 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
360         }
361 
362         /* Save the context */
363         timer->context.tclr = l;
364         return 0;
365 }
366 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
367 
368 int omap_dm_timer_stop(struct omap_dm_timer *timer)
369 {
370         unsigned long rate = 0;
371 
372         if (unlikely(!timer))
373                 return -EINVAL;
374 
375         if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
376                 rate = clk_get_rate(timer->fclk);
377 
378         __omap_dm_timer_stop(timer, timer->posted, rate);
379 
380         if (!(timer->capability & OMAP_TIMER_ALWON))
381                 timer->ctx_loss_count =
382                         omap_pm_get_dev_context_loss_count(&timer->pdev->dev);
383 
384         /*
385          * Since the register values are computed and written within
386          * __omap_dm_timer_stop, we need to use read to retrieve the
387          * context.
388          */
389         timer->context.tclr =
390                         omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
391         timer->context.tisr = __raw_readl(timer->irq_stat);
392         omap_dm_timer_disable(timer);
393         return 0;
394 }
395 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
396 
397 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
398 {
399         int ret;
400         char *parent_name = NULL;
401         struct clk *fclk, *parent;
402         struct dmtimer_platform_data *pdata;
403 
404         if (unlikely(!timer))
405                 return -EINVAL;
406 
407         pdata = timer->pdev->dev.platform_data;
408 
409         if (source < 0 || source >= 3)
410                 return -EINVAL;
411 
412         /*
413          * FIXME: Used for OMAP1 devices only because they do not currently
414          * use the clock framework to set the parent clock. To be removed
415          * once OMAP1 migrated to using clock framework for dmtimers
416          */
417         if (pdata->set_timer_src)
418                 return pdata->set_timer_src(timer->pdev, source);
419 
420         fclk = clk_get(&timer->pdev->dev, "fck");
421         if (IS_ERR_OR_NULL(fclk)) {
422                 pr_err("%s: fck not found\n", __func__);
423                 return -EINVAL;
424         }
425 
426         switch (source) {
427         case OMAP_TIMER_SRC_SYS_CLK:
428                 parent_name = "timer_sys_ck";
429                 break;
430 
431         case OMAP_TIMER_SRC_32_KHZ:
432                 parent_name = "timer_32k_ck";
433                 break;
434 
435         case OMAP_TIMER_SRC_EXT_CLK:
436                 parent_name = "timer_ext_ck";
437                 break;
438         }
439 
440         parent = clk_get(&timer->pdev->dev, parent_name);
441         if (IS_ERR_OR_NULL(parent)) {
442                 pr_err("%s: %s not found\n", __func__, parent_name);
443                 ret = -EINVAL;
444                 goto out;
445         }
446 
447         ret = clk_set_parent(fclk, parent);
448         if (IS_ERR_VALUE(ret))
449                 pr_err("%s: failed to set %s as parent\n", __func__,
450                         parent_name);
451 
452         clk_put(parent);
453 out:
454         clk_put(fclk);
455 
456         return ret;
457 }
458 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
459 
460 int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
461                             unsigned int load)
462 {
463         u32 l;
464 
465         if (unlikely(!timer))
466                 return -EINVAL;
467 
468         omap_dm_timer_enable(timer);
469         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
470         if (autoreload)
471                 l |= OMAP_TIMER_CTRL_AR;
472         else
473                 l &= ~OMAP_TIMER_CTRL_AR;
474         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
475         omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
476 
477         omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
478         /* Save the context */
479         timer->context.tclr = l;
480         timer->context.tldr = load;
481         omap_dm_timer_disable(timer);
482         return 0;
483 }
484 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
485 
486 /* Optimized set_load which removes costly spin wait in timer_start */
487 int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
488                             unsigned int load)
489 {
490         u32 l;
491 
492         if (unlikely(!timer))
493                 return -EINVAL;
494 
495         omap_dm_timer_enable(timer);
496 
497         if (!(timer->capability & OMAP_TIMER_ALWON)) {
498                 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) !=
499                                 timer->ctx_loss_count)
500                         omap_timer_restore_context(timer);
501         }
502 
503         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
504         if (autoreload) {
505                 l |= OMAP_TIMER_CTRL_AR;
506                 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
507         } else {
508                 l &= ~OMAP_TIMER_CTRL_AR;
509         }
510         l |= OMAP_TIMER_CTRL_ST;
511 
512         __omap_dm_timer_load_start(timer, l, load, timer->posted);
513 
514         /* Save the context */
515         timer->context.tclr = l;
516         timer->context.tldr = load;
517         timer->context.tcrr = load;
518         return 0;
519 }
520 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
521 
522 int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
523                              unsigned int match)
524 {
525         u32 l;
526 
527         if (unlikely(!timer))
528                 return -EINVAL;
529 
530         omap_dm_timer_enable(timer);
531         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
532         if (enable)
533                 l |= OMAP_TIMER_CTRL_CE;
534         else
535                 l &= ~OMAP_TIMER_CTRL_CE;
536         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
537         omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
538 
539         /* Save the context */
540         timer->context.tclr = l;
541         timer->context.tmar = match;
542         omap_dm_timer_disable(timer);
543         return 0;
544 }
545 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
546 
547 int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
548                            int toggle, int trigger)
549 {
550         u32 l;
551 
552         if (unlikely(!timer))
553                 return -EINVAL;
554 
555         omap_dm_timer_enable(timer);
556         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
557         l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
558                OMAP_TIMER_CTRL_PT | (0x03 << 10));
559         if (def_on)
560                 l |= OMAP_TIMER_CTRL_SCPWM;
561         if (toggle)
562                 l |= OMAP_TIMER_CTRL_PT;
563         l |= trigger << 10;
564         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
565 
566         /* Save the context */
567         timer->context.tclr = l;
568         omap_dm_timer_disable(timer);
569         return 0;
570 }
571 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
572 
573 int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
574 {
575         u32 l;
576 
577         if (unlikely(!timer))
578                 return -EINVAL;
579 
580         omap_dm_timer_enable(timer);
581         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
582         l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
583         if (prescaler >= 0x00 && prescaler <= 0x07) {
584                 l |= OMAP_TIMER_CTRL_PRE;
585                 l |= prescaler << 2;
586         }
587         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
588 
589         /* Save the context */
590         timer->context.tclr = l;
591         omap_dm_timer_disable(timer);
592         return 0;
593 }
594 EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
595 
596 int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
597                                   unsigned int value)
598 {
599         if (unlikely(!timer))
600                 return -EINVAL;
601 
602         omap_dm_timer_enable(timer);
603         __omap_dm_timer_int_enable(timer, value);
604 
605         /* Save the context */
606         timer->context.tier = value;
607         timer->context.twer = value;
608         omap_dm_timer_disable(timer);
609         return 0;
610 }
611 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
612 
613 unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
614 {
615         unsigned int l;
616 
617         if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
618                 pr_err("%s: timer not available or enabled.\n", __func__);
619                 return 0;
620         }
621 
622         l = __raw_readl(timer->irq_stat);
623 
624         return l;
625 }
626 EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
627 
628 int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
629 {
630         if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
631                 return -EINVAL;
632 
633         __omap_dm_timer_write_status(timer, value);
634         /* Save the context */
635         timer->context.tisr = value;
636         return 0;
637 }
638 EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
639 
640 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
641 {
642         if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
643                 pr_err("%s: timer not iavailable or enabled.\n", __func__);
644                 return 0;
645         }
646 
647         return __omap_dm_timer_read_counter(timer, timer->posted);
648 }
649 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
650 
651 int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
652 {
653         if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
654                 pr_err("%s: timer not available or enabled.\n", __func__);
655                 return -EINVAL;
656         }
657 
658         omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
659 
660         /* Save the context */
661         timer->context.tcrr = value;
662         return 0;
663 }
664 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
665 
666 int omap_dm_timers_active(void)
667 {
668         struct omap_dm_timer *timer;
669 
670         list_for_each_entry(timer, &omap_timer_list, node) {
671                 if (!timer->reserved)
672                         continue;
673 
674                 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
675                     OMAP_TIMER_CTRL_ST) {
676                         return 1;
677                 }
678         }
679         return 0;
680 }
681 EXPORT_SYMBOL_GPL(omap_dm_timers_active);
682 
683 /**
684  * omap_dm_timer_probe - probe function called for every registered device
685  * @pdev:       pointer to current timer platform device
686  *
687  * Called by driver framework at the end of device registration for all
688  * timer devices.
689  */
690 static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
691 {
692         unsigned long flags;
693         struct omap_dm_timer *timer;
694         struct resource *mem, *irq;
695         struct device *dev = &pdev->dev;
696         struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
697 
698         if (!pdata) {
699                 dev_err(dev, "%s: no platform data.\n", __func__);
700                 return -ENODEV;
701         }
702 
703         irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
704         if (unlikely(!irq)) {
705                 dev_err(dev, "%s: no IRQ resource.\n", __func__);
706                 return -ENODEV;
707         }
708 
709         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
710         if (unlikely(!mem)) {
711                 dev_err(dev, "%s: no memory resource.\n", __func__);
712                 return -ENODEV;
713         }
714 
715         timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
716         if (!timer) {
717                 dev_err(dev, "%s: memory alloc failed!\n", __func__);
718                 return  -ENOMEM;
719         }
720 
721         timer->io_base = devm_request_and_ioremap(dev, mem);
722         if (!timer->io_base) {
723                 dev_err(dev, "%s: region already claimed.\n", __func__);
724                 return -ENOMEM;
725         }
726 
727         timer->id = pdev->id;
728         timer->irq = irq->start;
729         timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
730         timer->pdev = pdev;
731         timer->capability = pdata->timer_capability;
732 
733         /* Skip pm_runtime_enable for OMAP1 */
734         if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
735                 pm_runtime_enable(dev);
736                 pm_runtime_irq_safe(dev);
737         }
738 
739         if (!timer->reserved) {
740                 pm_runtime_get_sync(dev);
741                 __omap_dm_timer_init_regs(timer);
742                 pm_runtime_put(dev);
743         }
744 
745         /* add the timer element to the list */
746         spin_lock_irqsave(&dm_timer_lock, flags);
747         list_add_tail(&timer->node, &omap_timer_list);
748         spin_unlock_irqrestore(&dm_timer_lock, flags);
749 
750         dev_dbg(dev, "Device Probed.\n");
751 
752         return 0;
753 }
754 
755 /**
756  * omap_dm_timer_remove - cleanup a registered timer device
757  * @pdev:       pointer to current timer platform device
758  *
759  * Called by driver framework whenever a timer device is unregistered.
760  * In addition to freeing platform resources it also deletes the timer
761  * entry from the local list.
762  */
763 static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
764 {
765         struct omap_dm_timer *timer;
766         unsigned long flags;
767         int ret = -EINVAL;
768 
769         spin_lock_irqsave(&dm_timer_lock, flags);
770         list_for_each_entry(timer, &omap_timer_list, node)
771                 if (timer->pdev->id == pdev->id) {
772                         list_del(&timer->node);
773                         ret = 0;
774                         break;
775                 }
776         spin_unlock_irqrestore(&dm_timer_lock, flags);
777 
778         return ret;
779 }
780 
781 static struct platform_driver omap_dm_timer_driver = {
782         .probe  = omap_dm_timer_probe,
783         .remove = __devexit_p(omap_dm_timer_remove),
784         .driver = {
785                 .name   = "omap_timer",
786         },
787 };
788 
789 static int __init omap_dm_timer_driver_init(void)
790 {
791         return platform_driver_register(&omap_dm_timer_driver);
792 }
793 
794 static void __exit omap_dm_timer_driver_exit(void)
795 {
796         platform_driver_unregister(&omap_dm_timer_driver);
797 }
798 
799 early_platform_init("earlytimer", &omap_dm_timer_driver);
800 module_init(omap_dm_timer_driver_init);
801 module_exit(omap_dm_timer_driver_exit);
802 
803 MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
804 MODULE_LICENSE("GPL");
805 MODULE_ALIAS("platform:" DRIVER_NAME);
806 MODULE_AUTHOR("Texas Instruments Inc");
807 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp