From 12b28ba6d6164d3aa54b7e32032bcbd9b7c2a320 Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Tue, 28 Mar 2017 20:57:55 -0500 Subject: ARM: OMAP2+: timer: Add suspend-resume callbacks for clkevent device OMAP timer code registers two timers - one as clocksource and one as clockevent. Since AM33XX has only one usable timer in the WKUP domain one of the timers needs suspend-resume support to restore the configuration to pre-suspend state. commit adc78e6b9946 ("timekeeping: Add suspend and resume of clock event devices") introduced .suspend and .resume callbacks for clock event devices. Leverage these callbacks to have AM33XX clockevent timer behave properly across system suspend. Extend the use of the .suspend and .resume callbacks used by am335x clockevent to am437x as well. Signed-off-by: Dave Gerlach Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/timer.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'arch/arm/mach-omap2/timer.c') diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 07dd692c4737..70670dfd7135 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -68,6 +68,9 @@ static struct omap_dm_timer clkev; static struct clock_event_device clockevent_gpt; +/* Clockevent hwmod for am335x and am437x suspend */ +static struct omap_hwmod *clockevent_gpt_hwmod; + #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER static unsigned long arch_timer_freq; @@ -125,6 +128,23 @@ static int omap2_gp_timer_set_periodic(struct clock_event_device *evt) return 0; } +static void omap_clkevt_idle(struct clock_event_device *unused) +{ + if (!clockevent_gpt_hwmod) + return; + + omap_hwmod_idle(clockevent_gpt_hwmod); +} + +static void omap_clkevt_unidle(struct clock_event_device *unused) +{ + if (!clockevent_gpt_hwmod) + return; + + omap_hwmod_enable(clockevent_gpt_hwmod); + __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW); +} + static struct clock_event_device clockevent_gpt = { .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, @@ -358,6 +378,14 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, 3, /* Timer internal resynch latency */ 0xffffffff); + if (soc_is_am33xx() || soc_is_am43xx()) { + clockevent_gpt.suspend = omap_clkevt_idle; + clockevent_gpt.resume = omap_clkevt_unidle; + + clockevent_gpt_hwmod = + omap_hwmod_lookup(clockevent_gpt.name); + } + pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name, clkev.rate); } -- cgit v1.2.3 From 8d39ff3d1696f7c6122500e21016f6837984ad8b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 31 May 2017 15:51:30 -0700 Subject: ARM: OMAP2+: Remove unused legacy code for timer We are now booting all mach-omap2 in device tree only mode. Any code that is only called in legacy boot mode where of_have_populated_dt() is not set is safe to remove now. Reviewed-by: Sebastian Reichel Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/timer.c | 169 +++++--------------------------------------- 1 file changed, 19 insertions(+), 150 deletions(-) (limited to 'arch/arm/mach-omap2/timer.c') diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 07dd692c4737..e4be76016939 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -232,37 +232,27 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, const char **timer_name, int posted) { - char name[10]; /* 10 = sizeof("gptXX_Xck0") */ const char *oh_name = NULL; struct device_node *np; struct omap_hwmod *oh; - struct resource irq, mem; struct clk *src; int r = 0; - if (of_have_populated_dt()) { - np = omap_get_timer_dt(omap_timer_match, property); - if (!np) - return -ENODEV; + np = omap_get_timer_dt(omap_timer_match, property); + if (!np) + return -ENODEV; - of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); - if (!oh_name) - return -ENODEV; + of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); + if (!oh_name) + return -ENODEV; - timer->irq = irq_of_parse_and_map(np, 0); - if (!timer->irq) - return -ENXIO; + timer->irq = irq_of_parse_and_map(np, 0); + if (!timer->irq) + return -ENXIO; - timer->io_base = of_iomap(np, 0); + timer->io_base = of_iomap(np, 0); - of_node_put(np); - } else { - if (omap_dm_timer_reserve_systimer(timer->id)) - return -ENODEV; - - sprintf(name, "timer%d", timer->id); - oh_name = name; - } + of_node_put(np); oh = omap_hwmod_lookup(oh_name); if (!oh) @@ -270,22 +260,6 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, *timer_name = oh->name; - if (!of_have_populated_dt()) { - r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, - &irq); - if (r) - return -ENXIO; - timer->irq = irq.start; - - r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, - &mem); - if (r) - return -ENXIO; - - /* Static mapping, never released */ - timer->io_base = ioremap(mem.start, mem.end - mem.start); - } - if (!timer->io_base) return -ENXIO; @@ -405,18 +379,15 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void) const char *oh_name = "counter_32k"; /* - * If device-tree is present, then search the DT blob - * to see if the 32kHz counter is supported. + * See if the 32kHz counter is supported. */ - if (of_have_populated_dt()) { - np = omap_get_timer_dt(omap_counter_match, NULL); - if (!np) - return -ENODEV; - - of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); - if (!oh_name) - return -ENODEV; - } + np = omap_get_timer_dt(omap_counter_match, NULL); + if (!np) + return -ENODEV; + + of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); + if (!oh_name) + return -ENODEV; /* * First check hwmod data is available for sync32k counter @@ -434,18 +405,6 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void) return ret; } - if (!of_have_populated_dt()) { - void __iomem *vbase; - - vbase = omap_hwmod_get_mpu_rt_va(oh); - - ret = omap_init_clocksource_32k(vbase); - if (ret) { - pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n", - __func__, ret); - omap_hwmod_idle(oh); - } - } return ret; } @@ -660,96 +619,6 @@ void __init omap5_realtime_timer_init(void) } #endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ -/** - * 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; - struct platform_device *pdev; - struct omap_timer_capability_dev_attr *timer_dev_attr; - - 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); - - if (timer_dev_attr) - pdata->timer_capability = timer_dev_attr->timer_capability; - - pdata->timer_errata = omap_dm_timer_get_errata(); - pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; - - pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata)); - - 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; - - /* If dtb is there, the devices will be created dynamically */ - if (of_have_populated_dt()) - return -ENODEV; - - 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; -} -omap_arch_initcall(omap2_dm_timer_init); - /** * omap2_override_clocksource - clocksource override with user configuration * -- cgit v1.2.3 From 138f7ca78f5a0677f591fdf23d0309c2f4774bf7 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 31 May 2017 17:59:58 +0300 Subject: ARM: OMAP2+: timer: add support for fetching fck handle from DT The mux clock handle shall be provided via "fck" DT handle. This avoids the need to lookup the main clock via hwmod core, which will not work with the clkctrl clock support anymore; the main clock is not going to be a mux. Signed-off-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/timer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-omap2/timer.c') diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 07dd692c4737..af90f95c2433 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -255,6 +255,8 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, timer->io_base = of_iomap(np, 0); + timer->fclk = of_clk_get_by_name(np, "fck"); + of_node_put(np); } else { if (omap_dm_timer_reserve_systimer(timer->id)) @@ -292,7 +294,8 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, omap_hwmod_setup_one(oh_name); /* After the dmtimer is using hwmod these clocks won't be needed */ - timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); + if (IS_ERR_OR_NULL(timer->fclk)) + timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); if (IS_ERR(timer->fclk)) return PTR_ERR(timer->fclk); -- cgit v1.2.3