2 * linux/arch/arm/plat-omap/dmtimer.c
4 * OMAP Dual-Mode Timers
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>
10 * dmtimer adaptation to platform_driver.
12 * Copyright (C) 2005 Nokia Corporation
13 * OMAP2 support by Juha Yrjola
14 * API improvements and OMAP2 clock framework support by Timo Teras
16 * Copyright (C) 2009 Texas Instruments
17 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
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.
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.
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.
39 #include <linux/slab.h>
40 #include <linux/err.h>
42 #include <plat/dmtimer.h>
44 static LIST_HEAD(omap_timer_list);
45 static DEFINE_SPINLOCK(dm_timer_lock);
48 * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
49 * @timer: timer pointer over which read operation to perform
50 * @reg: lowest byte holds the register offset
52 * The posted mode bit is encoded in reg. Note that in posted mode write
53 * pending bit must be checked. Otherwise a read of a non completed write
54 * will produce an error.
56 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
58 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
59 return __omap_dm_timer_read(timer, reg, timer->posted);
63 * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
64 * @timer: timer pointer over which write operation is to perform
65 * @reg: lowest byte holds the register offset
66 * @value: data to write into the register
68 * The posted mode bit is encoded in reg. Note that in posted mode the write
69 * pending bit must be checked. Otherwise a write on a register which has a
70 * pending write will be lost.
72 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
75 WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
76 __omap_dm_timer_write(timer, reg, value, timer->posted);
79 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
87 while (!(__raw_readl(timer->sys_stat) & 1)) {
90 printk(KERN_ERR "Timer failed to reset\n");
96 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
98 if (timer->pdev->id != 1) {
99 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
100 omap_dm_timer_wait_for_reset(timer);
103 __omap_dm_timer_reset(timer, 0, 0);
107 int omap_dm_timer_prepare(struct omap_dm_timer *timer)
109 struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
112 timer->fclk = clk_get(&timer->pdev->dev, "fck");
113 if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
115 dev_err(&timer->pdev->dev, ": No fclk handle.\n");
119 omap_dm_timer_enable(timer);
121 if (pdata->needs_manual_reset)
122 omap_dm_timer_reset(timer);
124 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
130 struct omap_dm_timer *omap_dm_timer_request(void)
132 struct omap_dm_timer *timer = NULL, *t;
136 spin_lock_irqsave(&dm_timer_lock, flags);
137 list_for_each_entry(t, &omap_timer_list, node) {
147 ret = omap_dm_timer_prepare(timer);
153 spin_unlock_irqrestore(&dm_timer_lock, flags);
156 pr_debug("%s: timer request failed!\n", __func__);
160 EXPORT_SYMBOL_GPL(omap_dm_timer_request);
162 struct omap_dm_timer *omap_dm_timer_request_specific(int id)
164 struct omap_dm_timer *timer = NULL, *t;
168 spin_lock_irqsave(&dm_timer_lock, flags);
169 list_for_each_entry(t, &omap_timer_list, node) {
170 if (t->pdev->id == id && !t->reserved) {
178 ret = omap_dm_timer_prepare(timer);
184 spin_unlock_irqrestore(&dm_timer_lock, flags);
187 pr_debug("%s: timer%d request failed!\n", __func__, id);
191 EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
193 void omap_dm_timer_free(struct omap_dm_timer *timer)
195 omap_dm_timer_disable(timer);
196 clk_put(timer->fclk);
198 WARN_ON(!timer->reserved);
201 EXPORT_SYMBOL_GPL(omap_dm_timer_free);
203 void omap_dm_timer_enable(struct omap_dm_timer *timer)
205 struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
210 if (!pdata->needs_manual_reset) {
211 clk_enable(timer->fclk);
212 clk_enable(timer->iclk);
217 EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
219 void omap_dm_timer_disable(struct omap_dm_timer *timer)
221 struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
226 if (!pdata->needs_manual_reset) {
227 clk_disable(timer->iclk);
228 clk_disable(timer->fclk);
233 EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
235 int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
239 EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
241 #if defined(CONFIG_ARCH_OMAP1)
244 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
245 * @inputmask: current value of idlect mask
247 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
250 struct omap_dm_timer *timer = NULL;
253 /* If ARMXOR cannot be idled this function call is unnecessary */
254 if (!(inputmask & (1 << 1)))
257 /* If any active timer is using ARMXOR return modified mask */
258 spin_lock_irqsave(&dm_timer_lock, flags);
259 list_for_each_entry(timer, &omap_timer_list, node) {
262 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
263 if (l & OMAP_TIMER_CTRL_ST) {
264 if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
265 inputmask &= ~(1 << 1);
267 inputmask &= ~(1 << 2);
271 spin_unlock_irqrestore(&dm_timer_lock, flags);
275 EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
279 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
283 EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
285 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
291 EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
295 void omap_dm_timer_trigger(struct omap_dm_timer *timer)
297 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
299 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
301 void omap_dm_timer_start(struct omap_dm_timer *timer)
305 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
306 if (!(l & OMAP_TIMER_CTRL_ST)) {
307 l |= OMAP_TIMER_CTRL_ST;
308 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
311 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
313 void omap_dm_timer_stop(struct omap_dm_timer *timer)
315 unsigned long rate = 0;
316 struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
318 if (!pdata->needs_manual_reset)
319 rate = clk_get_rate(timer->fclk);
321 __omap_dm_timer_stop(timer, timer->posted, rate);
323 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
325 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
328 struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
330 if (source < 0 || source >= 3)
333 omap_dm_timer_disable(timer);
334 ret = pdata->set_timer_src(timer->pdev, source);
335 omap_dm_timer_enable(timer);
339 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
341 void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
346 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
348 l |= OMAP_TIMER_CTRL_AR;
350 l &= ~OMAP_TIMER_CTRL_AR;
351 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
352 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
354 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
356 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
358 /* Optimized set_load which removes costly spin wait in timer_start */
359 void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
364 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
366 l |= OMAP_TIMER_CTRL_AR;
367 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
369 l &= ~OMAP_TIMER_CTRL_AR;
371 l |= OMAP_TIMER_CTRL_ST;
373 __omap_dm_timer_load_start(timer, l, load, timer->posted);
375 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
377 void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
382 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
384 l |= OMAP_TIMER_CTRL_CE;
386 l &= ~OMAP_TIMER_CTRL_CE;
387 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
388 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
390 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
392 void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
393 int toggle, int trigger)
397 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
398 l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
399 OMAP_TIMER_CTRL_PT | (0x03 << 10));
401 l |= OMAP_TIMER_CTRL_SCPWM;
403 l |= OMAP_TIMER_CTRL_PT;
405 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
407 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
409 void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
413 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
414 l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
415 if (prescaler >= 0x00 && prescaler <= 0x07) {
416 l |= OMAP_TIMER_CTRL_PRE;
419 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
421 EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
423 void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
426 __omap_dm_timer_int_enable(timer, value);
428 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
430 unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
434 l = __raw_readl(timer->irq_stat);
438 EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
440 void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
442 __omap_dm_timer_write_status(timer, value);
444 EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
446 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
448 return __omap_dm_timer_read_counter(timer, timer->posted);
450 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
452 void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
454 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
456 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
458 int omap_dm_timers_active(void)
460 struct omap_dm_timer *timer;
462 list_for_each_entry(timer, &omap_timer_list, node) {
466 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
467 OMAP_TIMER_CTRL_ST) {
473 EXPORT_SYMBOL_GPL(omap_dm_timers_active);
476 * omap_dm_timer_probe - probe function called for every registered device
477 * @pdev: pointer to current timer platform device
479 * Called by driver framework at the end of device registration for all
482 static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
486 struct omap_dm_timer *timer;
487 struct resource *mem, *irq, *ioarea;
488 struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
491 dev_err(&pdev->dev, "%s: no platform data.\n", __func__);
495 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
496 if (unlikely(!irq)) {
497 dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__);
501 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
502 if (unlikely(!mem)) {
503 dev_err(&pdev->dev, "%s: no memory resource.\n", __func__);
507 ioarea = request_mem_region(mem->start, resource_size(mem),
510 dev_err(&pdev->dev, "%s: region already claimed.\n", __func__);
514 timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL);
516 dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n",
519 goto err_free_ioregion;
522 timer->io_base = ioremap(mem->start, resource_size(mem));
523 if (!timer->io_base) {
524 dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__);
529 timer->id = pdev->id;
530 timer->irq = irq->start;
533 /* add the timer element to the list */
534 spin_lock_irqsave(&dm_timer_lock, flags);
535 list_add_tail(&timer->node, &omap_timer_list);
536 spin_unlock_irqrestore(&dm_timer_lock, flags);
538 dev_dbg(&pdev->dev, "Device Probed.\n");
546 release_mem_region(mem->start, resource_size(mem));
552 * omap_dm_timer_remove - cleanup a registered timer device
553 * @pdev: pointer to current timer platform device
555 * Called by driver framework whenever a timer device is unregistered.
556 * In addition to freeing platform resources it also deletes the timer
557 * entry from the local list.
559 static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
561 struct omap_dm_timer *timer;
565 spin_lock_irqsave(&dm_timer_lock, flags);
566 list_for_each_entry(timer, &omap_timer_list, node)
567 if (timer->pdev->id == pdev->id) {
568 list_del(&timer->node);
573 spin_unlock_irqrestore(&dm_timer_lock, flags);
578 static struct platform_driver omap_dm_timer_driver = {
579 .probe = omap_dm_timer_probe,
580 .remove = omap_dm_timer_remove,
582 .name = "omap_timer",
586 static int __init omap_dm_timer_driver_init(void)
588 return platform_driver_register(&omap_dm_timer_driver);
591 static void __exit omap_dm_timer_driver_exit(void)
593 platform_driver_unregister(&omap_dm_timer_driver);
596 early_platform_init("earlytimer", &omap_dm_timer_driver);
597 module_init(omap_dm_timer_driver_init);
598 module_exit(omap_dm_timer_driver_exit);
600 MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
601 MODULE_LICENSE("GPL");
602 MODULE_ALIAS("platform:" DRIVER_NAME);
603 MODULE_AUTHOR("Texas Instruments Inc");