Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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/slab.h>
 41#include <linux/err.h>
 42#include <linux/pm_runtime.h>
 43
 44#include <plat/dmtimer.h>
 45
 46#include <mach/hardware.h>
 47
 48static LIST_HEAD(omap_timer_list);
 49static DEFINE_SPINLOCK(dm_timer_lock);
 50
 51/**
 52 * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
 53 * @timer:      timer pointer over which read operation to perform
 54 * @reg:        lowest byte holds the register offset
 55 *
 56 * The posted mode bit is encoded in reg. Note that in posted mode write
 57 * pending bit must be checked. Otherwise a read of a non completed write
 58 * will produce an error.
 59 */
 60static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
 61{
 62	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
 63	return __omap_dm_timer_read(timer, reg, timer->posted);
 64}
 65
 66/**
 67 * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
 68 * @timer:      timer pointer over which write operation is to perform
 69 * @reg:        lowest byte holds the register offset
 70 * @value:      data to write into the register
 71 *
 72 * The posted mode bit is encoded in reg. Note that in posted mode the write
 73 * pending bit must be checked. Otherwise a write on a register which has a
 74 * pending write will be lost.
 75 */
 76static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 77						u32 value)
 78{
 79	WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
 80	__omap_dm_timer_write(timer, reg, value, timer->posted);
 81}
 82
 83static void omap_timer_restore_context(struct omap_dm_timer *timer)
 84{
 85	if (timer->revision == 1)
 86		__raw_writel(timer->context.tistat, timer->sys_stat);
 87
 88	__raw_writel(timer->context.tisr, timer->irq_stat);
 89	omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
 90				timer->context.twer);
 91	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
 92				timer->context.tcrr);
 93	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
 94				timer->context.tldr);
 95	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
 96				timer->context.tmar);
 97	omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
 98				timer->context.tsicr);
 99	__raw_writel(timer->context.tier, timer->irq_ena);
