Commit c3c0a20d authored by Nicolai Stange's avatar Nicolai Stange Committed by John Stultz

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 66f49121 ("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 0aeac458 ("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: default avatarNicolai Stange <nicstange@gmail.com>
Signed-off-by: default avatarJohn Stultz <john.stultz@linaro.org>
parent 890f423b
...@@ -46,7 +46,6 @@ struct sh_tmu_channel { ...@@ -46,7 +46,6 @@ struct sh_tmu_channel {
void __iomem *base; void __iomem *base;
int irq; int irq;
unsigned long rate;
unsigned long periodic; unsigned long periodic;
struct clock_event_device ced; struct clock_event_device ced;
struct clocksource cs; struct clocksource cs;
...@@ -59,6 +58,7 @@ struct sh_tmu_device { ...@@ -59,6 +58,7 @@ struct sh_tmu_device {
void __iomem *mapbase; void __iomem *mapbase;
struct clk *clk; struct clk *clk;
unsigned long rate;
enum sh_tmu_model model; enum sh_tmu_model model;
...@@ -165,7 +165,6 @@ static int __sh_tmu_enable(struct sh_tmu_channel *ch) ...@@ -165,7 +165,6 @@ static int __sh_tmu_enable(struct sh_tmu_channel *ch)
sh_tmu_write(ch, TCNT, 0xffffffff); sh_tmu_write(ch, TCNT, 0xffffffff);
/* configure channel to parent clock / 4, irq off */ /* 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); sh_tmu_write(ch, TCR, TCR_TPSC_CLK4);
/* enable channel */ /* enable channel */
...@@ -271,10 +270,8 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs) ...@@ -271,10 +270,8 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs)
return 0; return 0;
ret = sh_tmu_enable(ch); ret = sh_tmu_enable(ch);
if (!ret) { if (!ret)
__clocksource_update_freq_hz(cs, ch->rate);
ch->cs_enabled = true; ch->cs_enabled = true;
}
return ret; return ret;
} }
...@@ -334,8 +331,7 @@ static int sh_tmu_register_clocksource(struct sh_tmu_channel *ch, ...@@ -334,8 +331,7 @@ static int sh_tmu_register_clocksource(struct sh_tmu_channel *ch,
dev_info(&ch->tmu->pdev->dev, "ch%u: used as clock source\n", dev_info(&ch->tmu->pdev->dev, "ch%u: used as clock source\n",
ch->index); ch->index);
/* Register with dummy 1 Hz value, gets updated in ->enable() */ clocksource_register_hz(cs, ch->tmu->rate);
clocksource_register_hz(cs, 1);
return 0; return 0;
} }
...@@ -346,14 +342,10 @@ static struct sh_tmu_channel *ced_to_sh_tmu(struct clock_event_device *ced) ...@@ -346,14 +342,10 @@ static struct sh_tmu_channel *ced_to_sh_tmu(struct clock_event_device *ced)
static void sh_tmu_clock_event_start(struct sh_tmu_channel *ch, int periodic) 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); sh_tmu_enable(ch);
clockevents_config(ced, ch->rate);
if (periodic) { 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); sh_tmu_set_next(ch, ch->periodic, 1);
} }
} }
...@@ -435,7 +427,7 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch, ...@@ -435,7 +427,7 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch,
dev_info(&ch->tmu->pdev->dev, "ch%u: used for clock events\n", dev_info(&ch->tmu->pdev->dev, "ch%u: used for clock events\n",
ch->index); 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, ret = request_irq(ch->irq, sh_tmu_interrupt,
IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
...@@ -561,6 +553,14 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev) ...@@ -561,6 +553,14 @@ static int sh_tmu_setup(struct sh_tmu_device *tmu, struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto err_clk_put; 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. */ /* Map the memory resource. */
ret = sh_tmu_map_memory(tmu); ret = sh_tmu_map_memory(tmu);
if (ret < 0) { if (ret < 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment