Skip to contentSkip to conversation

clk: at91: Fix for PLL set_rate changes not being actually written to PLL peripheral bits

PATCH In review Marcin Ziemianowicz 2 participants 2 messages Apr 10, 2018

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH v2 2/2 clk: at91: Fix for PLL set_rate changes not being actually written to PLL peripheral bits

When a USB device is connected to the USB host port on the SAM9N12 then you get "-62" error which seems to indicate USB replies from the device are timing out. Looking around, I saw the USB bus was running at half speed. Going further, it seems that in ..._set_rate() the PLL wasn't actually being adjusted. Writing the multiplier and divider values to the peripheral fixes the bus running at half speed.

---
 drivers/clk/at91/clk-pll.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/clk/at91/clk-pll.c +8 -0
index 534961766ae5..db7155fe9346 100644
@@ -288,6 +288,14 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 	pll->div = div;
 	pll->mul = mul;
 
+	// Set the PLL as per above div and mil values.
+	regmap_update_bits(pll->regmap, AT91_CKGR_PLLBR,
+		AT91_PMC_DIV | AT91_PMC_MUL,
+		(div << 0) | (mul << 16));
+
+	pr_debug("clk-pll: setting new rate, (%lu hz / %u) * %u = %lu hz\n",
+		parent_rate, div, mul, rate);
+
 	return 0;
 }
 
Signature · 1 line
2.17.0
#1 lore raw

Hi Marcin,

Quoted 17 lines · On Mon, 9 Apr 2018 20:16:49 -0400 Marcin Ziemianowicz…

When a USB device is connected to the USB host port on the SAM9N12 then you get "-62" error which seems to indicate USB replies from the device are timing out. Looking around, I saw the USB bus was running at half speed. Going further, it seems that in ..._set_rate() the PLL wasn't actually being adjusted. Writing the multiplier and divider values to the peripheral fixes the bus running at half speed.

---
 drivers/clk/at91/clk-pll.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/clk/at91/clk-pll.c +0 -0
index 534961766ae5..db7155fe9346 100644

drivers/clk/at91/clk-pll.c static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, · line 291

Quoted 4 lines
drivers/clk/at91/clk-pll.c +1 -0
@@ -288,6 +288,14 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 	pll->div = div;
 	pll->mul = mul;
 
+	// Set the PLL as per above div and mil values.

^ mul

Please do not use C++-style comments, use /* comment */ instead.

drivers/clk/at91/clk-pll.c static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, · line 292

Quoted 1 line
drivers/clk/at91/clk-pll.c +1 -0
+	regmap_update_bits(pll->regmap, AT91_CKGR_PLLBR,

You hardcode the PLL ID here. What if this function if called for PLLA?

drivers/clk/at91/clk-pll.c static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, · line 293

Quoted 1 line
drivers/clk/at91/clk-pll.c +1 -0
+		AT91_PMC_DIV | AT91_PMC_MUL,

You should use PLL_MUL_MASK(layout) and PLL_DIV_MASK to do that.

drivers/clk/at91/clk-pll.c static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, · line 294

Quoted 1 line
drivers/clk/at91/clk-pll.c +1 -0
+		(div << 0) | (mul << 16));

This is wrong. The clk has the CLK_SET_RATE_GATE set, which means the rate cannot be updated if the PLL is not gated, and if you look at clk_pll_prepare(), you'll see that div and mul fields are updated there. Now, maybe there's a bug in clk_pll_prepare(), but clk_pll_set_rate() is definitely not the place where we want ->div and ->mul to be written to the register.

drivers/clk/at91/clk-pll.c static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, · line 301

Quoted 7 lines
drivers/clk/at91/clk-pll.c +4 -0
+
+	pr_debug("clk-pll: setting new rate, (%lu hz / %u) * %u = %lu hz\n",
+		parent_rate, div, mul, rate);
+
 	return 0;
 }
 

Regards,

Boris