Skip to content

Commit b2adbc9

Browse files
sipragabebarino
authored andcommitted
clk: si5351: allow PLLs to be adjusted without reset
Introduce a new PLL reset mode flag which controls whether or not to reset a PLL after adjusting its rate. The mode can be configured through platform data or device tree. Since commit 6dc669a ("clk: si5351: Add PLL soft reset"), the driver unconditionally resets a PLL whenever its rate is adjusted. The rationale was that a PLL reset was required to get three outputs working at the same time. Before this change, the driver never reset the PLLs. Commit b26ff12 ("clk: si5351: Apply PLL soft reset before enabling the outputs") subsequently introduced an option to reset the PLL when enabling a clock output that sourced it. Here, the rationale was that this is required to get a deterministic phase relationship between multiple output clocks. This clearly shows that it is useful to reset the PLLs in applications where multiple clock outputs are used. However, the Si5351 also allows for glitch-free rate adjustment of its PLLs if one avoids resetting the PLL. In our audio application where a single Si5351 clock output is used to supply a runtime adjustable bit clock, this unconditional PLL reset behaviour introduces unwanted glitches in the clock output. It would appear that the problem being solved in the former commit may be solved by using the optional device tree property introduced in the latter commit, obviating the need for an unconditional PLL reset after rate adjustment. But it's not OK to break the default behaviour of the driver, and it cannot be assumed that all device trees are using the property introduced in the latter commit. Hence, the new behaviour is made opt-in. Cc: Sebastian Hesselbarth <[email protected]> Cc: Rabeeh Khoury <[email protected]> Cc: Jacob Siverskog <[email protected]> Cc: Sergej Sawazki <[email protected]> Signed-off-by: Alvin Šipraga <[email protected]> Acked-by: Sebastian Hesselbarth <[email protected]> Link: https://lore.kernel.org/r/20231124-alvin-clk-si5351-no-pll-reset-v6-3-69b82311cb90@bang-olufsen.dk Signed-off-by: Stephen Boyd <[email protected]>
1 parent 9f950e7 commit b2adbc9

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

drivers/clk/clk-si5351.c

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,8 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
506506
{
507507
struct si5351_hw_data *hwdata =
508508
container_of(hw, struct si5351_hw_data, hw);
509+
struct si5351_platform_data *pdata =
510+
hwdata->drvdata->client->dev.platform_data;
509511
u8 reg = (hwdata->num == 0) ? SI5351_PLLA_PARAMETERS :
510512
SI5351_PLLB_PARAMETERS;
511513

@@ -518,9 +520,10 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
518520
(hwdata->params.p2 == 0) ? SI5351_CLK_INTEGER_MODE : 0);
519521

520522
/* Do a pll soft reset on the affected pll */
521-
si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
522-
hwdata->num == 0 ? SI5351_PLL_RESET_A :
523-
SI5351_PLL_RESET_B);
523+
if (pdata->pll_reset[hwdata->num])
524+
si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
525+
hwdata->num == 0 ? SI5351_PLL_RESET_A :
526+
SI5351_PLL_RESET_B);
524527

525528
dev_dbg(&hwdata->drvdata->client->dev,
526529
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
@@ -1222,6 +1225,44 @@ static int si5351_dt_parse(struct i2c_client *client,
12221225
}
12231226
}
12241227

1228+
/*
1229+
* Parse PLL reset mode. For compatibility with older device trees, the
1230+
* default is to always reset a PLL after setting its rate.
1231+
*/
1232+
pdata->pll_reset[0] = true;
1233+
pdata->pll_reset[1] = true;
1234+
1235+
of_property_for_each_u32(np, "silabs,pll-reset-mode", prop, p, num) {
1236+
if (num >= 2) {
1237+
dev_err(&client->dev,
1238+
"invalid pll %d on pll-reset-mode prop\n", num);
1239+
return -EINVAL;
1240+
}
1241+
1242+
p = of_prop_next_u32(prop, p, &val);
1243+
if (!p) {
1244+
dev_err(&client->dev,
1245+
"missing pll-reset-mode for pll %d\n", num);
1246+
return -EINVAL;
1247+
}
1248+
1249+
switch (val) {
1250+
case 0:
1251+
/* Reset PLL whenever its rate is adjusted */
1252+
pdata->pll_reset[num] = true;
1253+
break;
1254+
case 1:
1255+
/* Don't reset PLL whenever its rate is adjusted */
1256+
pdata->pll_reset[num] = false;
1257+
break;
1258+
default:
1259+
dev_err(&client->dev,
1260+
"invalid pll-reset-mode %d for pll %d\n", val,
1261+
num);
1262+
return -EINVAL;
1263+
}
1264+
}
1265+
12251266
/* per clkout properties */
12261267
for_each_child_of_node(np, child) {
12271268
if (of_property_read_u32(child, "reg", &num)) {

include/linux/platform_data/si5351.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,12 @@ struct si5351_clkout_config {
105105
* @clk_xtal: xtal input clock
106106
* @clk_clkin: clkin input clock
107107
* @pll_src: array of pll source clock setting
108+
* @pll_reset: array indicating if plls should be reset after setting the rate
108109
* @clkout: array of clkout configuration
109110
*/
110111
struct si5351_platform_data {
111112
enum si5351_pll_src pll_src[2];
113+
bool pll_reset[2];
112114
struct si5351_clkout_config clkout[8];
113115
};
114116

0 commit comments

Comments
 (0)