| From 82f4b40ec43c886c8c16939ca9bf9f37bfc8e6bc Mon Sep 17 00:00:00 2001 |
| From: Nicolai Stange <nicstange@gmail.com> |
| Date: Mon, 6 Feb 2017 22:12:00 +0100 |
| Subject: [PATCH 129/286] clocksource: sh_tmu: Compute rate before registration |
| again |
| |
| With the upcoming NTP correction related rate adjustments to be implemented |
| in the clockevents core, the latter needs to get informed about every rate |
| change of a clockevent device made after its registration. |
| |
| Currently, sh_tmu violates this requirement in that it registers its |
| clockevent device with a dummy rate and sets its final rate through |
| clockevents_config() called from its ->set_state_oneshot() and |
| ->set_state_periodic() functions respectively. |
| |
| This patch moves the setting of the clockevent device's rate to its |
| registration. |
| |
| Note that there has been some back and forth regarding this question with |
| respect to the clocksource also provided by this driver: |
| commit 66f49121ffa4 ("clocksource: sh_tmu: compute mult and shift before |
| registration") |
| moves the rate determination from the clocksource's ->enable() function to |
| before its registration. OTOH, the later |
| commit 0aeac458d9eb ("clocksource: sh_tmu: __clocksource_updatefreq_hz() |
| update") |
| basically reverts this, saying |
| "Without this patch the old code uses clocksource_register() together |
| with a hack that assumes a never changing clock rate." |
| |
| However, I checked all current sh_tmu users in arch/sh as well as in |
| arch/arm/mach-shmobile carefully and right now, none of them changes any |
| rate in any clock tree relevant to sh_tmu after their respective |
| time_init(). Since all sh_tmu instances are created after time_init(), none |
| of them should ever observe any clock rate changes. |
| |
| What's more, both, a clocksource as well as a clockevent device, can |
| immediately get selected for use at their registration and thus, enabled |
| at this point already. So it's probably safer to assume a "never changing |
| clock rate" here. |
| |
| - Move the struct sh_tmu_channel's ->rate member to struct sh_tmu_device: |
| it's a property of the underlying clock which is in turn specific to |
| the sh_tmu_device. |
| - Determine the ->rate value in sh_tmu_setup() at device probing rather |
| than at first usage. |
| - Set the clockevent device's rate at its registration. |
| - Although not strictly necessary for the upcoming clockevent core changes, |
| set the clocksource's rate at its registration for consistency. |
| |
| Signed-off-by: Nicolai Stange <nicstange@gmail.com> |
| Signed-off-by: John Stultz <john.stultz@linaro.org> |
| (cherry picked from commit c3c0a20df9fc55e2243a31f91a943b3e8ba61289) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/clocksource/sh_tmu.c | 26 +++++++++++++------------- |
| 1 file changed, 13 insertions(+), 13 deletions(-) |
| |
| --- a/drivers/clocksource/sh_tmu.c |
| +++ b/drivers/clocksource/sh_tmu.c |
| @@ -46,7 +46,6 @@ struct sh_tmu_channel { |
| void __iomem *base; |
| int irq; |
| |
| - unsigned long rate; |
| unsigned long periodic; |
| struct clock_event_device ced; |
| struct clocksource cs; |
| @@ -59,6 +58,7 @@ struct sh_tmu_device { |
| |
| void __iomem *mapbase; |
| struct clk *clk; |
| + unsigned long rate; |
| |
| enum sh_tmu_model model; |
| |
| @@ -165,7 +165,6 @@ static int __sh_tmu_enable(struct sh_tmu |
| sh_tmu_write(ch, TCNT, 0xffffffff); |
| |
| /* configure channel to parent clock / 4, irq off */ |
| - ch->rate = clk_get_rate(ch->tmu->clk) / 4; |
| sh_tmu_write(ch, TCR, TCR_TPSC_CLK4); |
| |
| /* enable channel */ |
| @@ -271,10 +270,8 @@ static int sh_tmu_clocksource_enable(str |
| return 0; |
| |
| ret = sh_tmu_enable(ch); |
| - if (!ret) { |
| - __clocksource_update_freq_hz(cs, ch->rate); |
| + if (!ret) |
| ch->cs_enabled = true; |
| - } |
| |
| return ret; |
| } |
| @@ -334,8 +331,7 @@ static int sh_tmu_register_clocksource(s |
| dev_info(&ch->tmu->pdev->dev, "ch%u: used as clock source\n", |
| ch->index); |
| |
| - /* Register with dummy 1 Hz value, gets updated in ->enable() */ |
| - clocksource_register_hz(cs, 1); |
| + clocksource_register_hz(cs, ch->tmu->rate); |
| return 0; |
| } |
| |
| @@ -346,14 +342,10 @@ static struct sh_tmu_channel *ced_to_sh_ |
| |
| static void sh_tmu_clock_event_start(struct sh_tmu_channel *ch, int periodic) |
| { |
| - struct clock_event_device *ced = &ch->ced; |
| - |
| sh_tmu_enable(ch); |
| |
| - clockevents_config(ced, ch->rate); |
| - |
| if (periodic) { |
| - ch->periodic = (ch->rate + HZ/2) / HZ; |
| + ch->periodic = (ch->tmu->rate + HZ/2) / HZ; |
| sh_tmu_set_next(ch, ch->periodic, 1); |
| } |
| } |
| @@ -435,7 +427,7 @@ static void sh_tmu_register_clockevent(s |
| dev_info(&ch->tmu->pdev->dev, "ch%u: used for clock events\n", |
| ch->index); |
| |
| - clockevents_config_and_register(ced, 1, 0x300, 0xffffffff); |
| + clockevents_config_and_register(ced, ch->tmu->rate, 0x300, 0xffffffff); |
| |
| ret = request_irq(ch->irq, sh_tmu_interrupt, |
| IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, |
| @@ -561,6 +553,14 @@ static int sh_tmu_setup(struct sh_tmu_de |
| if (ret < 0) |
| goto err_clk_put; |
| |
| + /* Determine clock rate. */ |
| + ret = clk_enable(tmu->clk); |
| + if (ret < 0) |
| + goto err_clk_unprepare; |
| + |
| + tmu->rate = clk_get_rate(tmu->clk) / 4; |
| + clk_disable(tmu->clk); |
| + |
| /* Map the memory resource. */ |
| ret = sh_tmu_map_memory(tmu); |
| if (ret < 0) { |