2 * OMAP2+ Dual-Mode Timers - platform device registration
4 * Contains first level initialization routines which extracts timers
5 * information from hwmod database and registers with linux device model.
6 * It also has low level function to change the timer input clock source.
8 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
9 * Tarun Kanti DebBarma <tarun.kanti@ti.com>
10 * Thara Gopinath <thara@ti.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
16 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
17 * kind, whether express or implied; without even the implied warranty
18 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
22 #include <linux/clk.h>
23 #include <linux/err.h>
24 #include <linux/slab.h>
26 #include <plat/dmtimer.h>
27 #include <plat/omap_device.h>
29 #include <plat/omap_hwmod.h>
30 #include <plat/omap-pm.h>
32 #include "powerdomain.h"
34 static u8 __initdata system_timer_id
;
37 * omap2_dm_timer_set_src - change the timer input clock source
38 * @pdev: timer platform device pointer
39 * @source: array index of parent clock source
41 static int omap2_dm_timer_set_src(struct platform_device
*pdev
, int source
)
44 struct dmtimer_platform_data
*pdata
= pdev
->dev
.platform_data
;
46 char *fclk_name
= "32k_ck"; /* default name */
48 struct clk
*fclk
= clk_get(&pdev
->dev
, "fck");
49 if (IS_ERR_OR_NULL(fclk
)) {
50 dev_err(&pdev
->dev
, "%s: %d: clk_get() FAILED\n",
56 case OMAP_TIMER_SRC_SYS_CLK
:
60 case OMAP_TIMER_SRC_32_KHZ
:
64 case OMAP_TIMER_SRC_EXT_CLK
:
65 if (pdata
->timer_ip_type
== OMAP_TIMER_IP_VERSION_1
) {
70 dev_err(&pdev
->dev
, "%s: %d: invalid clk src.\n",
76 new_fclk
= clk_get(&pdev
->dev
, fclk_name
);
77 if (IS_ERR_OR_NULL(new_fclk
)) {
78 dev_err(&pdev
->dev
, "%s: %d: clk_get() %s FAILED\n",
79 __func__
, __LINE__
, fclk_name
);
84 ret
= clk_set_parent(fclk
, new_fclk
);
85 if (IS_ERR_VALUE(ret
)) {
86 dev_err(&pdev
->dev
, "%s: clk_set_parent() to %s FAILED\n",
97 struct omap_device_pm_latency omap2_dmtimer_latency
[] = {
99 .deactivate_func
= omap_device_idle_hwmods
,
100 .activate_func
= omap_device_enable_hwmods
,
101 .flags
= OMAP_DEVICE_LATENCY_AUTO_ADJUST
,
106 * omap_timer_init - build and register timer device with an
107 * associated timer hwmod
108 * @oh: timer hwmod pointer to be used to build timer device
109 * @user: parameter that can be passed from calling hwmod API
111 * Called by omap_hwmod_for_each_by_class to register each of the timer
112 * devices present in the system. The number of timer devices is known
113 * by parsing through the hwmod database for a given class name. At the
114 * end of function call memory is allocated for timer device and it is
115 * registered to the framework ready to be proved by the driver.
117 static int __init
omap_timer_init(struct omap_hwmod
*oh
, void *unused
)
121 char *name
= "omap_timer";
122 struct dmtimer_platform_data
*pdata
;
123 struct omap_device
*od
;
124 struct omap_secure_timer_dev_attr
*secure_timer_dev_attr
;
125 struct powerdomain
*pwrdm
;
128 * Extract the IDs from name field in hwmod database
129 * and use the same for constructing ids' for the
130 * timer devices. In a way, we are avoiding usage of
131 * static variable witin the function to do the same.
132 * CAUTION: We have to be careful and make sure the
133 * name in hwmod database does not change in which case
134 * we might either make corresponding change here or
135 * switch back static variable mechanism.
137 sscanf(oh
->name
, "timer%2d", &id
);
138 if (unlikely(id
== system_timer_id
))
141 pr_debug("%s: %s\n", __func__
, oh
->name
);
143 /* do not register secure timer */
144 secure_timer_dev_attr
= oh
->dev_attr
;
145 if (secure_timer_dev_attr
&& secure_timer_dev_attr
->is_secure_timer
)
148 pdata
= kzalloc(sizeof(*pdata
), GFP_KERNEL
);
150 pr_err("%s: No memory for [%s]\n", __func__
, oh
->name
);
153 pdata
->set_timer_src
= omap2_dm_timer_set_src
;
154 pdata
->timer_ip_type
= oh
->class->rev
;
155 pwrdm
= omap_hwmod_get_pwrdm(oh
);
157 pr_debug("%s: could not find pwrdm for (%s) in omap hwmod!\n",
161 pdata
->loses_context
= pwrdm_can_ever_lose_context(pwrdm
);
163 od
= omap_device_build(name
, id
, oh
, pdata
, sizeof(*pdata
),
164 omap2_dmtimer_latency
,
165 ARRAY_SIZE(omap2_dmtimer_latency
),
166 pdata
->is_early_init
);
169 pr_err("%s: Can't build omap_device for %s: %s.\n",
170 __func__
, name
, oh
->name
);
180 * omap2_system_timer_init - top level system timer initialization
181 * called from omap2_gp_timer_init() in timer-gp.c
182 * @id : system timer id
184 * This function does hwmod setup for the system timer entry needed
185 * prior to building and registering the device. After the device is
186 * registered early probe initiated.
188 int __init
omap2_system_timer_init(u8 id
)
191 char *name
= "omap_timer";
192 struct dmtimer_platform_data
*pdata
;
193 struct omap_device
*od
;
194 struct omap_hwmod
*oh
;
195 char system_timer_name
[8]; /* 8 = sizeof("timerXX0") */
197 system_timer_id
= id
;
199 sprintf(system_timer_name
, "timer%d", id
);
200 ret
= omap_hwmod_setup_one(system_timer_name
);
202 pr_err("%s: omap_hwmod_setup_one(%s) failed.\n",
203 __func__
, system_timer_name
);
206 oh
= omap_hwmod_lookup(system_timer_name
);
208 pr_debug("%s: could not find (%s) in omap_hwmod_list!\n",
209 __func__
, system_timer_name
);
213 pdata
= kzalloc(sizeof(*pdata
), GFP_KERNEL
);
215 pr_err("%s: No memory for [%s]\n", __func__
, oh
->name
);
218 pdata
->is_early_init
= 1;
219 pdata
->set_timer_src
= omap2_dm_timer_set_src
;
220 pdata
->timer_ip_type
= oh
->class->rev
;
221 pdata
->needs_manual_reset
= 0;
223 od
= omap_device_build(name
, id
, oh
, pdata
, sizeof(*pdata
),
224 omap2_dmtimer_latency
,
225 ARRAY_SIZE(omap2_dmtimer_latency
),
226 pdata
->is_early_init
);
229 pr_err("%s: Can't build omap_device for %s: %s.\n",
230 __func__
, name
, oh
->name
);
237 early_platform_driver_register_all("earlytimer");
238 early_platform_driver_probe("earlytimer", 1, 0);
245 * omap2_system_timer_set_src - change the timer input clock source
246 * Allow system timer to program clock source before pm_runtime
247 * framework is available during system boot.
248 * @timer: pointer to struct omap_dm_timer
249 * @source: array index of parent clock source
251 int __init
omap2_system_timer_set_src(struct omap_dm_timer
*timer
, int source
)
255 if (IS_ERR_OR_NULL(timer
) || IS_ERR_OR_NULL(timer
->fclk
))
258 clk_disable(timer
->fclk
);
259 ret
= omap2_dm_timer_set_src(timer
->pdev
, source
);
260 clk_enable(timer
->fclk
);
266 * omap2_dm_timer_init - top level regular device initialization
268 * Uses dedicated hwmod api to parse through hwmod database for
269 * given class name and then build and register the timer device.
271 static int __init
omap2_dm_timer_init(void)
275 ret
= omap_hwmod_for_each_by_class("timer", omap_timer_init
, NULL
);
277 pr_err("%s: device registration failed.\n", __func__
);
283 arch_initcall(omap2_dm_timer_init
);