}
OMAP_SYS_TIMER(4)
#endif
- struct omap_device *od;
+++ +
+++ +/**
+++ + * omap2_dm_timer_set_src - change the timer input clock source
+++ + * @pdev: timer platform device pointer
+++ + * @source: array index of parent clock source
+++ + */
+++ +static int omap2_dm_timer_set_src(struct platform_device *pdev, int source)
+++ +{
+++ + int ret;
+++ + struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
+++ + struct clk *fclk, *parent;
+++ + char *parent_name = NULL;
+++ +
+++ + fclk = clk_get(&pdev->dev, "fck");
+++ + if (IS_ERR_OR_NULL(fclk)) {
+++ + dev_err(&pdev->dev, "%s: %d: clk_get() FAILED\n",
+++ + __func__, __LINE__);
+++ + return -EINVAL;
+++ + }
+++ +
+++ + switch (source) {
+++ + case OMAP_TIMER_SRC_SYS_CLK:
+++ + parent_name = "sys_ck";
+++ + break;
+++ +
+++ + case OMAP_TIMER_SRC_32_KHZ:
+++ + parent_name = "32k_ck";
+++ + break;
+++ +
+++ + case OMAP_TIMER_SRC_EXT_CLK:
+++ + if (pdata->timer_ip_version == OMAP_TIMER_IP_VERSION_1) {
+++ + parent_name = "alt_ck";
+++ + break;
+++ + }
+++ + dev_err(&pdev->dev, "%s: %d: invalid clk src.\n",
+++ + __func__, __LINE__);
+++ + clk_put(fclk);
+++ + return -EINVAL;
+++ + }
+++ +
+++ + parent = clk_get(&pdev->dev, parent_name);
+++ + if (IS_ERR_OR_NULL(parent)) {
+++ + dev_err(&pdev->dev, "%s: %d: clk_get() %s FAILED\n",
+++ + __func__, __LINE__, parent_name);
+++ + clk_put(fclk);
+++ + return -EINVAL;
+++ + }
+++ +
+++ + ret = clk_set_parent(fclk, parent);
+++ + if (IS_ERR_VALUE(ret)) {
+++ + dev_err(&pdev->dev, "%s: clk_set_parent() to %s FAILED\n",
+++ + __func__, parent_name);
+++ + ret = -EINVAL;
+++ + }
+++ +
+++ + clk_put(parent);
+++ + clk_put(fclk);
+++ +
+++ + return ret;
+++ +}
+++ +
+++ +struct omap_device_pm_latency omap2_dmtimer_latency[] = {
+++ + {
+++ + .deactivate_func = omap_device_idle_hwmods,
+++ + .activate_func = omap_device_enable_hwmods,
+++ + .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+++ + },
+++ +};
+++ +
+++ +/**
+++ + * omap_timer_init - build and register timer device with an
+++ + * associated timer hwmod
+++ + * @oh: timer hwmod pointer to be used to build timer device
+++ + * @user: parameter that can be passed from calling hwmod API
+++ + *
+++ + * Called by omap_hwmod_for_each_by_class to register each of the timer
+++ + * devices present in the system. The number of timer devices is known
+++ + * by parsing through the hwmod database for a given class name. At the
+++ + * end of function call memory is allocated for timer device and it is
+++ + * registered to the framework ready to be proved by the driver.
+++ + */
+++ +static int __init omap_timer_init(struct omap_hwmod *oh, void *unused)
+++ +{
+++ + int id;
+++ + int ret = 0;
+++ + char *name = "omap_timer";
+++ + struct dmtimer_platform_data *pdata;
- od = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
+++++ struct platform_device *pdev;
+++ + struct omap_timer_capability_dev_attr *timer_dev_attr;
+++ + struct powerdomain *pwrdm;
+++ +
+++ + pr_debug("%s: %s\n", __func__, oh->name);
+++ +
+++ + /* on secure device, do not register secure timer */
+++ + timer_dev_attr = oh->dev_attr;
+++ + if (omap_type() != OMAP2_DEVICE_TYPE_GP && timer_dev_attr)
+++ + if (timer_dev_attr->timer_capability == OMAP_TIMER_SECURE)
+++ + return ret;
+++ +
+++ + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+++ + if (!pdata) {
+++ + pr_err("%s: No memory for [%s]\n", __func__, oh->name);
+++ + return -ENOMEM;
+++ + }
+++ +
+++ + /*
+++ + * Extract the IDs from name field in hwmod database
+++ + * and use the same for constructing ids' for the
+++ + * timer devices. In a way, we are avoiding usage of
+++ + * static variable witin the function to do the same.
+++ + * CAUTION: We have to be careful and make sure the
+++ + * name in hwmod database does not change in which case
+++ + * we might either make corresponding change here or
+++ + * switch back static variable mechanism.
+++ + */
+++ + sscanf(oh->name, "timer%2d", &id);
+++ +
+++ + pdata->set_timer_src = omap2_dm_timer_set_src;
+++ + pdata->timer_ip_version = oh->class->rev;
+++ +
+++ + /* Mark clocksource and clockevent timers as reserved */
+++ + if ((sys_timer_reserved >> (id - 1)) & 0x1)
+++ + pdata->reserved = 1;
+++ +
+++ + pwrdm = omap_hwmod_get_pwrdm(oh);
+++ + pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+++ +#ifdef CONFIG_PM
+++ + pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
+++ +#endif
- if (IS_ERR(od)) {
+++++ pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata),
+++ + omap2_dmtimer_latency,
+++ + ARRAY_SIZE(omap2_dmtimer_latency),
+++ + 0);
+++ +
+++++ if (IS_ERR(pdev)) {
+++ + pr_err("%s: Can't build omap_device for %s: %s.\n",
+++ + __func__, name, oh->name);
+++ + ret = -EINVAL;
+++ + }
+++ +
+++ + kfree(pdata);
+++ +
+++ + return ret;
+++ +}
+++ +
+++ +/**
+++ + * omap2_dm_timer_init - top level regular device initialization
+++ + *
+++ + * Uses dedicated hwmod api to parse through hwmod database for
+++ + * given class name and then build and register the timer device.
+++ + */
+++ +static int __init omap2_dm_timer_init(void)
+++ +{
+++ + int ret;
+++ +
+++ + ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL);
+++ + if (unlikely(ret)) {
+++ + pr_err("%s: device registration failed.\n", __func__);
+++ + return -EINVAL;
+++ + }
+++ +
+++ + return 0;
+++ +}
+++ +arch_initcall(omap2_dm_timer_init);