100	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
101				timer->context.tclr);
102}
103
104static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
105{
106	int c;
107
108	if (!timer->sys_stat)
109		return;
110
111	c = 0;
112	while (!(__raw_readl(timer->sys_stat) & 1)) {
113		c++;
114		if (c > 100000) {
115			printk(KERN_ERR "Timer failed to reset\n");
116			return;
117		}
118	}
119}
120
121static void omap_dm_timer_reset(struct omap_dm_timer *timer)
122{
123	omap_dm_timer_enable(timer);
124	if (timer->pdev->id != 1) {
125		omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
126		omap_dm_timer_wait_for_reset(timer);
127	}
128
129	__omap_dm_timer_reset(timer, 0, 0);
130	omap_dm_timer_disable(timer);
131	timer->posted = 1;
132}
133
134int omap_dm_timer_prepare(struct omap_dm_timer *timer)
135{
136	struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
137	int ret;
138
139	timer->fclk = clk_get(&timer->pdev->dev, "fck");
140	if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
141		timer->fclk = NULL;
142		dev_err(&timer->pdev->dev, ": No fclk handle.\n");
143		return -EINVAL;
144	}
145
146	if (pdata->needs_manual_reset)
147		omap_dm_timer_reset(timer);
148
149	ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
150
151	timer->posted = 1;
152	return ret;
153}
154
155struct omap_dm_timer *omap_dm_timer_request(void)
156{
157	struct omap_dm_timer *timer = NULL, *t;
158	unsigned long flags;
159	int ret = 0;
160
161	spin_lock_irqsave(&dm_timer_lock, flags);
162	list_for_each_entry(t, &omap_timer_list, node) {
163		if (t->reserved)
164			continue;
165
166		timer = t;
167		timer->reserved = 1;
168		break;
169	}
170
171	if (timer) {
172		ret = omap_dm_timer_prepare(timer);
173		if (ret) {
174			timer->reserved = 0;
175			timer = NULL;
176		}
177	}
178	spin_unlock_irqrestore(&dm_timer_lock, flags);
179
180	if (!timer)
181		pr_debug("%s: timer request failed!\n", __func__);
182
183	return timer;
184}
185EXPORT_SYMBOL_GPL(omap_dm_timer_request);
186
187struct omap_dm_timer *omap_dm_timer_request_specific(int id)
188{
189	struct omap_dm_timer *timer = NULL, *t;
190	unsigned long flags;
191	int ret = 0;
192
193	spin_lock_irqsave(&dm_timer_lock, flags);
194	list_for_each_entry(t, &omap_timer_list, node) {
195		if (t->pdev->id == id && !t->reserved) {
196			timer = t;
197			timer->reserved = 1;
198			break;
199		}
200	}
201
202	if (timer) {
203		ret = omap_dm_timer_prepare(timer);
204		if (ret) {
205			timer->reserved = 0;
206			timer = NULL;
207		}
208	}
209	spin_unlock_irqrestore(&dm_timer_lock, flags);
210
211	if (!timer)
212		pr_debug("%s: timer%d request failed!\n", __func__, id);
213
214	return timer;
215}
216EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
217
218int omap_dm_timer_free(struct omap_dm_timer *timer)
219{
220	if (unlikely(!timer))
221		return -EINVAL;
222
223	clk_put(timer->fclk);
224
225	WARN_ON(!timer->reserved);
226	timer->reserved = 0;
227	return 0;
228}
229EXPORT_SYMBOL_GPL(omap_dm_timer_free);
230
231void omap_dm_timer_enable(struct omap_dm_timer *timer)
232{
233	pm_runtime_get_sync(&timer->pdev->dev);
234}
235EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
236
237void omap_dm_timer_disable(struct omap_dm_timer *timer)
238{
239	pm_runtime_put_sync(&timer->pdev->dev);
240}
241EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
242
243int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
244{
245	if (timer)
246		return timer->irq;
247	return -EINVAL;
248}
249EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
250
251#if defined(CONFIG_ARCH_OMAP1)
252
253/**
254 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
255 * @inputmask: current value of idlect mask
256 */
257__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
258{
259	int i = 0;
260	struct omap_dm_timer *timer = NULL;
261	unsigned long flags;
262
263	/* If ARMXOR cannot be idled this function call is unnecessary */
264	if (!(inputmask & (1 << 1)))
265		return inputmask;
266
267	/* If any active timer is using ARMXOR return modified mask */
268	spin_lock_irqsave(&dm_timer_lock, flags);
269	list_for_each_entry(timer, &omap_timer_list, node) {
270		u32 l;
271
272		l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
273		if (l & OMAP_TIMER_CTRL_ST) {
274			if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
275				inputmask &= ~(1 << 1);
276			else
277				inputmask &= ~(1 << 2);
278		}
279		i++;
280	}
281	spin_unlock_irqrestore(&dm_timer_lock, flags);
282
283	return inputmask;
284}
285EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
286
287#else
288
289struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
290{
291	if (timer)
292		return timer->fclk;
293	return NULL;
294}
295EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
296
297__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
298{
299	BUG();
300
301	return 0;
302}
303EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
304
305#endif
306
307int omap_dm_timer_trigger(struct omap_dm_timer *timer)
308{
309	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
310		pr_err("%s: timer not available or enabled.\n", __func__);
311		return -EINVAL;
312	}
313
314	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
315	return 0;
316}
317EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
318
319int omap_dm_timer_start(struct omap_dm_timer *timer)
320{
321	u32 l;
322
323	if (unlikely(!timer))
324		return -EINVAL;
325
326	omap_dm_timer_enable(timer);
327
328	if (timer->loses_context) {
329		u32 ctx_loss_cnt_after =
330			timer->get_context_loss_count(&timer->pdev->dev);
331		if (ctx_loss_cnt_after != timer->ctx_loss_count)
332			omap_timer_restore_context(timer);
333	}
334
335	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
336	if (!(l & OMAP_TIMER_CTRL_ST)) {
337		l |= OMAP_TIMER_CTRL_ST;
338		omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
339	}
340
341	/* Save the context */
342	timer->context.tclr = l;
343	return 0;
344}
345EXPORT_SYMBOL_GPL(omap_dm_timer_start);
346
347int omap_dm_timer_stop(struct omap_dm_timer *timer)
348{
349	unsigned long rate = 0;
350	struct dmtimer_platform_data *pdata;
351
352	if (unlikely(!timer))
353		return -EINVAL;
354
355	pdata = timer->pdev->dev.platform_data;
356	if (!pdata->needs_manual_reset)
357		rate = clk_get_rate(timer->fclk);
358
359	__omap_dm_timer_stop(timer, timer->posted, rate);
360
361	if (timer->loses_context && timer->get_context_loss_count)
362		timer->ctx_loss_count =
363			timer->get_context_loss_count(&timer->pdev->dev);
364
365	/*
366	 * Since the register values are computed and written within
367	 * __omap_dm_timer_stop, we need to use read to retrieve the
368	 * context.
369	 */
370	timer->context.tclr =
371			omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
372	timer->context.tisr = __raw_readl(timer->irq_stat);
373	omap_dm_timer_disable(timer);
374	return 0;
375}
376EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
377
378int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
379{
380	int ret;
381	struct dmtimer_platform_data *pdata;
382
383	if (unlikely(!timer))
384		return -EINVAL;
385
386	pdata = timer->pdev->dev.platform_data;
387
388	if (source < 0 || source >= 3)
389		return -EINVAL;
390
391	ret = pdata->set_timer_src(timer->pdev, source);
392
393	return ret;
394}
395EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
396
397int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
398			    unsigned int load)
399{
400	u32 l;
401
402	if (unlikely(!timer))
403		return -EINVAL;
404
405	omap_dm_timer_enable(timer);
406	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
407	if (autoreload)
408		l |= OMAP_TIMER_CTRL_AR;
409	else
410		l &= ~OMAP_TIMER_CTRL_AR;
411	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
412	omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
413
414	omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
415	/* Save the context */
416	timer->context.tclr = l;
417	timer->context.tldr = load;
418	omap_dm_timer_disable(timer);
419	return 0;
420}
421EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
422
423/* Optimized set_load which removes costly spin wait in timer_start */
424int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
425                            unsigned int load)
426{
427	u32 l;
428
429	if (unlikely(!timer))
430		return -EINVAL;
431
432	omap_dm_timer_enable(timer);
433
434	if (timer->loses_context) {
435		u32 ctx_loss_cnt_after =
436			timer->get_context_loss_count(&timer->pdev->dev);
437		if (ctx_loss_cnt_after != timer->ctx_loss_count)
438			omap_timer_restore_context(timer);
439	}
440
441	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
442	if (autoreload) {
443		l |= OMAP_TIMER_CTRL_AR;
444		omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
445	} else {
446		l &= ~OMAP_TIMER_CTRL_AR;
447	}
448	l |= OMAP_TIMER_CTRL_ST;
449
450	__omap_dm_timer_load_start(timer, l, load, timer->posted);
451
452	/* Save the context */
453	timer->context.tclr = l;
454	timer->context.tldr = load;
455	timer->context.tcrr = load;
456	return 0;
457}
458EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
459
460int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
461			     unsigned int match)
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 (enable)
471		l |= OMAP_TIMER_CTRL_CE;
472	else
473		l &= ~OMAP_TIMER_CTRL_CE;
474	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
475	omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
476
477	/* Save the context */
478	timer->context.tclr = l;
479	timer->context.tmar = match;
480	omap_dm_timer_disable(timer);
481	return 0;
482}
483EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
484
485int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
486			   int toggle, int trigger)
487{
488	u32 l;
489
490	if (unlikely(!timer))
491		return -EINVAL;
492
493	omap_dm_timer_enable(timer);
494	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
495	l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
496	       OMAP_TIMER_CTRL_PT | (0x03 << 10));
497	if (def_on)
498		l |= OMAP_TIMER_CTRL_SCPWM;
499	if (toggle)
500		l |= OMAP_TIMER_CTRL_PT;
501	l |= trigger << 10;
502	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
503
504	/* Save the context */
505	timer->context.tclr = l;
506	omap_dm_timer_disable(timer);
507	return 0;
508}
509EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
510
511int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
512{
513	u32 l;
514
515	if (unlikely(!timer))
516		return -EINVAL;
517
518	omap_dm_timer_enable(timer);
519	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
520	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
521	if (prescaler >= 0x00 && prescaler <= 0x07) {
522		l |= OMAP_TIMER_CTRL_PRE;
523		l |= prescaler << 2;
524	}
525	omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
526
527	/* Save the context */
528	timer->context.tclr = l;
529	omap_dm_timer_disable(timer);
530	return 0;
531}
532EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
533
534int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
535				  unsigned int value)
536{
537	if (unlikely(!timer))
538		return -EINVAL;
539
540	omap_dm_timer_enable(timer);
541	__omap_dm_timer_int_enable(timer, value);
542
543	/* Save the context */
544	timer->context.tier = value;
545	timer->context.twer = value;
546	omap_dm_timer_disable(timer);
547	return 0;
548}
549EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
550
551unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
552{
553	unsigned int l;
554
555	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
556		pr_err("%s: timer not available or enabled.\n", __func__);
557		return 0;
558	}
559
560	l = __raw_readl(timer->irq_stat);
561
562	return l;
563}
564EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
565
566int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
567{
568	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
569		return -EINVAL;
570
571	__omap_dm_timer_write_status(timer, value);
572	/* Save the context */
573	timer->context.tisr = value;
574	return 0;
575}
576EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
577
578unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
579{
580	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
581		pr_err("%s: timer not iavailable or enabled.\n", __func__);
582		return 0;
583	}
584
585	return __omap_dm_timer_read_counter(timer, timer->posted);
586}
587EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
588
589int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
590{
591	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
592		pr_err("%s: timer not available or enabled.\n", __func__);
593		return -EINVAL;
594	}
595
596	omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
597
598	/* Save the context */
599	timer->context.tcrr = value;
600	return 0;
601}
602EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
603
604int omap_dm_timers_active(void)
605{
606	struct omap_dm_timer *timer;
607
608	list_for_each_entry(timer, &omap_timer_list, node) {
609		if (!timer->reserved)
610			continue;
611
612		if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
613		    OMAP_TIMER_CTRL_ST) {
614			return 1;
615		}
616	}
617	return 0;
618}
619EXPORT_SYMBOL_GPL(omap_dm_timers_active);
620
621/**
622 * omap_dm_timer_probe - probe function called for every registered device
623 * @pdev:	pointer to current timer platform device
624 *
625 * Called by driver framework at the end of device registration for all
626 * timer devices.
627 */
628static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
629{
630	int ret;
631	unsigned long flags;
632	struct omap_dm_timer *timer;
633	struct resource *mem, *irq, *ioarea;
634	struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
635
636	if (!pdata) {
637		dev_err(&pdev->dev, "%s: no platform data.\n", __func__);
638		return -ENODEV;
639	}
640
641	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
642	if (unlikely(!irq)) {
643		dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__);
644		return -ENODEV;
645	}
646
647	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
648	if (unlikely(!mem)) {
649		dev_err(&pdev->dev, "%s: no memory resource.\n", __func__);
650		return -ENODEV;
651	}
652
653	ioarea = request_mem_region(mem->start, resource_size(mem),
654			pdev->name);
655	if (!ioarea) {
656		dev_err(&pdev->dev, "%s: region already claimed.\n", __func__);
657		return -EBUSY;
658	}
659
660	timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL);
661	if (!timer) {
662		dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n",
663			__func__);
664		ret = -ENOMEM;
665		goto err_free_ioregion;
666	}
667
668	timer->io_base = ioremap(mem->start, resource_size(mem));
669	if (!timer->io_base) {
670		dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__);
671		ret = -ENOMEM;
672		goto err_free_mem;
673	}
674
675	timer->id = pdev->id;
676	timer->irq = irq->start;
677	timer->reserved = pdata->reserved;
678	timer->pdev = pdev;
679	timer->loses_context = pdata->loses_context;
680	timer->get_context_loss_count = pdata->get_context_loss_count;
681
682	/* Skip pm_runtime_enable for OMAP1 */
683	if (!pdata->needs_manual_reset) {
684		pm_runtime_enable(&pdev->dev);
685		pm_runtime_irq_safe(&pdev->dev);
686	}
687
688	if (!timer->reserved) {
689		pm_runtime_get_sync(&pdev->dev);
690		__omap_dm_timer_init_regs(timer);
691		pm_runtime_put(&pdev->dev);
692	}
693
694	/* add the timer element to the list */
695	spin_lock_irqsave(&dm_timer_lock, flags);
696	list_add_tail(&timer->node, &omap_timer_list);
697	spin_unlock_irqrestore(&dm_timer_lock, flags);
698
699	dev_dbg(&pdev->dev, "Device Probed.\n");
700
701	return 0;
702
703err_free_mem:
704	kfree(timer);
705
706err_free_ioregion:
707	release_mem_region(mem->start, resource_size(mem));
708
709	return ret;
710}
711
712/**
713 * omap_dm_timer_remove - cleanup a registered timer device
714 * @pdev:	pointer to current timer platform device
715 *
716 * Called by driver framework whenever a timer device is unregistered.
717 * In addition to freeing platform resources it also deletes the timer
718 * entry from the local list.
719 */
720static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
721{
722	struct omap_dm_timer *timer;
723	unsigned long flags;
724	int ret = -EINVAL;
725
726	spin_lock_irqsave(&dm_timer_lock, flags);
727	list_for_each_entry(timer, &omap_timer_list, node)
728		if (timer->pdev->id == pdev->id) {
729			list_del(&timer->node);
730			kfree(timer);
731			ret = 0;
732			break;
733		}
734	spin_unlock_irqrestore(&dm_timer_lock, flags);
735
736	return ret;
737}
738
739static struct platform_driver omap_dm_timer_driver = {
740	.probe  = omap_dm_timer_probe,
741	.remove = __devexit_p(omap_dm_timer_remove),
742	.driver = {
743		.name   = "omap_timer",
744	},
745};
746
747static int __init omap_dm_timer_driver_init(void)
748{
749	return platform_driver_register(&omap_dm_timer_driver);
750}
751
752static void __exit omap_dm_timer_driver_exit(void)
753{
754	platform_driver_unregister(&omap_dm_timer_driver);
755}
756
757early_platform_init("earlytimer", &omap_dm_timer_driver);
758module_init(omap_dm_timer_driver_init);
759module_exit(omap_dm_timer_driver_exit);
760
761MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
762MODULE_LICENSE("GPL");
763MODULE_ALIAS("platform:" DRIVER_NAME);
764MODULE_AUTHOR("Texas Instruments Inc");