Commit 27a5362e authored by Adam Wujek's avatar Adam Wujek Committed by Adam Wujek

sw/petalinux/linux: backport SI5341

Signed-off-by: 's avatarAdam Wujek <dev_public@wujek.eu>
parent 0b641b7e
From 6eb515aa4b088e7b0d940eda054737b749827226 Mon Sep 17 00:00:00 2001
From: Colin Ian King <colin.king@canonical.com>
Date: Mon, 1 Jul 2019 17:50:20 +0100
Subject: [PATCH] clk: Si5341/Si5340: remove redundant assignment to n_den
The variable n_den is initialized however that value is never read
as n_den is re-assigned a little later in the two paths of a
following if-statement. Remove the redundant assignment.
Addresses-Coverity: ("Unused value")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
Link: https://lkml.kernel.org/r/20190701165020.19840-1-colin.king@canonical.com
Acked-by: Mike Looijmans <mike.looijmans@topic.nl>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-si5341.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index 72424eb7e5f8..6e780c2a9e6b 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -547,7 +547,6 @@ static int si5341_synth_clk_set_rate(struct clk_hw *hw, unsigned long rate,
bool is_integer;
n_num = synth->data->freq_vco;
- n_den = rate;
/* see if there's an integer solution */
r = do_div(n_num, rate);
From d2ca2cdee1e3cf13d97cbdd66bd2e6876707c25a Mon Sep 17 00:00:00 2001
From: Mike Looijmans <mike.looijmans@topic.nl>
Date: Fri, 17 May 2019 15:20:20 +0200
Subject: [PATCH] dt-bindings: clock: Add silabs,si5341
Adds the devicetree bindings for the Si5341 and Si5340 chips from
Silicon Labs. These are multiple-input multiple-output clock
synthesizers.
Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
.../bindings/clock/silabs,si5341.txt | 162 ++++++++++++++++++
1 file changed, 162 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/silabs,si5341.txt
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
new file mode 100644
index 000000000000..a70c333e4cd4
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
@@ -0,0 +1,162 @@
+Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
+
+Reference
+[1] Si5341 Data Sheet
+ https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
+[2] Si5341 Reference Manual
+ https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
+
+The Si5341 and Si5340 are programmable i2c clock generators with up to 10 output
+clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
+in turn can be directed to any of the 10 (or 4) outputs through a divider.
+The internal structure of the clock generators can be found in [2].
+
+The driver can be used in "as is" mode, reading the current settings from the
+chip at boot, in case you have a (pre-)programmed device. If the PLL is not
+configured when the driver probes, it assumes the driver must fully initialize
+it.
+
+The device type, speed grade and revision are determined runtime by probing.
+
+The driver currently only supports XTAL input mode, and does not support any
+fancy input configurations. They can still be programmed into the chip and
+the driver will leave them "as is".
+
+==I2C device node==
+
+Required properties:
+- compatible: shall be one of the following:
+ "silabs,si5340" - Si5340 A/B/C/D
+ "silabs,si5341" - Si5341 A/B/C/D
+- reg: i2c device address, usually 0x74
+- #clock-cells: from common clock binding; shall be set to 2.
+ The first value is "0" for outputs, "1" for synthesizers.
+ The second value is the output or synthesizer index.
+- clocks: from common clock binding; list of parent clock handles,
+ corresponding to inputs. Use a fixed clock for the "xtal" input.
+ At least one must be present.
+- clock-names: One of: "xtal", "in0", "in1", "in2"
+- vdd-supply: Regulator node for VDD
+
+Optional properties:
+- vdda-supply: Regulator node for VDDA
+- vdds-supply: Regulator node for VDDS
+- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
+ feedback divider. Must be such that the PLL output is in the valid range. For
+ example, to create 14GHz from a 48MHz xtal, use m-num=14000 and m-den=48. Only
+ the fraction matters, using 3500 and 12 will deliver the exact same result.
+ If these are not specified, and the PLL is not yet programmed when the driver
+ probes, the PLL will be set to 14GHz.
+- silabs,reprogram: When present, the driver will always assume the device must
+ be initialized, and always performs the soft-reset routine. Since this will
+ temporarily stop all output clocks, don't do this if the chip is generating
+ the CPU clock for example.
+- interrupts: Interrupt for INTRb pin.
+- #address-cells: shall be set to 1.
+- #size-cells: shall be set to 0.
+
+
+== Child nodes: Outputs ==
+
+The child nodes list the output clocks.
+
+Each of the clock outputs can be overwritten individually by using a child node.
+If a child node for a clock output is not set, the configuration remains
+unchanged.
+
+Required child node properties:
+- reg: number of clock output.
+
+Optional child node properties:
+- vdd-supply: Regulator node for VDD for this output. The driver selects default
+ values for common-mode and amplitude based on the voltage.
+- silabs,format: Output format, one of:
+ 1 = differential (defaults to LVDS levels)
+ 2 = low-power (defaults to HCSL levels)
+ 4 = LVCMOS
+- silabs,common-mode: Manually override output common mode, see [2] for values
+- silabs,amplitude: Manually override output amplitude, see [2] for values
+- silabs,synth-master: boolean. If present, this output is allowed to change the
+ multisynth frequency dynamically.
+- silabs,silabs,disable-high: boolean. If set, the clock output is driven HIGH
+ when disabled, otherwise it's driven LOW.
+
+==Example==
+
+/* 48MHz reference crystal */
+ref48: ref48M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <48000000>;
+};
+
+i2c-master-node {
+ /* Programmable clock (for logic) */
+ si5341: clock-generator@74 {
+ reg = <0x74>;
+ compatible = "silabs,si5341";
+ #clock-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&ref48>;
+ clock-names = "xtal";
+
+ silabs,pll-m-num = <14000>; /* PLL at 14.0 GHz */
+ silabs,pll-m-den = <48>;
+ silabs,reprogram; /* Chips are not programmed, always reset */
+
+ out@0 {
+ reg = <0>;
+ silabs,format = <1>; /* LVDS 3v3 */
+ silabs,common-mode = <3>;
+ silabs,amplitude = <3>;
+ silabs,synth-master;
+ };
+
+ /*
+ * Output 6 configuration:
+ * LVDS 1v8
+ */
+ out@6 {
+ reg = <6>;
+ silabs,format = <1>; /* LVDS 1v8 */
+ silabs,common-mode = <13>;
+ silabs,amplitude = <3>;
+ };
+
+ /*
+ * Output 8 configuration:
+ * HCSL 3v3
+ */
+ out@8 {
+ reg = <8>;
+ silabs,format = <2>;
+ silabs,common-mode = <11>;
+ silabs,amplitude = <3>;
+ };
+ };
+};
+
+some-video-node {
+ /* Standard clock bindings */
+ clock-names = "pixel";
+ clocks = <&si5341 0 7>; /* Output 7 */
+
+ /* Set output 7 to use syntesizer 3 as its parent */
+ assigned-clocks = <&si5341 0 7>, <&si5341 1 3>;
+ assigned-clock-parents = <&si5341 1 3>;
+ /* Set output 7 to 148.5 MHz using a synth frequency of 594 MHz */
+ assigned-clock-rates = <148500000>, <594000000>;
+};
+
+some-audio-node {
+ clock-names = "i2s-clk";
+ clocks = <&si5341 0 0>;
+ /*
+ * since output 0 is a synth-master, the synth will be automatically set
+ * to an appropriate frequency when the audio driver requests another
+ * frequency. We give control over synth 2 to this output here.
+ */
+ assigned-clocks = <&si5341 0 0>;
+ assigned-clock-parents = <&si5341 1 2>;
+};
From 2c73c31c0742cd800831b657cbfaa77fe00079bc Mon Sep 17 00:00:00 2001
From: Mike Looijmans <mike.looijmans@topic.nl>
Date: Thu, 7 May 2020 08:15:44 +0200
Subject: [PATCH] clk: clk-si5341: Add support for the Si5345 series
Add support for the Si5342, Si5344 and Si5345 chips. These are equivalent
to the Si5341 family, but with more clock input options (which are not
supported yet by this driver).
Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>
Link: https://lkml.kernel.org/r/20200507061544.11388-1-mike.looijmans@topic.nl
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
.../bindings/clock/silabs,si5341.txt | 11 ++-
drivers/clk/clk-si5341.c | 69 +++++++++++++++++--
2 files changed, 74 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
index a70c333e4cd4..504cce3abe46 100644
--- a/Documentation/devicetree/bindings/clock/silabs,si5341.txt
+++ b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
@@ -1,15 +1,21 @@
-Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
+Binding for Silicon Labs Si5340, Si5341 Si5342, Si5344 and Si5345 programmable
+i2c clock generator.
Reference
[1] Si5341 Data Sheet
https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
[2] Si5341 Reference Manual
https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
+[3] Si5345 Reference Manual
+ https://www.silabs.com/documents/public/reference-manuals/Si5345-44-42-D-RM.pdf
The Si5341 and Si5340 are programmable i2c clock generators with up to 10 output
clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
in turn can be directed to any of the 10 (or 4) outputs through a divider.
The internal structure of the clock generators can be found in [2].
+The Si5345 is similar to the Si5341 with the addition of fractional input
+dividers and automatic input selection, as described in [3].
+The Si5342 and Si5344 are smaller versions of the Si5345, with 2 or 4 outputs.
The driver can be used in "as is" mode, reading the current settings from the
chip at boot, in case you have a (pre-)programmed device. If the PLL is not
@@ -28,6 +34,9 @@ Required properties:
- compatible: shall be one of the following:
"silabs,si5340" - Si5340 A/B/C/D
"silabs,si5341" - Si5341 A/B/C/D
+ "silabs,si5342" - Si5342 A/B/C/D
+ "silabs,si5344" - Si5344 A/B/C/D
+ "silabs,si5345" - Si5345 A/B/C/D
- reg: i2c device address, usually 0x74
- #clock-cells: from common clock binding; shall be set to 2.
The first value is "0" for outputs, "1" for synthesizers.
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index 3c228b018116..3d7acab9d280 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -1,8 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Driver for Silicon Labs Si5341/Si5340 Clock generator
+ * Driver for Silicon Labs Si5340, Si5341, Si5342, Si5344 and Si5345
* Copyright (C) 2019 Topic Embedded Products
* Author: Mike Looijmans <mike.looijmans@topic.nl>
+ *
+ * The Si5341 has 10 outputs and 5 synthesizers.
+ * The Si5340 is a smaller version of the Si5341 with only 4 outputs.
+ * The Si5345 is similar to the Si5341, with the addition of fractional input
+ * dividers and automatic input selection.
+ * The Si5342 and Si5344 are smaller versions of the Si5345.
*/
#include <linux/clk.h>
@@ -18,11 +24,17 @@
#define SI5341_NUM_INPUTS 4
-#define SI5341_MAX_NUM_OUTPUTS 10
#define SI5340_MAX_NUM_OUTPUTS 4
+#define SI5341_MAX_NUM_OUTPUTS 10
+#define SI5342_MAX_NUM_OUTPUTS 2
+#define SI5344_MAX_NUM_OUTPUTS 4
+#define SI5345_MAX_NUM_OUTPUTS 10
-#define SI5341_NUM_SYNTH 5
#define SI5340_NUM_SYNTH 4
+#define SI5341_NUM_SYNTH 5
+#define SI5342_NUM_SYNTH 2
+#define SI5344_NUM_SYNTH 4
+#define SI5345_NUM_SYNTH 5
/* Range of the synthesizer fractional divider */
#define SI5341_SYNTH_N_MIN 10
@@ -65,6 +77,7 @@ struct clk_si5341 {
u64 freq_vco; /* 13500–14256 MHz */
u8 num_outputs;
u8 num_synth;
+ u16 chip_id;
};
#define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
@@ -142,6 +155,7 @@ static const char * const si5341_input_clock_names[] = {
};
/* Output configuration registers 0..9 are not quite logically organized */
+/* Also for si5345 */
static const u16 si5341_reg_output_offset[] = {
0x0108,
0x010D,
@@ -155,6 +169,7 @@ static const u16 si5341_reg_output_offset[] = {
0x013A,
};
+/* for si5340, si5342 and si5344 */
static const u16 si5340_reg_output_offset[] = {
0x0112,
0x0117,
@@ -974,12 +989,32 @@ static int si5341_probe_chip_id(struct clk_si5341 *data)
data->reg_output_offset = si5341_reg_output_offset;
data->reg_rdiv_offset = si5341_reg_rdiv_offset;
break;
+ case 0x5342:
+ data->num_outputs = SI5342_MAX_NUM_OUTPUTS;
+ data->num_synth = SI5342_NUM_SYNTH;
+ data->reg_output_offset = si5340_reg_output_offset;
+ data->reg_rdiv_offset = si5340_reg_rdiv_offset;
+ break;
+ case 0x5344:
+ data->num_outputs = SI5344_MAX_NUM_OUTPUTS;
+ data->num_synth = SI5344_NUM_SYNTH;
+ data->reg_output_offset = si5340_reg_output_offset;
+ data->reg_rdiv_offset = si5340_reg_rdiv_offset;
+ break;
+ case 0x5345:
+ data->num_outputs = SI5345_MAX_NUM_OUTPUTS;
+ data->num_synth = SI5345_NUM_SYNTH;
+ data->reg_output_offset = si5341_reg_output_offset;
+ data->reg_rdiv_offset = si5341_reg_rdiv_offset;
+ break;
default:
dev_err(&data->i2c_client->dev, "Model '%x' not supported\n",
model);
return -EINVAL;
}
+ data->chip_id = model;
+
return 0;
}
@@ -1054,6 +1089,11 @@ static const struct si5341_reg_default si5341_preamble[] = {
{ 0x0B4E, 0x1A },
};
+static const struct si5341_reg_default si5345_preamble[] = {
+ { 0x0B25, 0x00 },
+ { 0x0540, 0x01 },
+};
+
static int si5341_send_preamble(struct clk_si5341 *data)
{
int res;
@@ -1068,8 +1108,14 @@ static int si5341_send_preamble(struct clk_si5341 *data)
res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xD8 : 0xC0);
if (res < 0)
return res;
- res = si5341_write_multiple(data,
- si5341_preamble, ARRAY_SIZE(si5341_preamble));
+
+ /* The si5342..si5345 require a different preamble */
+ if (data->chip_id > 0x5341)
+ res = si5341_write_multiple(data,
+ si5345_preamble, ARRAY_SIZE(si5345_preamble));
+ else
+ res = si5341_write_multiple(data,
+ si5341_preamble, ARRAY_SIZE(si5341_preamble));
if (res < 0)
return res;
@@ -1095,6 +1141,13 @@ static int si5341_finalize_defaults(struct clk_si5341 *data)
if (res < 0)
return res;
+ /* The si5342..si5345 have an additional post-amble */
+ if (data->chip_id > 0x5341) {
+ res = regmap_write(data->regmap, 0x540, 0x0);
+ if (res < 0)
+ return res;
+ }
+
/* Datasheet does not explain these nameless registers */
res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xDB : 0xC3);
if (res < 0)
@@ -1499,6 +1552,9 @@ static int si5341_probe(struct i2c_client *client,
static const struct i2c_device_id si5341_id[] = {
{ "si5340", 0 },
{ "si5341", 1 },
+ { "si5342", 2 },
+ { "si5344", 4 },
+ { "si5345", 5 },
{ }
};
MODULE_DEVICE_TABLE(i2c, si5341_id);
@@ -1506,6 +1562,9 @@ MODULE_DEVICE_TABLE(i2c, si5341_id);
static const struct of_device_id clk_si5341_of_match[] = {
{ .compatible = "silabs,si5340" },
{ .compatible = "silabs,si5341" },
+ { .compatible = "silabs,si5342" },
+ { .compatible = "silabs,si5344" },
+ { .compatible = "silabs,si5345" },
{ }
};
MODULE_DEVICE_TABLE(of, clk_si5341_of_match);
From 3b49a25e073a956ede0da1240a55b4b834fa3a85 Mon Sep 17 00:00:00 2001
From: Krzysztof Kozlowski <krzk@kernel.org>
Date: Wed, 16 Sep 2020 18:17:39 +0200
Subject: [PATCH] clk: si5341: drop unused 'err' variable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
'err' is assigned but never read:
/drivers/clk/clk-si5341.c: In function ‘si5341_output_get_parent’:
drivers/clk/clk-si5341.c:886:6: warning: variable ‘err’ set but not used [-Wunused-but-set-variable]
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
Link: https://lore.kernel.org/r/20200916161740.14173-5-krzk@kernel.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-si5341.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index 3d7acab9d280..e0446e66fa64 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -883,11 +883,9 @@ static int si5341_output_set_parent(struct clk_hw *hw, u8 index)
static u8 si5341_output_get_parent(struct clk_hw *hw)
{
struct clk_si5341_output *output = to_clk_si5341_output(hw);
- int err;
u32 val;
- err = regmap_read(output->data->regmap,
- SI5341_OUT_MUX_SEL(output), &val);
+ regmap_read(output->data->regmap, SI5341_OUT_MUX_SEL(output), &val);
return val & 0x7;
}
From 613af2c91f66bcf1d7e7961e1d6999d1bad82888 Mon Sep 17 00:00:00 2001
From: Robert Hancock <robert.hancock@calian.com>
Date: Thu, 25 Mar 2021 13:26:36 -0600
Subject: [PATCH] clk: si5341: Wait for DEVICE_READY on startup
The Si5341 datasheet warns that before accessing any other registers,
including the PAGE register, we need to wait for the DEVICE_READY register
to indicate the device is ready, or the process of the device loading its
state from NVM can be corrupted. Wait for DEVICE_READY on startup before
continuing initialization. This is done using a raw I2C register read
prior to setting up regmap to avoid any potential unwanted automatic PAGE
register accesses from regmap at this stage.
Fixes: 3044a860fd ("clk: Add Si5341/Si5340 driver")
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-3-robert.hancock@calian.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-si5341.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index e0446e66fa64..b8a960e927bc 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -94,6 +94,7 @@ struct clk_si5341_output_config {
#define SI5341_STATUS 0x000C
#define SI5341_SOFT_RST 0x001C
#define SI5341_IN_SEL 0x0021
+#define SI5341_DEVICE_READY 0x00FE
#define SI5341_XAXB_CFG 0x090E
#define SI5341_IN_EN 0x0949
#define SI5341_INX_TO_PFD_EN 0x094A
@@ -1189,6 +1190,32 @@ static const struct regmap_range_cfg si5341_regmap_ranges[] = {
},
};
+static int si5341_wait_device_ready(struct i2c_client *client)
+{
+ int count;
+
+ /* Datasheet warns: Any attempt to read or write any register other
+ * than DEVICE_READY before DEVICE_READY reads as 0x0F may corrupt the
+ * NVM programming and may corrupt the register contents, as they are
+ * read from NVM. Note that this includes accesses to the PAGE register.
+ * Also: DEVICE_READY is available on every register page, so no page
+ * change is needed to read it.
+ * Do this outside regmap to avoid automatic PAGE register access.
+ * May take up to 300ms to complete.
+ */
+ for (count = 0; count < 15; ++count) {
+ s32 result = i2c_smbus_read_byte_data(client,
+ SI5341_DEVICE_READY);
+ if (result < 0)
+ return result;
+ if (result == 0x0F)
+ return 0;
+ msleep(20);
+ }
+ dev_err(&client->dev, "timeout waiting for DEVICE_READY\n");
+ return -EIO;
+}
+
static const struct regmap_config si5341_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -1385,6 +1412,11 @@ static int si5341_probe(struct i2c_client *client,
data->i2c_client = client;
+ /* Must be done before otherwise touching hardware */
+ err = si5341_wait_device_ready(client);
+ if (err)
+ return err;
+
for (i = 0; i < SI5341_NUM_INPUTS; ++i) {
input = devm_clk_get(&client->dev, si5341_input_clock_names[i]);
if (IS_ERR(input)) {
From 5828026e4cb11c87935f306f6a439887f96f8d1b Mon Sep 17 00:00:00 2001
From: Robert Hancock <robert.hancock@calian.com>
Date: Thu, 25 Mar 2021 13:26:37 -0600
Subject: [PATCH] clk: si5341: Avoid divide errors due to bogus register
contents
If the Si5341 is being initially programmed and has no stored NVM
configuration, some of the register contents may contain unexpected
values, such as zeros, which could cause divide by zero errors during
driver initialization. Trap errors caused by zero registers or zero clock
rates which could result in divide errors later in the code.
Fixes: 3044a860fd ("clk: Add Si5341/Si5340 driver")
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-4-robert.hancock@calian.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-si5341.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index b8a960e927bc..ac1ccec2b681 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -624,6 +624,9 @@ static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
SI5341_SYNTH_N_NUM(synth->index), &n_num, &n_den);
if (err < 0)
return err;
+ /* Check for bogus/uninitialized settings */
+ if (!n_num || !n_den)
+ return 0;
/*
* n_num and n_den are shifted left as much as possible, so to prevent
@@ -807,6 +810,9 @@ static long si5341_output_clk_round_rate(struct clk_hw *hw, unsigned long rate,
{
unsigned long r;
+ if (!rate)
+ return 0;
+
r = *parent_rate >> 1;
/* If rate is an even divisor, no changes to parent required */
@@ -835,11 +841,16 @@ static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_si5341_output *output = to_clk_si5341_output(hw);
- /* Frequency divider is (r_div + 1) * 2 */
- u32 r_div = (parent_rate / rate) >> 1;
+ u32 r_div;
int err;
u8 r[3];
+ if (!rate)
+ return -EINVAL;
+
+ /* Frequency divider is (r_div + 1) * 2 */
+ r_div = (parent_rate / rate) >> 1;
+
if (r_div <= 1)
r_div = 0;
else if (r_div >= BIT(24))
From cb6f18307dd724d286dd683222de28f75e8a0f05 Mon Sep 17 00:00:00 2001
From: Robert Hancock <robert.hancock@calian.com>
Date: Thu, 25 Mar 2021 13:26:38 -0600
Subject: [PATCH] clk: si5341: Check for input clock presence and PLL lock on
startup
After initializing the device, wait for it to report that the input
clock is present and the PLL has locked before declaring success.
Fixes: 3044a860fd ("clk: Add Si5341/Si5340 driver")
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-5-robert.hancock@calian.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-si5341.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index ac1ccec2b681..da40b90c2aa8 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -92,6 +92,9 @@ struct clk_si5341_output_config {
#define SI5341_PN_BASE 0x0002
#define SI5341_DEVICE_REV 0x0005
#define SI5341_STATUS 0x000C
+#define SI5341_LOS 0x000D
+#define SI5341_STATUS_STICKY 0x0011
+#define SI5341_LOS_STICKY 0x0012
#define SI5341_SOFT_RST 0x001C
#define SI5341_IN_SEL 0x0021
#define SI5341_DEVICE_READY 0x00FE
@@ -99,6 +102,12 @@ struct clk_si5341_output_config {
#define SI5341_IN_EN 0x0949
#define SI5341_INX_TO_PFD_EN 0x094A
+/* Status bits */
+#define SI5341_STATUS_SYSINCAL BIT(0)
+#define SI5341_STATUS_LOSXAXB BIT(1)
+#define SI5341_STATUS_LOSREF BIT(2)
+#define SI5341_STATUS_LOL BIT(3)
+
/* Input selection */
#define SI5341_IN_SEL_MASK 0x06
#define SI5341_IN_SEL_SHIFT 1
@@ -1416,6 +1425,7 @@ static int si5341_probe(struct i2c_client *client,
unsigned int i;
struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS];
bool initialization_required;
+ u32 status;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -1583,6 +1593,22 @@ static int si5341_probe(struct i2c_client *client,
return err;
}
+ /* wait for device to report input clock present and PLL lock */
+ err = regmap_read_poll_timeout(data->regmap, SI5341_STATUS, status,
+ !(status & (SI5341_STATUS_LOSREF | SI5341_STATUS_LOL)),
+ 10000, 250000);
+ if (err) {
+ dev_err(&client->dev, "Error waiting for input clock or PLL lock\n");
+ return err;
+ }
+
+ /* clear sticky alarm bits from initialization */
+ err = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0);
+ if (err) {
+ dev_err(&client->dev, "unable to clear sticky status\n");
+ return err;
+ }
+
/* Free the names, clk framework makes copies */
for (i = 0; i < data->num_synth; ++i)
devm_kfree(&client->dev, (void *)synth_clock_names[i]);
From 83ee2bcb2101d82d98e3ccb7737cc748a8ab86ad Mon Sep 17 00:00:00 2001
From: Robert Hancock <robert.hancock@calian.com>
Date: Thu, 25 Mar 2021 13:26:39 -0600
Subject: [PATCH] clk: si5341: Update initialization magic
Update the default register settings to include the VCO_RESET_CALCODE
settings (set by the SiLabs ClockBuilder software but not described in
the datasheet). Also update part of the initialization sequence to match
ClockBuilder and the datasheet.
Fixes: 3044a860fd ("clk: Add Si5341/Si5340 driver")
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-6-robert.hancock@calian.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-si5341.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index da40b90c2aa8..eb22f4fdbc6b 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -350,6 +350,8 @@ static const struct si5341_reg_default si5341_reg_defaults[] = {
{ 0x094A, 0x00 }, /* INx_TO_PFD_EN (disabled) */
{ 0x0A02, 0x00 }, /* Not in datasheet */
{ 0x0B44, 0x0F }, /* PDIV_ENB (datasheet does not mention what it is) */
+ { 0x0B57, 0x10 }, /* VCO_RESET_CALCODE (not described in datasheet) */
+ { 0x0B58, 0x05 }, /* VCO_RESET_CALCODE (not described in datasheet) */
};
/* Read and interpret a 44-bit followed by a 32-bit value in the regmap */
@@ -1104,7 +1106,7 @@ static const struct si5341_reg_default si5341_preamble[] = {
{ 0x0B25, 0x00 },
{ 0x0502, 0x01 },
{ 0x0505, 0x03 },
- { 0x0957, 0x1F },
+ { 0x0957, 0x17 },
{ 0x0B4E, 0x1A },
};
From c450cc861bbd072ddc9eda6dd099da0d443b8345 Mon Sep 17 00:00:00 2001
From: Robert Hancock <robert.hancock@calian.com>
Date: Thu, 25 Mar 2021 13:26:41 -0600
Subject: [PATCH] clk: si5341: Add silabs,xaxb-ext-clk property
Add a property to allow specifying that the device XA/XB pins are used for
an external clock input rather than for a clock crystal.
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-8-robert.hancock@calian.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-si5341.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index 28ac7085f362..c5ab4a5ae6a5 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -80,6 +80,7 @@ struct clk_si5341 {
u8 num_outputs;
u8 num_synth;
u16 chip_id;
+ bool xaxb_ext_clk;
};
#define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
@@ -529,9 +530,11 @@ static int si5341_clk_reparent(struct clk_si5341 *data, u8 index)
if (err < 0)
return err;
- /* Power up XTAL oscillator and buffer */
+ /* Power up XTAL oscillator and buffer, select clock mode */
err = regmap_update_bits(data->regmap, SI5341_XAXB_CFG,
- SI5341_XAXB_CFG_PDNB, SI5341_XAXB_CFG_PDNB);
+ SI5341_XAXB_CFG_PDNB | SI5341_XAXB_CFG_EXTCLK_EN,
+ SI5341_XAXB_CFG_PDNB | (data->xaxb_ext_clk ?
+ SI5341_XAXB_CFG_EXTCLK_EN : 0));
if (err < 0)
return err;
}
@@ -1539,6 +1542,8 @@ static int si5341_probe(struct i2c_client *client,
initialization_required = !err;
}
+ data->xaxb_ext_clk = of_property_read_bool(client->dev.of_node,
+ "silabs,xaxb-ext-clk");
if (initialization_required) {
/* Populate the regmap cache in preparation for "cache only" */
From 1292641481cb8b484e03bfac54efbecbb3ddb6bb Mon Sep 17 00:00:00 2001
From: Robert Hancock <robert.hancock@calian.com>
Date: Thu, 25 Mar 2021 13:26:42 -0600
Subject: [PATCH] clk: si5341: Add silabs,iovdd-33 property
Add a property to allow specifying that the external I2C IO pins are using
3.3V voltage thresholds rather than 1.8V.
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-9-robert.hancock@calian.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-si5341.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index c5ab4a5ae6a5..d4aa67a4dc66 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -81,6 +81,7 @@ struct clk_si5341 {
u8 num_synth;
u16 chip_id;
bool xaxb_ext_clk;
+ bool iovdd_33;
};
#define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
@@ -103,6 +104,7 @@ struct clk_si5341_output_config {
#define SI5341_IN_SEL 0x0021
#define SI5341_DEVICE_READY 0x00FE
#define SI5341_XAXB_CFG 0x090E
+#define SI5341_IO_VDD_SEL 0x0943
#define SI5341_IN_EN 0x0949
#define SI5341_INX_TO_PFD_EN 0x094A
@@ -351,7 +353,6 @@ static const struct si5341_reg_default si5341_reg_defaults[] = {
{ 0x0804, 0x00 }, /* Not in datasheet */
{ 0x090E, 0x02 }, /* XAXB_EXTCLK_EN=0 XAXB_PDNB=1 (use XTAL) */
{ 0x091C, 0x04 }, /* ZDM_EN=4 (Normal mode) */
- { 0x0943, 0x00 }, /* IO_VDD_SEL=0 (0=1v8, use 1=3v3) */
{ 0x0949, 0x00 }, /* IN_EN (disable input clocks) */
{ 0x094A, 0x00 }, /* INx_TO_PFD_EN (disabled) */
{ 0x0A02, 0x00 }, /* Not in datasheet */
@@ -1160,6 +1161,11 @@ static int si5341_finalize_defaults(struct clk_si5341 *data)
int res;
u32 revision;
+ res = regmap_write(data->regmap, SI5341_IO_VDD_SEL,
+ data->iovdd_33 ? 1 : 0);
+ if (res < 0)
+ return res;
+
res = regmap_read(data->regmap, SI5341_DEVICE_REV, &revision);
if (res < 0)
return res;
@@ -1544,6 +1550,8 @@ static int si5341_probe(struct i2c_client *client,
}
data->xaxb_ext_clk = of_property_read_bool(client->dev.of_node,
"silabs,xaxb-ext-clk");
+ data->iovdd_33 = of_property_read_bool(client->dev.of_node,
+ "silabs,iovdd-33");
if (initialization_required) {
/* Populate the regmap cache in preparation for "cache only" */
From 11e16d5abda5dd6d00bc2f17565b5c5c9e25c593 Mon Sep 17 00:00:00 2001
From: Robert Hancock <robert.hancock@calian.com>
Date: Thu, 25 Mar 2021 13:26:43 -0600
Subject: [PATCH] clk: si5341: Add sysfs properties to allow checking/resetting
device faults
Add sysfs property files to allow viewing the current and latched states of
the input present and PLL lock bits, and allow resetting the latched fault
state. This allows manual checks or automated userspace polling for faults
occurring after initialization.
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-10-robert.hancock@calian.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
drivers/clk/clk-si5341.c | 96 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index d4aa67a4dc66..57ae183982d8 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -1457,6 +1457,94 @@ static int si5341_clk_select_active_input(struct clk_si5341 *data)
return res;
}
+static ssize_t input_present_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ u32 status;
+ int res = regmap_read(data->regmap, SI5341_STATUS, &status);
+
+ if (res < 0)
+ return res;
+ res = !(status & SI5341_STATUS_LOSREF);
+ return snprintf(buf, PAGE_SIZE, "%d\n", res);
+}
+static DEVICE_ATTR_RO(input_present);
+
+static ssize_t input_present_sticky_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ u32 status;
+ int res = regmap_read(data->regmap, SI5341_STATUS_STICKY, &status);
+
+ if (res < 0)
+ return res;
+ res = !(status & SI5341_STATUS_LOSREF);
+ return snprintf(buf, PAGE_SIZE, "%d\n", res);
+}
+static DEVICE_ATTR_RO(input_present_sticky);
+
+static ssize_t pll_locked_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ u32 status;
+ int res = regmap_read(data->regmap, SI5341_STATUS, &status);
+
+ if (res < 0)
+ return res;
+ res = !(status & SI5341_STATUS_LOL);
+ return snprintf(buf, PAGE_SIZE, "%d\n", res);
+}
+static DEVICE_ATTR_RO(pll_locked);
+
+static ssize_t pll_locked_sticky_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ u32 status;
+ int res = regmap_read(data->regmap, SI5341_STATUS_STICKY, &status);
+
+ if (res < 0)
+ return res;
+ res = !(status & SI5341_STATUS_LOL);
+ return snprintf(buf, PAGE_SIZE, "%d\n", res);
+}
+static DEVICE_ATTR_RO(pll_locked_sticky);
+
+static ssize_t clear_sticky_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct clk_si5341 *data = dev_get_drvdata(dev);
+ long val;
+
+ if (kstrtol(buf, 10, &val))
+ return -EINVAL;
+ if (val) {
+ int res = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0);
+
+ if (res < 0)
+ return res;
+ }
+ return count;
+}
+static DEVICE_ATTR_WO(clear_sticky);
+
+static const struct attribute *si5341_attributes[] = {
+ &dev_attr_input_present.attr,
+ &dev_attr_input_present_sticky.attr,
+ &dev_attr_pll_locked.attr,
+ &dev_attr_pll_locked_sticky.attr,
+ &dev_attr_clear_sticky.attr,
+ NULL
+};
+
static int si5341_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1687,6 +1775,12 @@ static int si5341_probe(struct i2c_client *client,
goto cleanup;
}
+ err = sysfs_create_files(&client->dev.kobj, si5341_attributes);
+ if (err) {
+ dev_err(&client->dev, "unable to create sysfs files\n");
+ goto cleanup;
+ }
+
/* Free the names, clk framework makes copies */
for (i = 0; i < data->num_synth; ++i)
devm_kfree(&client->dev, (void *)synth_clock_names[i]);
@@ -1706,6 +1800,8 @@ static int si5341_remove(struct i2c_client *client)
struct clk_si5341 *data = i2c_get_clientdata(client);
int i;
+ sysfs_remove_files(&client->dev.kobj, si5341_attributes);
+
for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
if (data->clk[i].vddo_reg)
regulator_disable(data->clk[i].vddo_reg);
From cb2d5d9e66e780444a759210c18f5a3e66de953a Mon Sep 17 00:00:00 2001
From: Robert Hancock <robert.hancock@calian.com>
Date: Thu, 25 Mar 2021 13:26:35 -0600
Subject: [PATCH] dt-bindings: clock: clk-si5341: Add new attributes
Add new silabs,xaxb-ext-clk and silabs,iovdd-33 properties.
Changed vdd-supply on top-level node to optional since it is not actually
used by the driver.
Removed vdd-supply from output sub-nodes, as it was not supported by the
driver and it is not easily possible to support this in that location with
the kernel regulator infrastructure. Changed to have vddoX-supply
attributes for each output on the top-level device node.
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
Link: https://lore.kernel.org/r/20210325192643.2190069-2-robert.hancock@calian.com
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
---
.../devicetree/bindings/clock/silabs,si5341.txt | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5341.txt b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
index 504cce3abe46..ce55aba0ce22 100644
--- a/Documentation/devicetree/bindings/clock/silabs,si5341.txt
+++ b/Documentation/devicetree/bindings/clock/silabs,si5341.txt
@@ -24,9 +24,8 @@ it.
The device type, speed grade and revision are determined runtime by probing.
-The driver currently only supports XTAL input mode, and does not support any
-fancy input configurations. They can still be programmed into the chip and
-the driver will leave them "as is".
+The driver currently does not support any fancy input configurations. They can
+still be programmed into the chip and the driver will leave them "as is".
==I2C device node==
@@ -45,9 +44,9 @@ Required properties:
corresponding to inputs. Use a fixed clock for the "xtal" input.
At least one must be present.
- clock-names: One of: "xtal", "in0", "in1", "in2"
-- vdd-supply: Regulator node for VDD
Optional properties:
+- vdd-supply: Regulator node for VDD
- vdda-supply: Regulator node for VDDA
- vdds-supply: Regulator node for VDDS
- silabs,pll-m-num, silabs,pll-m-den: Numerator and denominator for PLL
@@ -60,7 +59,14 @@ Optional properties:
be initialized, and always performs the soft-reset routine. Since this will
temporarily stop all output clocks, don't do this if the chip is generating
the CPU clock for example.
+- silabs,xaxb-ext-clk: When present, indicates that the XA/XB pins are used
+ in EXTCLK (external reference clock) rather than XTAL (crystal) mode.
- interrupts: Interrupt for INTRb pin.
+- silabs,iovdd-33: When present, indicates that the I2C lines are using 3.3V
+ rather than 1.8V thresholds.
+- vddoX-supply (where X is an output index): Regulator node for VDDO for the
+ specified output. The driver selects the output VDD_SEL setting based on this
+ voltage.
- #address-cells: shall be set to 1.
- #size-cells: shall be set to 0.
@@ -77,8 +83,6 @@ Required child node properties:
- reg: number of clock output.
Optional child node properties:
-- vdd-supply: Regulator node for VDD for this output. The driver selects default
- values for common-mode and amplitude based on the voltage.
- silabs,format: Output format, one of:
1 = differential (defaults to LVDS levels)
2 = low-power (defaults to HCSL levels)
......@@ -2,3 +2,4 @@ CONFIG_XILINX_PHY=y
CONFIG_SENSORS_MAX6639=y
CONFIG_SENSORS_LM75=y
CONFIG_SENSORS_IRPS5401=y
CONFIG_COMMON_CLK_SI5341=y
......@@ -4,4 +4,19 @@ SRC_URI += "file://devtool-fragment.cfg \
file://0001-net-xilinx_phy-Add-flag-to-reset-after-clock-enable.patch \
file://0002-net-macb-Handle-phy-reset-for-PCS-PMA-IP.patch \
file://0003-hwmon-pmbus-Add-Infineon-IRPS5401-driver.patch \
file://0004-clk-Add-Si5341-Si5340-driver.patch \
file://0005-clk-Si5341-Si5340-remove-redundant-assignment-to-n_d.patch \
file://0006-clk-clk-si5341-Support-multiple-input-ports.patch \
file://0007-dt-bindings-clock-Add-silabs-si5341.patch \
file://0008-clk-clk-si5341-Add-support-for-the-Si5345-series.patch \
file://0009-clk-si5341-drop-unused-err-variable.patch \
file://0010-clk-si5341-Wait-for-DEVICE_READY-on-startup.patch \
file://0011-clk-si5341-Avoid-divide-errors-due-to-bogus-register.patch \
file://0012-clk-si5341-Check-for-input-clock-presence-and-PLL-lo.patch \
file://0013-clk-si5341-Update-initialization-magic.patch \
file://0014-clk-si5341-Allow-different-output-VDD_SEL-values.patch \
file://0015-clk-si5341-Add-silabs-xaxb-ext-clk-property.patch \
file://0016-clk-si5341-Add-silabs-iovdd-33-property.patch \
file://0017-clk-si5341-Add-sysfs-properties-to-allow-checking-re.patch \
file://0018-dt-bindings-clock-clk-si5341-Add-new-attributes.patch \
"
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