2021-06-14 06:59:56

by Alexandru Tachici

[permalink] [raw]
Subject: [PATCH v2 0/2] clk: ad9545: Add support

From: Alexandru Tachici <[email protected]>

Add support for AD9545 Quad Input, 10-Output, Dual DPLL/IEEE 1588,
1 pps Synchronizer and Jitter Cleaner.

At the core of the device there are PLL blocks. Each block consists
of one DPLL and one APLL. The DPLL can be fed timestamps from one of
the 4 reference input dividers or one of the two auxiliary NCOs.

The APLL takes the output of the DPLL and up-converts this
frequency to 1.2-2.0 GHZ. First 6 output dividers are receiving
clock from APLL0 and last 4 outputs are receiving clock from APLL1.

Current approach is to register under common clock framework,
depending whether they are mentioned in the device-tree,
any of the used references input dividers, the two auxiliary
NCOs, PLL blocks, output dividers.

A clock tree example:
Ref-B
Ref-B-Div
PLL0
Q0C-div
PLL1
Q1A-div
Q1B-div

Alexandru Tachici (2):
clk: ad9545: Add support
dt-bindings: clock: ad9545: Add documentation

Changelog v1 -> v2:
- allow uHz DPLL loop bandwidth in DT
- allow user to set different tub fill/drain rates per DPLL from DT
for improved locking detection
- added reference priorities, DPLLs now can have multiple parents selected based on
the validity of the reference in question and priority
- added fast ACQ process that can be configured in the DT
- fixed DT bindings errors
- added support for system clock compensation

.../devicetree/bindings/clock/clk-ad9545.yaml | 556 ++++
drivers/clk/Kconfig | 6 +
drivers/clk/Makefile | 1 +
drivers/clk/adi/Kconfig | 29 +
drivers/clk/adi/Makefile | 9 +
drivers/clk/adi/clk-ad9545-i2c.c | 62 +
drivers/clk/adi/clk-ad9545-spi.c | 76 +
drivers/clk/adi/clk-ad9545.c | 2428 +++++++++++++++++
drivers/clk/adi/clk-ad9545.h | 16 +
include/dt-bindings/clock/ad9545.h | 69 +
10 files changed, 3252 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/clk-ad9545.yaml
create mode 100644 drivers/clk/adi/Kconfig
create mode 100644 drivers/clk/adi/Makefile
create mode 100644 drivers/clk/adi/clk-ad9545-i2c.c
create mode 100644 drivers/clk/adi/clk-ad9545-spi.c
create mode 100644 drivers/clk/adi/clk-ad9545.c
create mode 100644 drivers/clk/adi/clk-ad9545.h
create mode 100644 include/dt-bindings/clock/ad9545.h

--
2.25.1


2021-06-14 07:02:43

by Alexandru Tachici

[permalink] [raw]
Subject: [PATCH v2 1/2] clk: ad9545: Add support

From: Alexandru Tachici <[email protected]>

Add support for AD9545 Quad Input, 10-Output, Dual DPLL/IEEE 1588,
1 pps Synchronizer and Jitter Cleaner.

Signed-off-by: Alexandru Tachici <[email protected]>
---
drivers/clk/Kconfig | 6 +
drivers/clk/Makefile | 1 +
drivers/clk/adi/Kconfig | 29 +
drivers/clk/adi/Makefile | 9 +
drivers/clk/adi/clk-ad9545-i2c.c | 62 +
drivers/clk/adi/clk-ad9545-spi.c | 76 +
drivers/clk/adi/clk-ad9545.c | 2428 ++++++++++++++++++++++++++++++
drivers/clk/adi/clk-ad9545.h | 16 +
8 files changed, 2627 insertions(+)
create mode 100644 drivers/clk/adi/Kconfig
create mode 100644 drivers/clk/adi/Makefile
create mode 100644 drivers/clk/adi/clk-ad9545-i2c.c
create mode 100644 drivers/clk/adi/clk-ad9545-spi.c
create mode 100644 drivers/clk/adi/clk-ad9545.c
create mode 100644 drivers/clk/adi/clk-ad9545.h

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index e80918be8e9c..c39dfb6a6b66 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -38,6 +38,11 @@ menuconfig COMMON_CLK

if COMMON_CLK

+config COMMON_CLK_ADI
+ def_bool COMMON_CLK
+ help
+ Support for Analog Devices clock providers.
+
config COMMON_CLK_WM831X
tristate "Clock driver for WM831x/2x PMICs"
depends on MFD_WM831X
@@ -377,6 +382,7 @@ config COMMON_CLK_K210
Support for the Canaan Kendryte K210 RISC-V SoC clocks.

source "drivers/clk/actions/Kconfig"
+source "drivers/clk/adi/Kconfig"
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/baikal-t1/Kconfig"
source "drivers/clk/bcm/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 5f06879d7fe9..181064b6e593 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o

# please keep this section sorted lexicographically by directory path name
obj-y += actions/
+obj-$(CONFIG_COMMON_CLK_ADI) += adi/
obj-y += analogbits/
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_ARTPEC) += axis/
diff --git a/drivers/clk/adi/Kconfig b/drivers/clk/adi/Kconfig
new file mode 100644
index 000000000000..768b8227f336
--- /dev/null
+++ b/drivers/clk/adi/Kconfig
@@ -0,0 +1,29 @@
+#
+# Analog Devices Clock Drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Analog Devices Clock Drivers"
+
+config COMMON_CLK_AD9545
+ tristate
+
+config COMMON_CLK_AD9545_I2C
+ tristate "Analog Devices AD9545 via I2C"
+ depends on REGMAP_I2C
+ select COMMON_CLK_AD9545
+ help
+ Say yes here to build support for Analog Devices AD9545
+ Quad Input, 10-Output, Dual DPLL/IEEE 1588,
+ 1 pps Synchronizer and Jitter Cleaner via I2C
+
+config COMMON_CLK_AD9545_SPI
+ tristate "Analog Devices AD9545 via SPI"
+ depends on REGMAP_SPI
+ select COMMON_CLK_AD9545
+ help
+ Say yes here to build support for Analog Devices AD9545
+ Quad Input, 10-Output, Dual DPLL/IEEE 1588,
+ 1 pps Synchronizer and Jitter Cleaner via SPI
+
+endmenu
diff --git a/drivers/clk/adi/Makefile b/drivers/clk/adi/Makefile
new file mode 100644
index 000000000000..7ba1fded3013
--- /dev/null
+++ b/drivers/clk/adi/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+#
+# Makefile for AD9545 Network Clock Generator/Synchronizer
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_COMMON_CLK_AD9545) += clk-ad9545.o
+obj-$(CONFIG_COMMON_CLK_AD9545_I2C) += clk-ad9545-i2c.o
+obj-$(CONFIG_COMMON_CLK_AD9545_SPI) += clk-ad9545-spi.o
diff --git a/drivers/clk/adi/clk-ad9545-i2c.c b/drivers/clk/adi/clk-ad9545-i2c.c
new file mode 100644
index 000000000000..c85326b3cdd2
--- /dev/null
+++ b/drivers/clk/adi/clk-ad9545-i2c.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * AD9545 Network Clock Generator/Synchronizer
+ *
+ * Copyright 2020 Analog Devices Inc.
+ */
+
+#include "clk-ad9545.h"
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+static const struct regmap_config ad9545_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0x3A3B,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int ad9545_i2c_probe(struct i2c_client *client)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &ad9545_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "devm_regmap_init_i2c failed!\n");
+ return PTR_ERR(regmap);
+ }
+
+ return ad9545_probe(&client->dev, regmap);
+}
+
+static const struct of_device_id ad9545_i2c_of_match[] = {
+ { .compatible = "adi,ad9545" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad9545_i2c_of_match);
+
+static const struct i2c_device_id ad9545_i2c_id[] = {
+ {"ad9545"},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ad9545_i2c_id);
+
+static struct i2c_driver ad9545_i2c_driver = {
+ .driver = {
+ .name = "ad9545",
+ .of_match_table = ad9545_i2c_of_match,
+ },
+ .probe_new = ad9545_i2c_probe,
+ .id_table = ad9545_i2c_id,
+};
+module_i2c_driver(ad9545_i2c_driver);
+
+MODULE_AUTHOR("Alexandru Tachici <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices AD9545 I2C");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/clk/adi/clk-ad9545-spi.c b/drivers/clk/adi/clk-ad9545-spi.c
new file mode 100644
index 000000000000..b0f9f59e6dea
--- /dev/null
+++ b/drivers/clk/adi/clk-ad9545-spi.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * AD9545 Network Clock Generator/Synchronizer
+ *
+ * Copyright 2020 Analog Devices Inc.
+ */
+
+#include "clk-ad9545.h"
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#define AD9545_CONFIG_0 0x0000
+
+#define AD9545_4WIRE_SPI 0x3
+#define AD9545_4WIRE_SPI_MSK GENMASK(4, 3)
+
+static const struct regmap_config ad9545_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0x3A3B,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int ad9545_spi_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = devm_regmap_init_spi(spi, &ad9545_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "devm_regmap_init_spi failed!\n");
+ return PTR_ERR(regmap);
+ }
+
+ if (!(spi->mode & SPI_3WIRE)) {
+ ret = regmap_write(regmap, AD9545_CONFIG_0,
+ FIELD_PREP(AD9545_4WIRE_SPI_MSK, AD9545_4WIRE_SPI));
+ if (ret < 0)
+ return ret;
+ }
+
+ return ad9545_probe(&spi->dev, regmap);
+}
+
+static const struct of_device_id ad9545_spi_of_match[] = {
+ { .compatible = "adi,ad9545" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad9545_spi_of_match);
+
+static const struct spi_device_id ad9545_spi_id[] = {
+ {"ad9545", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad9545_spi_id);
+
+static struct spi_driver ad9545_spi_driver = {
+ .driver = {
+ .name = "ad9545",
+ .of_match_table = ad9545_spi_of_match,
+ },
+ .probe = ad9545_spi_probe,
+ .id_table = ad9545_spi_id,
+};
+module_spi_driver(ad9545_spi_driver);
+
+MODULE_AUTHOR("Alexandru Tachici <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices AD9545 SPI");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/clk/adi/clk-ad9545.c b/drivers/clk/adi/clk-ad9545.c
new file mode 100644
index 000000000000..b678b11fcd15
--- /dev/null
+++ b/drivers/clk/adi/clk-ad9545.c
@@ -0,0 +1,2428 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+/*
+ * AD9545 Network Clock Generator/Synchronizer
+ *
+ * Copyright 2020 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/rational.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/ad9545.h>
+
+#define AD9545_CONFIG_0 0x0000
+#define AD9545_PRODUCT_ID_LOW 0x0004
+#define AD9545_PRODUCT_ID_HIGH 0x0005
+#define AD9545_IO_UPDATE 0x000F
+#define AD9545_M0_PIN 0x0102
+#define AD9545_CHIP_ID 0x0121
+#define AD9545_SYS_CLK_FB_DIV 0x0200
+#define AD9545_SYS_CLK_INPUT 0x0201
+#define AD9545_SYS_CLK_REF_FREQ 0x0202
+#define AD9545_SYS_STABILITY_T 0x0207
+#define AD9545_COMPENSATE_TDCS 0x0280
+#define AD9545_COMPENSATE_DPLL 0x0282
+#define AD9545_AUX_DPLL_CHANGE_LIMIT 0x0283
+#define AD9545_AUX_DPLL_SOURCE 0x0284
+#define AD9545_AUX_DPLL_LOOP_BW 0x0285
+#define AD9545_REF_A_CTRL 0x0300
+#define AD9545_REF_A_RDIV 0x0400
+#define AD9545_REF_A_PERIOD 0x0404
+#define AD9545_REF_A_OFFSET_LIMIT 0x040C
+#define AD9545_REF_A_MONITOR_HYST 0x040F
+#define AD9545_PHASE_LOCK_THRESH 0x0800
+#define AD9545_PHASE_LOCK_FILL_RATE 0x0803
+#define AD9545_PHASE_LOCK_DRAIN_RATE 0x0804
+#define AD9545_FREQ_LOCK_THRESH 0x0805
+#define AD9545_FREQ_LOCK_FILL_RATE 0x0808
+#define AD9545_FREQ_LOCK_DRAIN_RATE 0x0809
+#define AD9545_DPLL0_FTW 0x1000
+#define AD9545_DRIVER_0A_CONF 0x10D7
+#define AD9545_SYNC_CTRL0 0x10DB
+#define AD9545_APLL0_M_DIV 0x1081
+#define AD9545_Q0A_DIV 0x1100
+#define AD9545_Q0A_PHASE 0x1104
+#define AD9545_Q0A_PHASE_CONF 0x1108
+#define AD9545_DPLL0_EN 0x1200
+#define AD9545_DPLL0_SOURCE 0x1201
+#define AD9545_DPLL0_LOOP_BW 0x1204
+#define AD9545_DPLL0_N_DIV 0x120C
+#define AD9545_DPLL0_FRAC 0x1210
+#define AD9545_DPLL0_MOD 0x1213
+#define AD9545_DPLL0_FAST_L1 0x1216
+#define AD9545_DPLL0_FAST_L2 0x1217
+#define AD9545_DRIVER_1A_CONF 0x14D7
+#define AD9545_Q1A_DIV 0x1500
+#define AD9545_Q1A_PHASE 0x1504
+#define AD9545_Q1A_PHASE_CONF 0x1508
+#define AD9545_CALIB_CLK 0x2000
+#define AD9545_POWER_DOWN_REF 0x2001
+#define AD9545_PWR_CALIB_CH0 0x2100
+#define AD9545_CTRL_CH0 0x2101
+#define AD9545_DIV_OPS_Q0A 0x2102
+#define AD9545_DPLL0_MODE 0x2105
+#define AD9545_DPLL0_FAST_MODE 0x2106
+#define AD9545_DIV_OPS_Q1A 0x2202
+#define AD9545_NCO0_FREQ 0x2805
+#define AD9545_TDC0_DIV 0x2A00
+#define AD9545_TDC0_PERIOD 0x2A01
+#define AD9545_PLL_STATUS 0x3001
+#define AD9545_MISC 0x3002
+#define AD9545_REFA_STATUS 0x3005
+#define AD9545_PLL0_STATUS 0x3100
+
+#define AD9545_REF_CTRL_DIF_MSK GENMASK(3, 2)
+#define AD9545_REF_CTRL_REFA_MSK GENMASK(5, 4)
+#define AD9545_REF_CTRL_REFAA_MSK GENMASK(7, 6)
+
+#define AD9545_UPDATE_REGS 0x1
+#define AD9545_RESET_REGS 0x81
+
+#define AD9545_MX_PIN(x) (AD9545_M0_PIN + (x))
+
+#define AD9545_SYNC_CTRLX(x) (AD9545_SYNC_CTRL0 + ((x) * 0x400))
+#define AD9545_REF_X_RDIV(x) (AD9545_REF_A_RDIV + ((x) * 0x20))
+#define AD9545_REF_X_PERIOD(x) (AD9545_REF_A_PERIOD + ((x) * 0x20))
+#define AD9545_REF_X_OFFSET_LIMIT(x) (AD9545_REF_A_OFFSET_LIMIT + ((x) * 0x20))
+#define AD9545_REF_X_MONITOR_HYST(x) (AD9545_REF_A_MONITOR_HYST + ((x) * 0x20))
+#define AD9545_REF_X_PHASE_LOCK_FILL(x) (AD9545_PHASE_LOCK_FILL_RATE + ((x) * 0x20))
+#define AD9545_REF_X_PHASE_LOCK_DRAIN(x) (AD9545_PHASE_LOCK_DRAIN_RATE + ((x) * 0x20))
+#define AD9545_REF_X_FREQ_LOCK_FILL(x) (AD9545_FREQ_LOCK_FILL_RATE + ((x) * 0x20))
+#define AD9545_REF_X_FREQ_LOCK_DRAIN(x) (AD9545_FREQ_LOCK_DRAIN_RATE + ((x) * 0x20))
+
+#define AD9545_SOURCEX_PHASE_THRESH(x) (AD9545_PHASE_LOCK_THRESH + ((x) * 0x20))
+#define AD9545_SOURCEX_FREQ_THRESH(x) (AD9545_FREQ_LOCK_THRESH + ((x) * 0x20))
+#define AD9545_NCOX_PHASE_THRESH(x) (AD9545_SOURCEX_PHASE_THRESH((x) + 4))
+#define AD9545_NCOX_FREQ_THRESH(x) (AD9545_SOURCEX_FREQ_THRESH((x) + 4))
+
+#define AD9545_APLLX_M_DIV(x) (AD9545_APLL0_M_DIV + ((x) * 0x400))
+
+#define AD9545_Q0_DIV(x) (AD9545_Q0A_DIV + ((x) * 0x9))
+#define AD9545_Q1_DIV(x) (AD9545_Q1A_DIV + ((x) * 0x9))
+#define AD9545_QX_DIV(x) ({ \
+ typeof(x) x_ = (x); \
+ \
+ (x_ > 5) ? AD9545_Q1_DIV(x_ - 6) : AD9545_Q0_DIV(x_); \
+})
+
+#define AD9545_Q0_PHASE(x) (AD9545_Q0A_PHASE + ((x) * 0x9))
+#define AD9545_Q1_PHASE(x) (AD9545_Q1A_PHASE + ((x) * 0x9))
+#define AD9545_QX_PHASE(x) ({ \
+ typeof(x) x_ = (x); \
+ \
+ (x_ > 5) ? AD9545_Q1_PHASE(x_ - 6) : AD9545_Q0_PHASE(x_); \
+})
+
+#define AD9545_Q0_PHASE_CONF(x) (AD9545_Q0A_PHASE_CONF + ((x) * 0x9))
+#define AD9545_Q1_PHASE_CONF(x) (AD9545_Q1A_PHASE_CONF + ((x) * 0x9))
+#define AD9545_QX_PHASE_CONF(x) ({ \
+ typeof(x) x_ = (x); \
+ \
+ (x_ > 5) ? AD9545_Q1_PHASE_CONF(x_ - 6) : AD9545_Q0_PHASE_CONF(x_); \
+})
+
+#define AD9545_DPLLX_FTW(x) (AD9545_DPLL0_FTW + ((x) * 0x400))
+#define AD9545_DPLLX_EN(x, y) (AD9545_DPLL0_EN + ((x) * 0x400) + ((y) * 0x20))
+#define AD9545_DPLLX_SOURCE(x, y) (AD9545_DPLL0_SOURCE + ((x) * 0x400) + ((y) * 0x20))
+#define AD9545_DPLLX_LOOP_BW(x, y) (AD9545_DPLL0_LOOP_BW + ((x) * 0x400) + ((y) * 0x20))
+#define AD9545_DPLLX_N_DIV(x, y) (AD9545_DPLL0_N_DIV + ((x) * 0x400) + ((y) * 0x20))
+#define AD9545_DPLLX_FRAC_DIV(x, y) (AD9545_DPLL0_FRAC + ((x) * 0x400) + ((y) * 0x20))
+#define AD9545_DPLLX_MOD_DIV(x, y) (AD9545_DPLL0_MOD + ((x) * 0x400) + ((y) * 0x20))
+#define AD9545_DPLLX_FAST_L1(x, y) (AD9545_DPLL0_FAST_L1 + ((x) * 0x400) + ((y) * 0x20))
+#define AD9545_DPLLX_FAST_L2(x, y) (AD9545_DPLL0_FAST_L2 + ((x) * 0x400) + ((y) * 0x20))
+
+#define AD9545_DIV_OPS_Q0(x) (AD9545_DIV_OPS_Q0A + (x))
+#define AD9545_DIV_OPS_Q1(x) (AD9545_DIV_OPS_Q1A + (x))
+#define AD9545_DIV_OPS_QX(x) ({ \
+ typeof(x) x_ = (x) / 2; \
+ \
+ (x_ > 2) ? AD9545_DIV_OPS_Q1(x_ - 3) : AD9545_DIV_OPS_Q0(x_); \
+})
+
+#define AD9545_PWR_CALIB_CHX(x) (AD9545_PWR_CALIB_CH0 + ((x) * 0x100))
+#define AD9545_PLLX_STATUS(x) (AD9545_PLL0_STATUS + ((x) * 0x100))
+#define AD9545_DPLLX_FAST_MODE(x) (AD9545_DPLL0_FAST_MODE + ((x) * 0x100))
+#define AD9545_REFX_STATUS(x) (AD9545_REFA_STATUS + (x))
+
+#define AD9545_PROFILE_SEL_MODE_MSK GENMASK(3, 2)
+#define AD9545_PROFILE_SEL_MODE(x) FIELD_PREP(AD9545_PROFILE_SEL_MODE_MSK, x)
+
+#define AD9545_NCOX_FREQ(x) (AD9545_NCO0_FREQ + ((x) * 0x40))
+
+#define AD9545_TDCX_DIV(x) (AD9545_TDC0_DIV + ((x) * 0x9))
+#define AD9545_TDCX_PERIOD(x) (AD9545_TDC0_PERIOD + ((x) * 0x9))
+
+/* AD9545 MX PIN bitfields */
+#define AD9545_MX_TO_TDCX(x) (0x30 + (x))
+
+/* AD9545 COMPENSATE TDCS bitfields */
+#define AD9545_COMPENSATE_TDCS_VIA_AUX_DPLL 0x4
+
+/* AD9545 COMPENSATE DPLL bitfields */
+#define AD9545_COMPNESATE_VIA_AUX_DPLL 0x44
+
+/* define AD9545_DPLLX_EN bitfields */
+#define AD9545_EN_PROFILE_MSK BIT(0)
+#define AD9545_SEL_PRIORITY_MSK GENMASK(5, 1)
+
+/* AD9545_PWR_CALIB_CHX bitfields */
+#define AD9545_PWR_DOWN_CH BIT(0)
+#define AD9545_CALIB_APLL BIT(1)
+
+/* AD9545_SYNC_CTRLX bitfields */
+#define AD9545_SYNC_CTRL_DPLL_REF_MSK BIT(2)
+#define AD9545_SYNC_CTRL_MODE_MSK GENMASK(1, 0)
+
+/* AD9545_QX_PHASE_CONF bitfields */
+#define AD9545_QX_HALF_DIV_MSK BIT(5)
+#define AD9545_QX_PHASE_32_MSK BIT(6)
+
+/* AD9545_DIV_OPS_QX bitfields */
+#define AD9545_DIV_OPS_MUTE_A_MSK BIT(2)
+#define AD9545_DIV_OPS_MUTE_AA_MSK BIT(3)
+
+/* AD9545_PLL_STATUS bitfields */
+#define AD9545_PLLX_LOCK(x, y) ((1 << (4 + (x))) & (y))
+
+/* AD9545_MISC bitfields */
+#define AD9545_MISC_AUX_NC0_ERR_MSK GENMASK(5, 4)
+#define AD9545_MISC_AUX_NC1_ERR_MSK GENMASK(7, 6)
+#define AD9545_AUX_DPLL_LOCK_MSK BIT(1)
+#define AD9545_AUX_DPLL_REF_FAULT BIT(2)
+
+/* AD9545_REFX_STATUS bitfields */
+#define AD9545_REFX_VALID_MSK BIT(4)
+
+#define AD9545_SYS_PLL_STABLE_MSK GENMASK(1, 0)
+#define AD9545_SYS_PLL_STABLE(x) (((x) & AD9545_SYS_PLL_STABLE_MSK) == 0x3)
+
+#define AD9545_APLL_LOCKED(x) ((x) & BIT(3))
+
+#define AD9545_SYS_CLK_STABILITY_MS 50
+
+#define AD9545_R_DIV_MAX 0x40000000
+#define AD9545_IN_MAX_TDC_FREQ_HZ 200000
+
+#define AD9545_MAX_REFS 4
+
+#define AD9545_APLL_M_DIV_MIN 14
+#define AD9545_APLL_M_DIV_MAX 255
+
+#define AD9545_DPLL_MAX_N 1073741823
+#define AD9545_DPLL_MAX_FRAC 116777215
+#define AD9545_DPLL_MAX_MOD 116777215
+#define AD9545_MAX_DPLL_PROFILES 6
+
+#define AD9545_NCO_MAX_FREQ 65535
+
+static const unsigned int ad9545_apll_rate_ranges_hz[2][2] = {
+ {2400000000U, 3200000000U}, {3200000000U, 4000000000U}
+};
+
+static const unsigned int ad9545_apll_pfd_rate_ranges_hz[2] = {
+ 162000000U, 300000000U
+};
+
+static const unsigned short ad9545_vco_calibration_op[][2] = {
+ {AD9545_CALIB_CLK, 0},
+ {AD9545_IO_UPDATE, AD9545_UPDATE_REGS},
+ {AD9545_CALIB_CLK, BIT(2)},
+ {AD9545_IO_UPDATE, AD9545_UPDATE_REGS},
+};
+
+static const u8 ad9545_tdc_source_mapping[] = {
+ 0, 1, 2, 3, 8, 9,
+};
+
+static const u32 ad9545_fast_acq_excess_bw_map[] = {
+ 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
+};
+
+static const u32 ad9545_fast_acq_timeout_map[] = {
+ 1, 10, 50, 100, 500, 1000, 10000, 50000,
+};
+
+static const u32 ad9545_hyst_scales_bp[] = {
+ 0, 3125, 6250, 12500, 25000, 50000, 75000, 87500
+};
+
+static const u32 ad9545_out_source_ua[] = {
+ 7500, 12500, 15000
+};
+
+static const u32 ad9545_rate_change_limit_map[] = {
+ 715, 1430, 2860, 5720, 11440, 22880, 45760,
+};
+
+static const char * const ad9545_ref_m_clk_names[] = {
+ "Ref-M0", "Ref-M1", "Ref-M2",
+};
+
+static const char * const ad9545_ref_clk_names[] = {
+ "Ref-A", "Ref-AA", "Ref-B", "Ref-BB",
+};
+
+static const char * const ad9545_in_clk_names[] = {
+ "Ref-A-Div", "Ref-AA-Div", "Ref-B-Div", "Ref-BB-Div",
+};
+
+static const char * const ad9545_out_clk_names[] = {
+ "Q0A-div", "Q0AA-div", "Q0B-div", "Q0BB-div", "Q0C-div", "Q0CC-div", "Q1A-div", "Q1AA-div",
+ "Q1B-div", "Q1BB-div",
+};
+
+static const char * const ad9545_pll_clk_names[] = {
+ "PLL0", "PLL1",
+};
+
+static const char * const ad9545_aux_nco_clk_names[] = {
+ "AUX_NCO0", "AUX_NCO1",
+};
+
+static const char * const ad9545_aux_tdc_clk_names[] = {
+ "AUX_TDC0", "AUX_TDC1",
+};
+
+static const char *ad9545_aux_dpll_name = "AUX_DPLL";
+
+enum ad9545_ref_mode {
+ AD9545_SINGLE_ENDED = 0,
+ AD9545_DIFFERENTIAL,
+};
+
+enum ad9545_single_ended_config {
+ AD9545_AC_COUPLED_IF = 0,
+ AD9545_DC_COUPLED_1V2,
+ AD9545_DC_COUPLED_1V8,
+ AD9545_IN_PULL_UP,
+};
+
+enum ad9545_diferential_config {
+ AD9545_AC_COUPLED = 0,
+ AD9545_DC_COUPLED,
+ AD9545_DC_COUPLED_LVDS,
+};
+
+enum ad9545_output_mode {
+ AD9545_SINGLE_DIV_DIF = 0,
+ AD9545_SINGLE_DIV,
+ AD9545_DUAL_DIV,
+};
+
+struct ad9545_out_clk {
+ struct ad9545_state *st;
+ bool output_used;
+ bool source_current;
+ enum ad9545_output_mode output_mode;
+ u32 source_ua;
+ struct clk_hw hw;
+ unsigned int address;
+};
+
+struct ad9545_dpll_profile {
+ unsigned int address;
+ unsigned int parent_index;
+ unsigned int priority;
+ unsigned int loop_bw_uhz;
+ unsigned int fast_acq_excess_bw;
+ unsigned int fast_acq_timeout_ms;
+ unsigned int fast_acq_settle_ms;
+ bool en;
+ u8 tdc_source;
+};
+
+struct ad9545_ppl_clk {
+ struct ad9545_state *st;
+ bool pll_used;
+ unsigned int address;
+ struct clk_hw hw;
+ unsigned int num_parents;
+ const struct clk_hw **parents;
+ struct ad9545_dpll_profile profiles[AD9545_MAX_DPLL_PROFILES];
+ unsigned int free_run_freq;
+ unsigned int fast_acq_trigger_mode;
+};
+
+struct ad9545_ref_in_clk {
+ struct clk_hw hw;
+ struct ad9545_state *st;
+ u32 r_div_ratio;
+ bool ref_used;
+ u32 d_tol_ppb;
+ u8 monitor_hyst_scale;
+ u32 valid_t_ms;
+ struct clk *parent_clk;
+ unsigned int address;
+ enum ad9545_ref_mode mode;
+ unsigned int freq_thresh_ps;
+ unsigned int phase_thresh_ps;
+ unsigned int phase_lock_fill_rate;
+ unsigned int phase_lock_drain_rate;
+ unsigned int freq_lock_fill_rate;
+ unsigned int freq_lock_drain_rate;
+ union {
+ enum ad9545_single_ended_config s_conf;
+ enum ad9545_diferential_config d_conf;
+ };
+};
+
+struct ad9545_aux_nco_clk {
+ struct clk_hw hw;
+ bool nco_used;
+ struct ad9545_state *st;
+ unsigned int address;
+ unsigned int freq_thresh_ps;
+ unsigned int phase_thresh_ps;
+};
+
+struct ad9545_aux_tdc_clk {
+ struct clk_hw hw;
+ bool tdc_used;
+ struct ad9545_state *st;
+ unsigned int address;
+ unsigned int pin_nr;
+};
+
+struct ad9545_aux_dpll_clk {
+ struct clk_hw hw;
+ bool dpll_used;
+ struct ad9545_state *st;
+ unsigned int source;
+ unsigned int loop_bw_mhz;
+ unsigned int rate_change_limit;
+};
+
+struct ad9545_sys_clk {
+ bool sys_clk_freq_doubler;
+ bool sys_clk_crystal;
+ u32 ref_freq_hz;
+ u32 sys_freq_hz;
+};
+
+struct ad9545_state {
+ struct device *dev;
+ struct regmap *regmap;
+ struct ad9545_sys_clk sys_clk;
+ struct ad9545_aux_dpll_clk aux_dpll_clk;
+ struct ad9545_ppl_clk pll_clks[ARRAY_SIZE(ad9545_pll_clk_names)];
+ struct ad9545_ref_in_clk ref_in_clks[ARRAY_SIZE(ad9545_ref_clk_names)];
+ struct ad9545_out_clk out_clks[ARRAY_SIZE(ad9545_out_clk_names)];
+ struct ad9545_aux_nco_clk aux_nco_clks[ARRAY_SIZE(ad9545_aux_nco_clk_names)];
+ struct ad9545_aux_tdc_clk aux_tdc_clks[ARRAY_SIZE(ad9545_aux_tdc_clk_names)];
+ struct clk **clks[4];
+};
+
+#define to_ref_in_clk(_hw) container_of(_hw, struct ad9545_ref_in_clk, hw)
+#define to_pll_clk(_hw) container_of(_hw, struct ad9545_ppl_clk, hw)
+#define to_out_clk(_hw) container_of(_hw, struct ad9545_out_clk, hw)
+#define to_nco_clk(_hw) container_of(_hw, struct ad9545_aux_nco_clk, hw)
+#define to_tdc_clk(_hw) container_of(_hw, struct ad9545_aux_tdc_clk, hw)
+
+static int ad9545_parse_dt_inputs(struct ad9545_state *st)
+{
+ struct fwnode_handle *inputs_node;
+ struct fwnode_handle *fwnode;
+ struct fwnode_handle *child;
+ struct clk *clk;
+ bool prop_found;
+ int ref_ind;
+ u32 val;
+ int ret;
+ int i;
+
+ fwnode = dev_fwnode(st->dev);
+ inputs_node = fwnode_get_named_child_node(fwnode, "ref-input-clks");
+ if (!inputs_node)
+ return 0;
+
+ prop_found = false;
+ fwnode_for_each_available_child_node(inputs_node, child) {
+ ret = fwnode_property_read_u32(child, "reg", &ref_ind);
+ if (ret < 0) {
+ dev_err(st->dev, "reg not specified in ref node.");
+ return ret;
+ }
+
+ if (ref_ind > 3)
+ return -EINVAL;
+
+ st->ref_in_clks[ref_ind].ref_used = true;
+ st->ref_in_clks[ref_ind].address = ref_ind;
+ st->ref_in_clks[ref_ind].st = st;
+
+ prop_found = fwnode_property_present(child, "adi,single-ended-mode");
+ if (prop_found) {
+ st->ref_in_clks[ref_ind].mode = AD9545_SINGLE_ENDED;
+ ret = fwnode_property_read_u32(child, "adi,single-ended-mode", &val);
+ if (ret < 0)
+ return ret;
+
+ st->ref_in_clks[ref_ind].s_conf = val;
+ } else {
+ st->ref_in_clks[ref_ind].mode = AD9545_DIFFERENTIAL;
+ ret = fwnode_property_read_u32(child, "adi,differential-mode", &val);
+ if (ret < 0)
+ return ret;
+
+ st->ref_in_clks[ref_ind].d_conf = val;
+ }
+
+ ret = fwnode_property_read_u32(child, "adi,r-divider-ratio", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No r-divider-ratio specified for ref: %d", ref_ind);
+ return ret;
+ }
+
+ st->ref_in_clks[ref_ind].r_div_ratio = val;
+
+ ret = fwnode_property_read_u32(child, "adi,ref-dtol-pbb", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No ref-dtol-pbb specified for ref: %d", ref_ind);
+ return ret;
+ }
+
+ st->ref_in_clks[ref_ind].d_tol_ppb = val;
+
+ ret = fwnode_property_read_u32(child, "adi,ref-monitor-hysteresis-pbb", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No ref-monitor-hysteresis-pbb specified for ref: %d",
+ ref_ind);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ad9545_hyst_scales_bp); i++) {
+ if (ad9545_hyst_scales_bp[i] == val) {
+ st->ref_in_clks[ref_ind].monitor_hyst_scale = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(ad9545_hyst_scales_bp))
+ return -EINVAL;
+
+ ret = fwnode_property_read_u32(child, "adi,ref-validation-timer-ms", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No ref-validation-timer-ms specified for ref: %d",
+ ref_ind);
+ return ret;
+ }
+
+ st->ref_in_clks[ref_ind].valid_t_ms = val;
+
+ ret = fwnode_property_read_u32(child, "adi,freq-lock-threshold-ps", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No freq-lock-threshold-ps specified for ref: %d",
+ ref_ind);
+ return ret;
+ }
+
+ st->ref_in_clks[ref_ind].freq_thresh_ps = val;
+
+ ret = fwnode_property_read_u32(child, "adi,phase-lock-threshold-ps", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No phase-lock-threshold-ps specified for ref: %d",
+ ref_ind);
+ return ret;
+ }
+
+ st->ref_in_clks[ref_ind].phase_thresh_ps = val;
+
+ ret = fwnode_property_read_u32(child, "adi,phase-lock-fill-rate", &val);
+ if (!ret)
+ st->ref_in_clks[ref_ind].phase_lock_fill_rate = val;
+
+ ret = fwnode_property_read_u32(child, "adi,phase-lock-drain-rate", &val);
+ if (!ret)
+ st->ref_in_clks[ref_ind].phase_lock_drain_rate = val;
+
+ ret = fwnode_property_read_u32(child, "adi,freq-lock-fill-rate", &val);
+ if (!ret)
+ st->ref_in_clks[ref_ind].freq_lock_fill_rate = val;
+
+ ret = fwnode_property_read_u32(child, "adi,freq-lock-drain-rate", &val);
+ if (!ret)
+ st->ref_in_clks[ref_ind].freq_lock_drain_rate = val;
+
+ clk = devm_clk_get(st->dev, ad9545_ref_clk_names[ref_ind]);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ st->ref_in_clks[ref_ind].parent_clk = clk;
+ }
+
+ return 0;
+}
+
+static int ad9545_parse_dt_plls(struct ad9545_state *st)
+{
+ struct fwnode_handle *profile_node;
+ struct fwnode_handle *pll_clks;
+ struct fwnode_handle *fwnode;
+ struct fwnode_handle *child;
+ u32 profile_addr;
+ u32 val;
+ u32 addr;
+ int ret;
+
+ fwnode = dev_fwnode(st->dev);
+ pll_clks = fwnode_get_named_child_node(fwnode, "pll-clks");
+ if (!pll_clks)
+ return 0;
+
+ fwnode_for_each_available_child_node(pll_clks, child) {
+ ret = fwnode_property_read_u32(child, "reg", &addr);
+ if (ret < 0)
+ return ret;
+
+ if (addr > 1)
+ return -EINVAL;
+
+ st->pll_clks[addr].pll_used = true;
+ st->pll_clks[addr].address = addr;
+
+ ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-trigger-mode", &val);
+ if (!ret)
+ st->pll_clks[addr].fast_acq_trigger_mode = val;
+
+ /* parse DPLL profiles */
+ fwnode_for_each_available_child_node(child, profile_node) {
+ ret = fwnode_property_read_u32(profile_node, "reg", &profile_addr);
+ if (ret < 0) {
+ dev_err(st->dev, "Could not read Profile reg property.");
+ return ret;
+ }
+
+ if (profile_addr >= AD9545_MAX_DPLL_PROFILES)
+ return -EINVAL;
+
+ st->pll_clks[addr].profiles[profile_addr].en = true;
+ st->pll_clks[addr].profiles[profile_addr].address = profile_addr;
+
+ ret = fwnode_property_read_u32(profile_node, "adi,pll-loop-bandwidth-uhz", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "Could not read Profile %d, pll-loop-bandwidth.",
+ profile_addr);
+ return ret;
+ }
+
+ st->pll_clks[addr].profiles[profile_addr].loop_bw_uhz = val;
+
+ ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-excess-bw",
+ &val);
+ if (!ret)
+ st->pll_clks[addr].profiles[profile_addr].fast_acq_excess_bw = val;
+
+ ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-timeout-ms",
+ &val);
+ if (!ret)
+ st->pll_clks[addr].profiles[profile_addr].fast_acq_timeout_ms = val;
+
+ ret = fwnode_property_read_u32(profile_node, "adi,fast-acq-lock-settle-ms",
+ &val);
+ if (!ret)
+ st->pll_clks[addr].profiles[profile_addr].fast_acq_settle_ms = val;
+
+ ret = fwnode_property_read_u32(profile_node, "adi,profile-priority", &val);
+ if (!ret)
+ st->pll_clks[addr].profiles[profile_addr].priority = val;
+
+ ret = fwnode_property_read_u32(profile_node, "adi,pll-source", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "Could not read Profile %d, pll-loop-bandwidth.",
+ profile_addr);
+ return ret;
+ }
+
+ if (val > 5)
+ return -EINVAL;
+
+ st->pll_clks[addr].profiles[profile_addr].tdc_source = val;
+ }
+ }
+
+ return 0;
+}
+
+static int ad9545_parse_dt_outputs(struct ad9545_state *st)
+{
+ struct fwnode_handle *output_clks;
+ struct fwnode_handle *fwnode;
+ struct fwnode_handle *child;
+ int out_ind;
+ u32 val;
+ int ret;
+
+ fwnode = dev_fwnode(st->dev);
+ output_clks = fwnode_get_named_child_node(fwnode, "output-clks");
+ if (!output_clks)
+ return 0;
+
+ fwnode_for_each_available_child_node(output_clks, child) {
+ ret = fwnode_property_read_u32(child, "reg", &out_ind);
+ if (ret < 0) {
+ dev_err(st->dev, "No reg specified for output.");
+ return ret;
+ }
+
+ if (out_ind > 9)
+ return -EINVAL;
+
+ st->out_clks[out_ind].output_used = true;
+ st->out_clks[out_ind].address = out_ind;
+
+ if (fwnode_property_present(child, "adi,current-source"))
+ st->out_clks[out_ind].source_current = true;
+
+ ret = fwnode_property_read_u32(child, "adi,current-source-microamp", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No current-source-microamp specified for output: %d",
+ out_ind);
+ return ret;
+ }
+
+ st->out_clks[out_ind].source_ua = val;
+
+ ret = fwnode_property_read_u32(child, "adi,output-mode", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No output-mode specified for output: %d", out_ind);
+ return ret;
+ }
+
+ st->out_clks[out_ind].output_mode = val;
+ }
+
+ return 0;
+}
+
+static int ad9545_parse_dt_ncos(struct ad9545_state *st)
+{
+ struct fwnode_handle *aux_ncos;
+ struct fwnode_handle *fwnode;
+ struct fwnode_handle *child;
+ u32 val;
+ u32 addr;
+ int ret;
+
+ fwnode = dev_fwnode(st->dev);
+ aux_ncos = fwnode_get_named_child_node(fwnode, "aux-ncos");
+ if (!aux_ncos)
+ return 0;
+
+ fwnode_for_each_available_child_node(aux_ncos, child) {
+ ret = fwnode_property_read_u32(child, "reg", &addr);
+ if (ret < 0) {
+ dev_err(st->dev, "No reg specified for aux. NCO.");
+ return ret;
+ }
+
+ if (addr > 1)
+ return -EINVAL;
+
+ st->aux_nco_clks[addr].nco_used = true;
+ st->aux_nco_clks[addr].address = addr;
+ st->aux_nco_clks[addr].st = st;
+
+ ret = fwnode_property_read_u32(child, "adi,freq-lock-threshold-ps", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No freq-lock-threshold-ps specified for aux. NCO: %d",
+ addr);
+ return ret;
+ }
+
+ st->aux_nco_clks[addr].freq_thresh_ps = val;
+
+ ret = fwnode_property_read_u32(child, "adi,phase-lock-threshold-ps", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No phase-lock-threshold-ps specified for aux. NCO: %d",
+ addr);
+ return ret;
+ }
+
+ st->aux_nco_clks[addr].phase_thresh_ps = val;
+ }
+
+ return 0;
+}
+
+static int ad9545_parse_dt_tdcs(struct ad9545_state *st)
+{
+ struct fwnode_handle *aux_tdc_clks;
+ struct fwnode_handle *fwnode;
+ struct fwnode_handle *child;
+ u32 val;
+ u32 addr;
+ int ret;
+
+ fwnode = dev_fwnode(st->dev);
+ aux_tdc_clks = fwnode_get_named_child_node(fwnode, "aux-tdc-clks");
+ if (!aux_tdc_clks)
+ return 0;
+
+ fwnode_for_each_available_child_node(aux_tdc_clks, child) {
+ ret = fwnode_property_read_u32(child, "reg", &addr);
+ if (ret < 0) {
+ dev_err(st->dev, "No reg specified for aux. TDC.");
+ return ret;
+ }
+
+ if (addr > 1) {
+ dev_err(st->dev, "Invalid address: %u for aux. TDC.", addr);
+ return -EINVAL;
+ }
+
+ st->aux_tdc_clks[addr].tdc_used = true;
+ st->aux_tdc_clks[addr].address = addr;
+ st->aux_tdc_clks[addr].st = st;
+
+ ret = fwnode_property_read_u32(child, "adi,pin-nr", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No source pin specified for aux. TDC: %d", addr);
+ return ret;
+ }
+
+ if (val >= ARRAY_SIZE(ad9545_ref_m_clk_names)) {
+ dev_err(st->dev, "Invalid Mx pin-nr: %d", val);
+ return -EINVAL;
+ }
+
+ st->aux_tdc_clks[addr].pin_nr = val;
+ }
+
+ return 0;
+}
+
+static int ad9545_parse_dt_aux_dpll(struct ad9545_state *st)
+{
+ struct fwnode_handle *fwnode;
+ struct fwnode_handle *child;
+ u32 val;
+ int ret;
+
+ fwnode = dev_fwnode(st->dev);
+ child = fwnode_get_named_child_node(fwnode, "aux-dpll");
+ if (!child)
+ return 0;
+
+ st->aux_dpll_clk.dpll_used = true;
+ st->aux_dpll_clk.st = st;
+
+ ret = fwnode_property_read_u32(child, "adi,compensation-source", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No TDC source specified for aux. DPLL.");
+ return ret;
+ }
+
+ st->aux_dpll_clk.source = val;
+
+ ret = fwnode_property_read_u32(child, "adi,aux-dpll-bw-mhz", &val);
+ if (ret < 0) {
+ dev_err(st->dev, "No loop bw specified for aux. DPLL.");
+ return ret;
+ }
+
+ st->aux_dpll_clk.loop_bw_mhz = val;
+
+ ret = fwnode_property_read_u32(child, "adi,rate-change-limit", &val);
+ if (!ret)
+ st->aux_dpll_clk.rate_change_limit = val;
+
+ return 0;
+}
+
+static int ad9545_parse_dt(struct ad9545_state *st)
+{
+ struct fwnode_handle *fwnode;
+ int ret;
+
+ fwnode = dev_fwnode(st->dev);
+
+ ret = fwnode_property_read_u32(fwnode, "adi,ref-frequency-hz", &st->sys_clk.ref_freq_hz);
+ if (ret < 0) {
+ dev_err(st->dev, "No ref-frequency-hz specified.");
+ return ret;
+ }
+
+ st->sys_clk.sys_clk_crystal = fwnode_property_present(fwnode, "adi,ref-crystal");
+ st->sys_clk.sys_clk_freq_doubler = fwnode_property_present(fwnode, "adi,freq-doubler");
+
+ ret = ad9545_parse_dt_inputs(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_parse_dt_plls(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_parse_dt_outputs(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_parse_dt_ncos(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_parse_dt_tdcs(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_parse_dt_aux_dpll(st);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int ad9545_check_id(struct ad9545_state *st)
+{
+ u32 chip_id;
+ u32 val;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD9545_PRODUCT_ID_LOW, &val);
+ if (ret < 0)
+ return ret;
+
+ chip_id = val;
+ ret = regmap_read(st->regmap, AD9545_PRODUCT_ID_HIGH, &val);
+ if (ret < 0)
+ return ret;
+
+ chip_id += val << 8;
+ if (chip_id != AD9545_CHIP_ID) {
+ dev_err(st->dev, "Unrecognized CHIP_ID 0x%X\n", chip_id);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int ad9545_io_update(struct ad9545_state *st)
+{
+ return regmap_write(st->regmap, AD9545_IO_UPDATE, AD9545_UPDATE_REGS);
+}
+
+static int ad9545_sys_clk_setup(struct ad9545_state *st)
+{
+ u64 ref_freq_milihz;
+ __le64 regval64;
+ u8 div_ratio;
+ u32 fosc;
+ int ret;
+ u8 val;
+ u32 fs;
+ int i;
+
+ /*
+ * System frequency must be between 2250 MHz and 2415 MHz.
+ * fs = fosc * K / j
+ * K - feedback divider ratio [4, 255]
+ * j = 1/2 if frequency doubler is enabled
+ */
+ fosc = DIV_ROUND_UP(st->sys_clk.ref_freq_hz, 1000000);
+
+ if (st->sys_clk.sys_clk_freq_doubler)
+ fosc *= 2;
+
+ div_ratio = 0;
+ for (i = 4; i < 256; i++) {
+ fs = i * fosc;
+
+ if (fs > 2250 && fs < 2415) {
+ div_ratio = i;
+ break;
+ }
+ }
+
+ if (!div_ratio) {
+ dev_err(st->dev, "No feedback divider ratio for sys clk PLL found.\n");
+ return -EINVAL;
+ }
+
+ st->sys_clk.sys_freq_hz = st->sys_clk.ref_freq_hz * div_ratio;
+ if (st->sys_clk.sys_clk_freq_doubler)
+ st->sys_clk.sys_freq_hz *= 2;
+
+ ret = regmap_write(st->regmap, AD9545_SYS_CLK_FB_DIV, div_ratio);
+ if (ret < 0)
+ return ret;
+
+ /* enable crystal maintaining amplifier */
+ val = 0;
+ if (st->sys_clk.sys_clk_crystal)
+ val |= BIT(3);
+
+ if (st->sys_clk.sys_clk_freq_doubler)
+ val |= BIT(0);
+
+ ret = regmap_write(st->regmap, AD9545_SYS_CLK_INPUT, val);
+ if (ret < 0)
+ return ret;
+
+ /* write reference frequency provided at XOA, XOB in milliherz */
+ ref_freq_milihz = mul_u32_u32(st->sys_clk.ref_freq_hz, 1000);
+ regval64 = cpu_to_le64(ref_freq_milihz);
+
+ ret = regmap_bulk_write(st->regmap, AD9545_SYS_CLK_REF_FREQ, &regval64, 5);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(st->regmap, AD9545_SYS_STABILITY_T, AD9545_SYS_CLK_STABILITY_MS);
+}
+
+static int ad9545_get_q_div(struct ad9545_state *st, int addr, u32 *q_div)
+{
+ __le32 regval;
+ int ret;
+
+ ret = regmap_bulk_read(st->regmap, AD9545_QX_DIV(addr), &regval, 4);
+ if (ret < 0)
+ return ret;
+
+ *q_div = le32_to_cpu(regval);
+
+ return 0;
+}
+
+static int ad9545_set_q_div(struct ad9545_state *st, int addr, u32 q_div)
+{
+ __le32 regval;
+ int ret;
+
+ regval = cpu_to_le32(q_div);
+ ret = regmap_bulk_write(st->regmap, AD9545_QX_DIV(addr), &regval, 4);
+ if (ret < 0)
+ return ret;
+
+ return ad9545_io_update(st);
+}
+
+static unsigned long ad95452_out_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct ad9545_out_clk *clk = to_out_clk(hw);
+ u32 qdiv;
+ int ret;
+
+ ret = ad9545_get_q_div(clk->st, clk->address, &qdiv);
+ if (ret < 0) {
+ dev_err(clk->st->dev, "Could not read Q div value.");
+ return 0;
+ }
+
+ return div_u64(parent_rate, qdiv);
+}
+
+static long ad9545_out_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ u32 out_rate;
+ u32 qdiv;
+
+ qdiv = div64_u64(*parent_rate, rate);
+ if (!qdiv)
+ out_rate = *parent_rate;
+ else
+ out_rate = div_u64(*parent_rate, qdiv);
+
+ return out_rate;
+}
+
+static int ad9545_out_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
+{
+ struct ad9545_out_clk *clk = to_out_clk(hw);
+ u32 qdiv = div64_u64(parent_rate, rate);
+
+ if (!qdiv)
+ qdiv = 1;
+
+ return ad9545_set_q_div(clk->st, clk->address, qdiv);
+}
+
+static int ad9545_out_clk_set_phase(struct clk_hw *hw, int degrees)
+{
+ struct ad9545_out_clk *clk = to_out_clk(hw);
+ u64 phase_code;
+ u32 phase_conf;
+ __le64 regval;
+ u32 half_div;
+ u32 qdiv;
+ int ret;
+
+ ret = ad9545_get_q_div(clk->st, clk->address, &qdiv);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(clk->st->regmap, AD9545_QX_PHASE_CONF(clk->address), &phase_conf);
+ if (ret < 0)
+ return ret;
+
+ half_div = !!(phase_conf & AD9545_QX_HALF_DIV_MSK);
+
+ /* Qxy phase bitfield depends on the current Q div value */
+ phase_code = qdiv;
+ phase_code = div_u64((phase_code * 2 + half_div) * degrees, 360);
+
+ /* Qxy phase bitfield is 33 bits long, with last bit in PHASE_CONF reg */
+ regval = cpu_to_le64(phase_code & 0xFFFFFFFF);
+ ret = regmap_bulk_write(clk->st->regmap, AD9545_QX_PHASE(clk->address), &regval, 4);
+ if (ret < 0)
+ return ret;
+
+ if (phase_code > U32_MAX) {
+ ret = regmap_update_bits(clk->st->regmap, AD9545_QX_PHASE_CONF(clk->address),
+ AD9545_QX_PHASE_32_MSK, AD9545_QX_PHASE_32_MSK);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ad9545_io_update(clk->st);
+}
+
+static int ad9545_out_clk_get_phase(struct clk_hw *hw)
+{
+ struct ad9545_out_clk *clk = to_out_clk(hw);
+ u64 input_edges_nr;
+ u64 phase_code;
+ __le32 regval;
+ u32 phase_conf;
+ u32 qdiv;
+ int ret;
+
+ ret = ad9545_get_q_div(clk->st, clk->address, &qdiv);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(clk->st->regmap, AD9545_QX_PHASE_CONF(clk->address), &phase_conf);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_bulk_read(clk->st->regmap, AD9545_QX_PHASE(clk->address), &regval, 4);
+ if (ret < 0)
+ return ret;
+
+ /* Qxy phase bitfield is 33 bits long, with last bit in PHASE_CONF reg */
+ phase_code = !!(phase_conf & AD9545_QX_PHASE_32_MSK);
+ phase_code = (phase_code >> 32) + cpu_to_le32(regval);
+
+ input_edges_nr = 2 * qdiv + !!(phase_conf & AD9545_QX_HALF_DIV_MSK);
+
+ /*
+ * phase = 360 * (Qxy Phase / E) where:
+ * E is the total number of input edges per output period of the Q-divider.
+ */
+ return div64_u64(phase_code * 360, input_edges_nr);
+}
+
+static int ad9545_output_muting(struct ad9545_out_clk *clk, bool mute)
+{
+ u8 regval = 0;
+ int ret;
+ u8 mask;
+
+ if (clk->address % 2)
+ mask = AD9545_DIV_OPS_MUTE_AA_MSK;
+ else
+ mask = AD9545_DIV_OPS_MUTE_A_MSK;
+
+ if (mute)
+ regval = mask;
+
+ ret = regmap_update_bits(clk->st->regmap, AD9545_DIV_OPS_QX(clk->address), mask, regval);
+ if (ret < 0)
+ return ret;
+
+ return ad9545_io_update(clk->st);
+}
+
+static int ad9545_out_clk_enable(struct clk_hw *hw)
+{
+ struct ad9545_out_clk *clk = to_out_clk(hw);
+
+ return ad9545_output_muting(clk, false);
+}
+
+static void ad9545_out_clk_disable(struct clk_hw *hw)
+{
+ struct ad9545_out_clk *clk = to_out_clk(hw);
+
+ ad9545_output_muting(clk, true);
+}
+
+static int ad9545_out_clk_is_enabled(struct clk_hw *hw)
+{
+ struct ad9545_out_clk *clk = to_out_clk(hw);
+ u32 regval;
+ int ret;
+ u8 mask;
+
+ if (clk->address % 2)
+ mask = AD9545_DIV_OPS_MUTE_AA_MSK;
+ else
+ mask = AD9545_DIV_OPS_MUTE_A_MSK;
+
+ ret = regmap_read(clk->st->regmap, AD9545_DIV_OPS_QX(clk->address), &regval);
+ if (ret < 0)
+ return ret;
+
+ return !!(mask & regval);
+}
+
+static const struct clk_ops ad9545_out_clk_ops = {
+ .enable = ad9545_out_clk_enable,
+ .disable = ad9545_out_clk_disable,
+ .is_enabled = ad9545_out_clk_is_enabled,
+ .recalc_rate = ad95452_out_clk_recalc_rate,
+ .round_rate = ad9545_out_clk_round_rate,
+ .set_rate = ad9545_out_clk_set_rate,
+ .set_phase = ad9545_out_clk_set_phase,
+ .get_phase = ad9545_out_clk_get_phase,
+};
+
+static int ad9545_outputs_setup(struct ad9545_state *st)
+{
+ struct clk_init_data init[ARRAY_SIZE(ad9545_out_clk_names)] = {0};
+ int out_i;
+ u16 addr;
+ int ret;
+ u8 reg;
+ int i;
+ int j;
+
+ /* configure current sources */
+ for (i = 0; i < ARRAY_SIZE(ad9545_out_clk_names) / 2; i++) {
+ st->out_clks[i * 2].st = st;
+ st->out_clks[i * 2 + 1].st = st;
+
+ if (st->out_clks[i * 2].output_used)
+ out_i = i * 2;
+ else if (st->out_clks[i * 2 + 1].output_used)
+ out_i = i * 2 + 1;
+ else
+ continue;
+
+ reg = 0;
+ if (st->out_clks[out_i].source_current)
+ reg = 1;
+
+ for (j = 0; j < ARRAY_SIZE(ad9545_out_source_ua); j++)
+ if (ad9545_out_source_ua[j] == st->out_clks[out_i].source_ua)
+ reg |= FIELD_PREP(GENMASK(2, 1), i);
+
+ reg |= FIELD_PREP(GENMASK(4, 3), st->out_clks[out_i].output_mode);
+
+ if (i < 3)
+ addr = AD9545_DRIVER_0A_CONF + i;
+ else
+ addr = AD9545_DRIVER_1A_CONF + (i - 3);
+
+ ret = regmap_write(st->regmap, addr, reg);
+ if (ret < 0)
+ return ret;
+ }
+
+ st->clks[AD9545_CLK_OUT] = devm_kzalloc(st->dev, ARRAY_SIZE(ad9545_out_clk_names) *
+ sizeof(struct clk *), GFP_KERNEL);
+ if (!st->clks[AD9545_CLK_OUT])
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(ad9545_out_clk_names); i++) {
+ if (!st->out_clks[i].output_used)
+ continue;
+
+ init[i].name = ad9545_out_clk_names[i];
+ init[i].ops = &ad9545_out_clk_ops;
+
+ if (i > 5)
+ init[i].parent_names = &ad9545_pll_clk_names[1];
+ else
+ init[i].parent_names = &ad9545_pll_clk_names[0];
+
+ init[i].num_parents = 1;
+
+ st->out_clks[i].hw.init = &init[i];
+ ret = devm_clk_hw_register(st->dev, &st->out_clks[i].hw);
+ if (ret < 0)
+ return ret;
+
+ st->clks[AD9545_CLK_OUT][i] = st->out_clks[i].hw.clk;
+ }
+
+ /* set to autosync to trigger on DPLL freq lock */
+ for (i = 0; i < ARRAY_SIZE(st->pll_clks); i++) {
+ reg = FIELD_PREP(AD9545_SYNC_CTRL_MODE_MSK, 3);
+ ret = regmap_write(st->regmap, AD9545_SYNC_CTRLX(i), reg);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ad9545_io_update(st);
+}
+
+static int ad9545_set_r_div(struct ad9545_state *st, u32 div, int addr)
+{
+ int ret;
+ u8 reg;
+ int i;
+
+ if (div > AD9545_R_DIV_MAX)
+ return -EINVAL;
+
+ /* r-div ratios are mapped from 0 onward */
+ div -= 1;
+ for (i = 0; i < 4; i++) {
+ reg = (div >> (i * 8)) & 0xFF;
+
+ ret = regmap_write(st->regmap, AD9545_REF_X_RDIV(addr) + i, reg);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ad9545_io_update(st);
+}
+
+static int ad9545_get_r_div(struct ad9545_state *st, int addr, u32 *r_div)
+{
+ int ret;
+ u32 div;
+ u32 reg;
+ int i;
+
+ div = 0;
+ for (i = 0; i < 4; i++) {
+ ret = regmap_read(st->regmap, AD9545_REF_X_RDIV(addr) + i, &reg);
+ if (ret < 0)
+ return ret;
+
+ div += (reg << (i * 8));
+ }
+
+ /* r-div ratios are mapped from 0 onward */
+ *r_div = ++div;
+
+ return 0;
+}
+
+static unsigned long ad95452_in_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct ad9545_ref_in_clk *clk = to_ref_in_clk(hw);
+ u32 div;
+ int ret;
+
+ ret = ad9545_get_r_div(clk->st, clk->address, &div);
+ if (ret < 0) {
+ dev_err(clk->st->dev, "Could not read r div value.");
+ return 1;
+ }
+
+ return DIV_ROUND_CLOSEST(parent_rate, div);
+}
+
+static const struct clk_ops ad9545_in_clk_ops = {
+ .recalc_rate = ad95452_in_clk_recalc_rate,
+};
+
+static int ad9545_input_refs_setup(struct ad9545_state *st)
+{
+ struct clk_init_data init[4] = {0};
+ __le32 regval;
+ __le64 regval64;
+ u64 period_es;
+ int ret;
+ u32 val;
+ u8 reg;
+ int i;
+
+ /* configure input references */
+ for (i = 0; i < ARRAY_SIZE(st->ref_in_clks); i += 2) {
+ if (st->ref_in_clks[i].mode == AD9545_DIFFERENTIAL) {
+ reg = BIT(0);
+ reg |= FIELD_PREP(AD9545_REF_CTRL_DIF_MSK, st->ref_in_clks[i].d_conf);
+ } else {
+ reg = 0;
+ reg |= FIELD_PREP(AD9545_REF_CTRL_REFA_MSK, st->ref_in_clks[i].s_conf);
+ reg |= FIELD_PREP(AD9545_REF_CTRL_REFAA_MSK, st->ref_in_clks[i + 1].s_conf);
+ }
+
+ ret = regmap_write(st->regmap, AD9545_REF_A_CTRL + i * 2, reg);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* configure refs r dividers */
+ for (i = 0; i < ARRAY_SIZE(st->ref_in_clks); i++) {
+ ret = ad9545_set_r_div(st, st->ref_in_clks[i].r_div_ratio, i);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(st->ref_in_clks); i++) {
+ if (!st->ref_in_clks[i].ref_used)
+ continue;
+
+ /* write nominal period in attoseconds */
+ period_es = 1000000000000000000ULL;
+ val = clk_get_rate(st->ref_in_clks[i].parent_clk);
+ if (!val)
+ return -EINVAL;
+
+ period_es = div_u64(period_es, val);
+
+ regval = cpu_to_le32(st->ref_in_clks[i].d_tol_ppb);
+ ret = regmap_bulk_write(st->regmap, AD9545_REF_X_OFFSET_LIMIT(i),
+ &regval, 3);
+ if (ret < 0)
+ return ret;
+
+ regval64 = cpu_to_le64(period_es);
+ ret = regmap_bulk_write(st->regmap, AD9545_REF_X_PERIOD(i), &regval64, 8);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD9545_REF_X_MONITOR_HYST(i),
+ st->ref_in_clks[i].monitor_hyst_scale);
+ if (ret < 0)
+ return ret;
+
+ regval = cpu_to_le32(st->ref_in_clks[i].freq_thresh_ps);
+ ret = regmap_bulk_write(st->regmap, AD9545_SOURCEX_FREQ_THRESH(i),
+ &regval, 3);
+ if (ret < 0)
+ return ret;
+
+ regval = cpu_to_le32(st->ref_in_clks[i].phase_thresh_ps);
+ ret = regmap_bulk_write(st->regmap, AD9545_SOURCEX_PHASE_THRESH(i),
+ &regval, 3);
+ if (ret < 0)
+ return ret;
+
+ regval = st->ref_in_clks[i].freq_lock_fill_rate;
+ if (regval) {
+ ret = regmap_write(st->regmap, AD9545_REF_X_FREQ_LOCK_FILL(i), regval);
+ if (ret < 0)
+ return ret;
+ }
+
+ regval = st->ref_in_clks[i].freq_lock_drain_rate;
+ if (regval) {
+ ret = regmap_write(st->regmap, AD9545_REF_X_FREQ_LOCK_DRAIN(i), regval);
+ if (ret < 0)
+ return ret;
+ }
+
+ regval = st->ref_in_clks[i].phase_lock_fill_rate;
+ if (regval) {
+ ret = regmap_write(st->regmap, AD9545_REF_X_PHASE_LOCK_FILL(i), regval);
+ if (ret < 0)
+ return ret;
+ }
+
+ regval = st->ref_in_clks[i].phase_lock_drain_rate;
+ if (regval) {
+ ret = regmap_write(st->regmap, AD9545_REF_X_PHASE_LOCK_DRAIN(i), regval);
+ if (ret < 0)
+ return ret;
+ }
+
+ init[i].name = ad9545_in_clk_names[i];
+ init[i].ops = &ad9545_in_clk_ops;
+ init[i].parent_names = &ad9545_ref_clk_names[i];
+ init[i].num_parents = 1;
+
+ st->ref_in_clks[i].hw.init = &init[i];
+ ret = devm_clk_hw_register(st->dev, &st->ref_in_clks[i].hw);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* disable unused references */
+ reg = 0;
+ for (i = 0; i < ARRAY_SIZE(st->ref_in_clks); i++) {
+ if (!st->ref_in_clks[i].ref_used)
+ reg |= (1 << i);
+ }
+
+ return regmap_write(st->regmap, AD9545_POWER_DOWN_REF, reg);
+}
+
+static int ad9545_calc_ftw(struct ad9545_ppl_clk *clk, u32 freq, u64 *tuning_word)
+{
+ u64 ftw = 1;
+ u32 ftw_frac;
+ u32 ftw_int;
+
+ /*
+ * In case of unlock event the DPLL will go in open-loop mode and output
+ * the freq given by the freerun tuning word.
+ * DPLLx Freerun TW = (2 ^ 48) × (f NCO /f System )
+ */
+ ftw = mul_u64_u32_div(ftw << 48, freq, clk->st->sys_clk.sys_freq_hz);
+
+ /*
+ * Check if FTW is valid:
+ * (2 ^ 48) / FTW = INT.FRAC where:
+ * 7 ≤ INT ≤ 13 and 0.05 ≤ FRAC ≤ 0.95
+ */
+ ftw_int = div64_u64(1ULL << 48, ftw);
+ if (ftw_int < 7 || ftw_int > 13)
+ return -EINVAL;
+
+ div_u64_rem(div64_u64(100 * (1ULL << 48), ftw), 100, &ftw_frac);
+ if (ftw_frac < 5 || ftw_frac > 95)
+ return -EINVAL;
+
+ *tuning_word = ftw;
+
+ return 0;
+}
+
+static int ad9545_set_freerun_freq(struct ad9545_ppl_clk *clk, u32 freq)
+{
+ __le64 regval;
+ u64 ftw;
+ int ret;
+
+ ret = ad9545_calc_ftw(clk, freq, &ftw);
+ if (ret < 0)
+ return ret;
+
+ regval = cpu_to_le64(ftw);
+ ret = regmap_bulk_write(clk->st->regmap, AD9545_DPLLX_FTW(clk->address), &regval, 6);
+ if (ret < 0)
+ return ret;
+
+ clk->free_run_freq = freq;
+ return ad9545_io_update(clk->st);
+}
+
+static u32 ad9545_calc_m_div(unsigned long rate)
+{
+ u32 m_div;
+
+ /*
+ * PFD of APLL has input frequency limits in 162 - 350 Mghz range.
+ * Use APLL to upconvert this freq to Ghz range.
+ */
+ m_div = div_u64(rate, ad9545_apll_pfd_rate_ranges_hz[0] / 2 +
+ ad9545_apll_pfd_rate_ranges_hz[1] / 2);
+ m_div = clamp_t(u8, m_div, AD9545_APLL_M_DIV_MIN, AD9545_APLL_M_DIV_MAX);
+
+ return m_div;
+}
+
+static u64 ad9545_calc_pll_params(struct ad9545_ppl_clk *clk, unsigned long rate,
+ unsigned long parent_rate, u32 *m, u32 *n,
+ unsigned long *frac, unsigned long *mod)
+{
+ u32 min_dpll_n_div;
+ u64 output_rate;
+ u32 dpll_n_div;
+ u32 m_div;
+ u64 den;
+ u64 num;
+
+ /* half divider at output requires APLL to generate twice the frequency demanded */
+ rate *= 2;
+
+ m_div = ad9545_calc_m_div(rate);
+
+ /*
+ * If N + FRAC / MOD = rate / (m_div * parent_rate)
+ * and N = [rate / (m_div * past_rate)]:
+ * We get: FRAC/MOD = (rate / (m_div * parent_rate)) - N
+ */
+ dpll_n_div = div64_u64(rate, parent_rate * m_div);
+
+ /*
+ * APLL has to be able to satisfy output freq bounds
+ * thus output of DPLL has a lower bound
+ */
+ min_dpll_n_div = div_u64(ad9545_apll_rate_ranges_hz[clk->address][0],
+ AD9545_APLL_M_DIV_MAX * parent_rate);
+ dpll_n_div = clamp_t(u32, dpll_n_div, min_dpll_n_div, AD9545_DPLL_MAX_N);
+
+ num = rate - (dpll_n_div * m_div * parent_rate);
+ den = m_div * parent_rate;
+
+ rational_best_approximation(num, den, AD9545_DPLL_MAX_FRAC, AD9545_DPLL_MAX_MOD, frac, mod);
+ *m = m_div;
+ *n = dpll_n_div;
+
+ output_rate = mul_u64_u32_div(*frac * parent_rate, m_div, *mod);
+ output_rate += parent_rate * dpll_n_div * m_div;
+
+ return (u32)DIV_ROUND_CLOSEST(output_rate, 2);
+}
+
+static int ad9545_tdc_source_valid(struct ad9545_ppl_clk *clk, unsigned int tdc_source)
+{
+ unsigned int regval;
+ int ret;
+
+ if (tdc_source >= AD9545_MAX_REFS) {
+ ret = regmap_read(clk->st->regmap, AD9545_MISC, &regval);
+ if (ret < 0)
+ return ret;
+
+ if (tdc_source == AD9545_MAX_REFS)
+ return !(regval & AD9545_MISC_AUX_NC0_ERR_MSK);
+ else
+ return !(regval & AD9545_MISC_AUX_NC1_ERR_MSK);
+ } else {
+ ret = regmap_read(clk->st->regmap, AD9545_REFX_STATUS(tdc_source), &regval);
+ if (ret < 0)
+ return ret;
+
+ return !!(regval & AD9545_REFX_VALID_MSK);
+ }
+}
+
+static u8 ad9545_pll_get_parent(struct clk_hw *hw)
+{
+ struct ad9545_ppl_clk *clk = to_pll_clk(hw);
+ struct ad9545_dpll_profile *profile;
+ u8 best_prio = 0xFF;
+ u8 best_parent;
+ int ret;
+ int i;
+
+ ret = ad9545_io_update(clk->st);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * A DPLL will pick a parent clock depending
+ * on the priorities and if it is a valid timestamp source.
+ */
+ for (i = 0; i < AD9545_MAX_DPLL_PROFILES; i++) {
+ profile = &clk->profiles[i];
+ if (!profile->en)
+ continue;
+
+ ret = ad9545_tdc_source_valid(clk, profile->tdc_source);
+ if (ret < 0)
+ return clk->num_parents;
+
+ if (ret > 0 && profile->priority < best_prio) {
+ best_prio = profile->priority;
+ best_parent = profile->parent_index;
+ }
+ }
+
+ if (best_prio != 0xFF)
+ return best_parent;
+
+ return clk->num_parents;
+}
+
+static unsigned long ad9545_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct ad9545_ppl_clk *clk = to_pll_clk(hw);
+ unsigned long output_rate;
+ __le32 regval;
+ u32 frac;
+ u32 mod;
+ int ret;
+ u32 m;
+ u32 n;
+ int i;
+
+ m = 0;
+ ret = regmap_read(clk->st->regmap, AD9545_APLLX_M_DIV(clk->address), &m);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If no ref is valid, pll will run in free run mode.
+ * At this point the NCO of the DPLL will output a free run frequency
+ * thus the output frequency of the PLL block will be:
+ * f NCO * M-div / 2
+ */
+ i = ad9545_pll_get_parent(hw);
+ if (i == clk->num_parents)
+ return div_u64(clk->free_run_freq * m, 2);
+
+ parent_rate = clk_hw_get_rate(clk->parents[i]);
+
+ ret = regmap_bulk_read(clk->st->regmap, AD9545_DPLLX_N_DIV(clk->address, i), &regval, 4);
+ if (ret < 0)
+ return ret;
+
+ n = le32_to_cpu(regval) + 1;
+
+ regval = 0;
+ ret = regmap_bulk_read(clk->st->regmap, AD9545_DPLLX_FRAC_DIV(clk->address, i), &regval, 3);
+ if (ret < 0)
+ return ret;
+
+ frac = le32_to_cpu(regval);
+
+ regval = 0;
+ ret = regmap_bulk_read(clk->st->regmap, AD9545_DPLLX_MOD_DIV(clk->address, i), &regval, 3);
+ if (ret < 0)
+ return ret;
+
+ mod = le32_to_cpu(regval);
+
+ /* Output rate of APLL = parent_rate * (N + (Frac / Mod)) * M */
+ output_rate = mul_u64_u32_div(frac * parent_rate, m, mod);
+ output_rate += parent_rate * n * m;
+
+ return output_rate / 2;
+}
+
+static long ad9545_pll_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct ad9545_ppl_clk *clk = to_pll_clk(hw);
+ unsigned long frac;
+ unsigned long mod;
+ int ret;
+ u64 ftw;
+ int i;
+ u32 m;
+ u32 n;
+
+ /* if no ref is valid, check if requested rate can be set in free run mode */
+ i = ad9545_pll_get_parent(hw);
+ if (i == clk->num_parents) {
+ /* in free run mode output freq is given by f NCO * m / 2 */
+ m = ad9545_calc_m_div(rate * 2);
+ ret = ad9545_calc_ftw(clk, div_u64(rate * 2, m), &ftw);
+ if (ret < 0)
+ return 0;
+
+ return rate;
+ }
+
+ return ad9545_calc_pll_params(clk, rate, *parent_rate, &m, &n, &frac, &mod);
+}
+
+static int ad9545_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
+{
+ struct ad9545_ppl_clk *clk = to_pll_clk(hw);
+ unsigned long out_rate;
+ unsigned long frac;
+ unsigned long mod;
+ __le32 regval;
+ int ret;
+ u32 m;
+ u32 n;
+ int i;
+
+ /*
+ * When setting a PLL rate, precalculate params for all enabled profiles.
+ * At this point there may or may not be a valid reference.
+ */
+ for (i = 0; i < clk->num_parents; i++) {
+ parent_rate = clk_hw_get_rate(clk->parents[i]);
+
+ out_rate = ad9545_calc_pll_params(clk, rate, parent_rate, &m, &n, &frac, &mod);
+ if (out_rate != rate)
+ return -EINVAL;
+
+ regval = cpu_to_le32(n - 1);
+ ret = regmap_bulk_write(clk->st->regmap, AD9545_DPLLX_N_DIV(clk->address, i),
+ &regval, 4);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(clk->st->regmap, AD9545_APLLX_M_DIV(clk->address), m);
+ if (ret < 0)
+ return ret;
+
+ regval = cpu_to_le32(frac);
+ ret = regmap_bulk_write(clk->st->regmap, AD9545_DPLLX_FRAC_DIV(clk->address, i),
+ &regval, 3);
+ if (ret < 0)
+ return ret;
+
+ regval = cpu_to_le32(mod);
+ ret = regmap_bulk_write(clk->st->regmap, AD9545_DPLLX_MOD_DIV(clk->address, i),
+ &regval, 3);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ad9545_set_freerun_freq(clk, div_u64(rate * 2, m));
+}
+
+static const struct clk_ops ad9545_pll_clk_ops = {
+ .recalc_rate = ad9545_pll_clk_recalc_rate,
+ .round_rate = ad9545_pll_clk_round_rate,
+ .set_rate = ad9545_pll_set_rate,
+ .get_parent = ad9545_pll_get_parent,
+};
+
+static int ad9545_pll_fast_acq_setup(struct ad9545_ppl_clk *pll, int profile)
+{
+ struct ad9545_state *st = pll->st;
+ unsigned int tmp;
+ int ret;
+ u8 reg;
+ int i;
+
+ tmp = pll->profiles[profile].fast_acq_excess_bw;
+ for (i = 0; i < ARRAY_SIZE(ad9545_fast_acq_excess_bw_map); i++)
+ if (tmp == ad9545_fast_acq_excess_bw_map[i])
+ break;
+
+ if (i < ARRAY_SIZE(ad9545_fast_acq_excess_bw_map)) {
+ ret = regmap_write(st->regmap, AD9545_DPLLX_FAST_L1(pll->address, profile), i);
+ if (ret < 0)
+ return ret;
+ } else {
+ dev_err(st->dev, "Wrong fast_acq_excess_bw value for DPLL %u, profile: %d.",
+ pll->address, profile);
+ return -EINVAL;
+ }
+
+ tmp = pll->profiles[profile].fast_acq_settle_ms;
+ for (i = 0; i < ARRAY_SIZE(ad9545_fast_acq_timeout_map); i++)
+ if (tmp == ad9545_fast_acq_timeout_map[i])
+ break;
+
+ if (i == ARRAY_SIZE(ad9545_fast_acq_timeout_map)) {
+ dev_err(st->dev, "Wrong fast_acq_settle_ms value for DPLL %u, profile %d.",
+ pll->address, profile);
+ return -EINVAL;
+ }
+
+ reg = i;
+
+ tmp = pll->profiles[profile].fast_acq_timeout_ms;
+ for (i = 0; i < ARRAY_SIZE(ad9545_fast_acq_timeout_map); i++)
+ if (tmp == ad9545_fast_acq_timeout_map[i])
+ break;
+
+ if (i == ARRAY_SIZE(ad9545_fast_acq_timeout_map)) {
+ dev_err(st->dev, "Wrong fast_acq_timeout_ms value for DPLL %u, profile %d.",
+ pll->address, profile);
+ return -EINVAL;
+ }
+
+ reg |= i << 4;
+
+ ret = regmap_write(st->regmap, AD9545_DPLLX_FAST_L2(pll->address, profile), reg);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(st->regmap, AD9545_DPLLX_FAST_MODE(pll->address),
+ pll->fast_acq_trigger_mode);
+}
+
+static int ad9545_plls_setup(struct ad9545_state *st)
+{
+ struct clk_init_data init[2] = {0};
+ struct ad9545_ppl_clk *pll;
+ struct clk_hw *hw;
+ int tdc_source;
+ __le32 regval;
+ int ret;
+ u8 reg;
+ int i;
+ int j;
+
+ st->clks[AD9545_CLK_PLL] = devm_kzalloc(st->dev, ARRAY_SIZE(ad9545_pll_clk_names) *
+ sizeof(struct clk *), GFP_KERNEL);
+ if (!st->clks[AD9545_CLK_PLL])
+ return -ENOMEM;
+
+ for (i = 0; i < 2; i++) {
+ pll = &st->pll_clks[i];
+ if (!pll->pll_used)
+ continue;
+
+ pll->st = st;
+ pll->address = i;
+
+ init[i].name = ad9545_pll_clk_names[i];
+ init[i].ops = &ad9545_pll_clk_ops;
+ init[i].num_parents = 0;
+ for (j = 0; j < AD9545_MAX_DPLL_PROFILES; j++)
+ if (pll->profiles[j].en)
+ init[i].num_parents++;
+
+ init[i].parent_hws = devm_kzalloc(st->dev, init[i].num_parents *
+ sizeof(*init[i].parent_hws), GFP_KERNEL);
+ if (!init[i].parent_hws)
+ return -ENOMEM;
+
+ pll->num_parents = init[i].num_parents;
+ pll->parents = init[i].parent_hws;
+
+ for (j = 0; j < AD9545_MAX_DPLL_PROFILES; j++) {
+ if (!pll->profiles[j].en)
+ continue;
+
+ pll->profiles[j].parent_index = j;
+
+ /* enable pll profile */
+ reg = AD9545_EN_PROFILE_MSK |
+ FIELD_PREP(AD9545_SEL_PRIORITY_MSK, pll->profiles[j].priority);
+ ret = regmap_write(st->regmap, AD9545_DPLLX_EN(i, j), reg);
+ if (ret < 0)
+ return ret;
+
+ /* set TDC source */
+ tdc_source = pll->profiles[j].tdc_source;
+ ret = regmap_write(st->regmap, AD9545_DPLLX_SOURCE(i, j),
+ ad9545_tdc_source_mapping[tdc_source]);
+ if (ret < 0)
+ return ret;
+
+ regval = cpu_to_le32(pll->profiles[j].loop_bw_uhz);
+ ret = regmap_bulk_write(st->regmap, AD9545_DPLLX_LOOP_BW(i, j), &regval, 4);
+ if (ret < 0)
+ return ret;
+
+ if (pll->profiles[j].tdc_source >= ARRAY_SIZE(ad9545_ref_clk_names))
+ hw = &st->aux_nco_clks[tdc_source - ARRAY_SIZE(ad9545_ref_clk_names)].hw;
+ else
+ hw = &st->ref_in_clks[tdc_source].hw;
+ init[i].parent_hws[j] = hw;
+
+ if (pll->profiles[j].fast_acq_excess_bw > 0) {
+ ret = ad9545_pll_fast_acq_setup(pll, j);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ pll->hw.init = &init[i];
+ ret = devm_clk_hw_register(st->dev, &pll->hw);
+ if (ret < 0)
+ return ret;
+
+ st->clks[AD9545_CLK_PLL][i] = pll->hw.clk;
+ }
+
+ return 0;
+}
+
+static int ad9545_get_nco_freq(struct ad9545_state *st, int addr, u32 *freq)
+{
+ __le16 regval;
+ int ret;
+
+ ret = regmap_bulk_read(st->regmap, AD9545_NCOX_FREQ(addr), &regval, 2);
+ if (ret < 0)
+ return ret;
+
+ *freq = le16_to_cpu(regval);
+ return 0;
+}
+
+static int ad9545_set_nco_freq(struct ad9545_state *st, int addr, u32 freq)
+{
+ __le32 regval;
+ int ret;
+
+ regval = cpu_to_le32(freq);
+ ret = regmap_bulk_write(st->regmap, AD9545_NCOX_FREQ(addr), &regval, 2);
+ if (ret < 0)
+ return ret;
+
+ return ad9545_io_update(st);
+}
+
+static unsigned long ad95452_nco_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct ad9545_aux_nco_clk *clk = to_nco_clk(hw);
+ u32 rate;
+ int ret;
+
+ ret = ad9545_get_nco_freq(clk->st, clk->address, &rate);
+ if (ret < 0) {
+ dev_err(clk->st->dev, "Could not read NCO freq.");
+ return 0;
+ }
+
+ return rate;
+}
+
+static long ad9545_nco_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ return clamp_t(u16, rate, 1, AD9545_NCO_MAX_FREQ);
+}
+
+static int ad9545_nco_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
+{
+ struct ad9545_aux_nco_clk *clk = to_nco_clk(hw);
+
+ return ad9545_set_nco_freq(clk->st, clk->address, rate);
+}
+
+static const struct clk_ops ad9545_nco_clk_ops = {
+ .recalc_rate = ad95452_nco_clk_recalc_rate,
+ .round_rate = ad9545_nco_clk_round_rate,
+ .set_rate = ad9545_nco_clk_set_rate,
+};
+
+static int ad9545_aux_ncos_setup(struct ad9545_state *st)
+{
+ struct clk_init_data init[2] = {0};
+ struct ad9545_aux_nco_clk *nco;
+ __le32 regval;
+ int ret;
+ int i;
+
+ st->clks[AD9545_CLK_NCO] = devm_kzalloc(st->dev, ARRAY_SIZE(ad9545_aux_nco_clk_names) *
+ sizeof(struct clk *), GFP_KERNEL);
+ if (!st->clks[AD9545_CLK_NCO])
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(st->aux_nco_clks); i++) {
+ nco = &st->aux_nco_clks[i];
+ if (!nco->nco_used)
+ continue;
+
+ regval = cpu_to_le32(nco->freq_thresh_ps);
+ ret = regmap_bulk_write(st->regmap, AD9545_NCOX_FREQ_THRESH(i), &regval, 3);
+ if (ret < 0)
+ return ret;
+
+ regval = cpu_to_le32(nco->phase_thresh_ps);
+ ret = regmap_bulk_write(st->regmap, AD9545_NCOX_PHASE_THRESH(i), &regval, 3);
+ if (ret < 0)
+ return ret;
+
+ init[i].name = ad9545_aux_nco_clk_names[i];
+ init[i].ops = &ad9545_nco_clk_ops;
+
+ nco->hw.init = &init[i];
+ ret = devm_clk_hw_register(st->dev, &nco->hw);
+ if (ret < 0)
+ return ret;
+
+ st->clks[AD9545_CLK_NCO][i] = nco->hw.clk;
+ }
+
+ return 0;
+}
+
+static int ad9545_set_tdc_div(struct ad9545_aux_tdc_clk *clk, u32 div)
+{
+ int ret;
+
+ if (!div)
+ return -EINVAL;
+
+ ret = regmap_write(clk->st->regmap, AD9545_TDCX_DIV(clk->address), --div);
+ if (ret < 0)
+ return ret;
+
+ return ad9545_io_update(clk->st);
+}
+
+static unsigned long ad9545_tdc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct ad9545_aux_tdc_clk *clk = to_tdc_clk(hw);
+ int ret;
+ u32 div;
+
+ ret = regmap_read(clk->st->regmap, AD9545_TDCX_DIV(clk->address), &div);
+ if (ret < 0) {
+ dev_err(clk->st->dev, "Could not read TDC freq.");
+ return ret;
+ }
+
+ div++;
+
+ return DIV_ROUND_UP_ULL((u64)parent_rate, div);
+}
+
+static long ad9545_tdc_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ u32 div;
+
+ if (!*parent_rate || !rate)
+ return 0;
+
+ div = clamp_t(u8, DIV_ROUND_UP_ULL((u64)*parent_rate, rate), 1, U8_MAX);
+
+ return DIV_ROUND_UP_ULL((u64)*parent_rate, div);
+}
+
+static int ad9545_tdc_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
+{
+ struct ad9545_aux_tdc_clk *clk = to_tdc_clk(hw);
+ __le64 regval64;
+ u64 period_es;
+ u32 div;
+ int ret;
+
+ if (!parent_rate || !rate)
+ return 0;
+
+ /* write parent rate received at the Mx pin in attoseconds */
+ period_es = div_u64(1000000000000000000ULL, parent_rate);
+ regval64 = cpu_to_le64(period_es);
+ ret = regmap_bulk_write(clk->st->regmap, AD9545_TDCX_PERIOD(clk->address), &regval64, 8);
+ if (ret < 0)
+ return ret;
+
+ div = clamp_t(u8, DIV_ROUND_UP_ULL((u64)parent_rate, rate), 1, U8_MAX);
+
+ return ad9545_set_tdc_div(clk, div);
+}
+
+static const struct clk_ops ad9545_aux_tdc_clk_ops = {
+ .recalc_rate = ad9545_tdc_clk_recalc_rate,
+ .round_rate = ad9545_tdc_clk_round_rate,
+ .set_rate = ad9545_tdc_clk_set_rate,
+};
+
+static int ad9545_aux_tdcs_setup(struct ad9545_state *st)
+{
+ struct clk_init_data init[ARRAY_SIZE(ad9545_aux_tdc_clk_names)] = {0};
+ struct ad9545_aux_tdc_clk *tdc;
+ int ret;
+ int i;
+
+ st->clks[AD9545_CLK_AUX_TDC] = devm_kcalloc(st->dev, ARRAY_SIZE(ad9545_aux_tdc_clk_names),
+ sizeof(*st->clks[AD9545_CLK_AUX_TDC]),
+ GFP_KERNEL);
+ if (!st->clks[AD9545_CLK_AUX_TDC])
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(st->aux_tdc_clks); i++) {
+ tdc = &st->aux_tdc_clks[i];
+ if (!tdc->tdc_used)
+ continue;
+
+ /* redirect Mx pin to this TDC */
+ ret = regmap_write(st->regmap, AD9545_MX_PIN(tdc->pin_nr),
+ AD9545_MX_TO_TDCX(tdc->address));
+ if (ret < 0)
+ return ret;
+
+ init[i].name = ad9545_aux_tdc_clk_names[i];
+ init[i].ops = &ad9545_aux_tdc_clk_ops;
+ init[i].parent_names = &ad9545_ref_m_clk_names[tdc->pin_nr];
+ init[i].num_parents = 1;
+ tdc->hw.init = &init[i];
+ ret = devm_clk_hw_register(st->dev, &tdc->hw);
+ if (ret < 0)
+ return ret;
+
+ st->clks[AD9545_CLK_AUX_TDC][i] = tdc->hw.clk;
+ }
+
+ return 0;
+}
+
+static unsigned long ad9545_aux_dpll_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ return parent_rate;
+}
+
+static const struct clk_ops ad9545_aux_dpll_clk_ops = {
+ .recalc_rate = ad9545_aux_dpll_clk_recalc_rate,
+};
+
+static int ad9545_aux_dpll_setup(struct ad9545_state *st)
+{
+ struct ad9545_aux_dpll_clk *clk;
+ struct clk_init_data init;
+ __le16 regval;
+ int ret;
+ u32 val;
+ int i;
+
+ clk = &st->aux_dpll_clk;
+ if (!clk->dpll_used)
+ return 0;
+
+ memset(&init, 0, sizeof(struct clk_init_data));
+
+ if (clk->source < ARRAY_SIZE(ad9545_in_clk_names)) {
+ val = clk->source;
+ init.parent_names = &ad9545_in_clk_names[val];
+ } else {
+ val = clk->source - ARRAY_SIZE(ad9545_in_clk_names);
+ if (val > ARRAY_SIZE(ad9545_aux_tdc_clk_names))
+ return -EINVAL;
+ init.parent_names = &ad9545_aux_tdc_clk_names[val];
+ val = val + 0x6;
+ }
+
+ ret = regmap_write(st->regmap, AD9545_AUX_DPLL_SOURCE, val);
+ if (ret < 0)
+ return ret;
+
+ /* write loop bandwidth in dHz */
+ regval = cpu_to_le16(clk->loop_bw_mhz / 100);
+ ret = regmap_bulk_write(st->regmap, AD9545_AUX_DPLL_LOOP_BW, &regval, 2);
+ if (ret < 0)
+ return ret;
+
+ val = 0;
+ for (i = 0; i < ARRAY_SIZE(ad9545_rate_change_limit_map); i++) {
+ if (ad9545_rate_change_limit_map[i] == clk->rate_change_limit) {
+ val = i;
+ break;
+ }
+ }
+
+ ret = regmap_write(st->regmap, AD9545_AUX_DPLL_CHANGE_LIMIT, val);
+ if (ret < 0)
+ return ret;
+
+ /* add compensation destination */
+ ret = regmap_write(st->regmap, AD9545_COMPENSATE_DPLL, AD9545_COMPNESATE_VIA_AUX_DPLL);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD9545_COMPENSATE_TDCS, AD9545_COMPENSATE_TDCS_VIA_AUX_DPLL);
+ if (ret < 0)
+ return ret;
+
+ init.name = ad9545_aux_dpll_name;
+ init.ops = &ad9545_aux_dpll_clk_ops;
+ init.num_parents = 1;
+
+ clk->hw.init = &init;
+ return devm_clk_hw_register(st->dev, &clk->hw);
+}
+
+static int ad9545_calib_system_clock(struct ad9545_state *st)
+{
+ int ret;
+ u32 reg;
+ int i;
+ int j;
+
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < ARRAY_SIZE(ad9545_vco_calibration_op); j++) {
+ ret = regmap_write(st->regmap, ad9545_vco_calibration_op[j][0],
+ ad9545_vco_calibration_op[j][1]);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* wait for sys pll to lock and become stable */
+ msleep(50 + AD9545_SYS_CLK_STABILITY_MS);
+
+ ret = regmap_read(st->regmap, AD9545_PLL_STATUS, &reg);
+ if (ret < 0)
+ return ret;
+
+ if (AD9545_SYS_PLL_STABLE(reg)) {
+ ret = regmap_write(st->regmap, AD9545_CALIB_CLK, 0);
+ if (ret < 0)
+ return ret;
+
+ return ad9545_io_update(st);
+ }
+ }
+
+ dev_err(st->dev, "System PLL unlocked.\n");
+ return -EIO;
+}
+
+static int ad9545_calib_apll(struct ad9545_state *st, int i)
+{
+ int cal_count;
+ u32 reg;
+ int ret;
+
+ /* APLL VCO calibration operation */
+ cal_count = 0;
+ while (cal_count < 2) {
+ ret = regmap_write(st->regmap, AD9545_PWR_CALIB_CHX(i), 0);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_io_update(st);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD9545_PWR_CALIB_CHX(i),
+ AD9545_CALIB_APLL);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_io_update(st);
+ if (ret < 0)
+ return ret;
+
+ cal_count += 1;
+ msleep(100);
+
+ ret = regmap_read(st->regmap, AD9545_PLLX_STATUS(i), &reg);
+ if (ret < 0)
+ return ret;
+
+ if (AD9545_APLL_LOCKED(reg)) {
+ ret = regmap_write(st->regmap, AD9545_PWR_CALIB_CHX(i), 0);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_io_update(st);
+ if (ret < 0)
+ return ret;
+
+ cal_count = 2;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int ad9545_calib_aplls(struct ad9545_state *st)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ad9545_pll_clk_names); i++) {
+ if (!st->pll_clks[i].pll_used)
+ continue;
+
+ ret = ad9545_calib_apll(st, i);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct clk *ad9545_clk_src_twocell_get(struct of_phandle_args *clkspec, void *data)
+{
+ unsigned int clk_address = clkspec->args[1];
+ unsigned int clk_type = clkspec->args[0];
+ struct clk ***clks = data;
+
+ if (clk_type > AD9545_CLK_AUX_TDC) {
+ pr_err("%s: invalid clock type %u\n", __func__, clk_type);
+ return ERR_PTR(-EINVAL);
+ }
+ if ((clk_type == AD9545_CLK_PLL && clk_address > AD9545_PLL1) ||
+ (clk_type == AD9545_CLK_OUT && clk_address > AD9545_Q1BB) ||
+ (clk_type == AD9545_CLK_NCO && clk_address > AD9545_NCO1) ||
+ (clk_type == AD9545_CLK_AUX_TDC && clk_address > AD9545_CLK_AUX_TDC1)) {
+ pr_err("%s: invalid clock address %u\n", __func__, clk_address);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return clks[clk_type][clk_address];
+}
+
+static int ad9545_setup(struct ad9545_state *st)
+{
+ int ret;
+ u32 val;
+ int i;
+
+ ret = regmap_update_bits(st->regmap, AD9545_CONFIG_0, AD9545_RESET_REGS, AD9545_RESET_REGS);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_sys_clk_setup(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_input_refs_setup(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_aux_ncos_setup(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_calib_system_clock(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_aux_tdcs_setup(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_aux_dpll_setup(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_calib_aplls(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_io_update(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_plls_setup(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_outputs_setup(st);
+ if (ret < 0)
+ return ret;
+
+ ret = of_clk_add_provider(st->dev->of_node, ad9545_clk_src_twocell_get,
+ &st->clks[AD9545_CLK_OUT]);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_calib_aplls(st);
+ if (ret < 0)
+ return ret;
+
+ /* check locks */
+ ret = regmap_read(st->regmap, AD9545_PLL_STATUS, &val);
+ for (i = 0; i < ARRAY_SIZE(st->pll_clks); i++)
+ if (st->pll_clks[i].pll_used && !AD9545_PLLX_LOCK(i, val))
+ dev_warn(st->dev, "PLL%d unlocked.\n", i);
+
+ if (st->aux_dpll_clk.dpll_used) {
+ ret = regmap_read(st->regmap, AD9545_MISC, &val);
+ if (ret < 0)
+ return ret;
+
+ if (!(val & AD9545_AUX_DPLL_LOCK_MSK))
+ dev_warn(st->dev, "Aux DPLL unlocked.\n");
+
+ if (val & AD9545_AUX_DPLL_REF_FAULT)
+ dev_warn(st->dev, "Aux DPLL reference fault.\n");
+ }
+
+ return 0;
+}
+
+int ad9545_probe(struct device *dev, struct regmap *regmap)
+{
+ struct ad9545_state *st;
+ int ret;
+
+ st = devm_kzalloc(dev, sizeof(struct ad9545_state), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->dev = dev;
+ st->regmap = regmap;
+
+ ret = ad9545_check_id(st);
+ if (ret < 0)
+ return ret;
+
+ ret = ad9545_parse_dt(st);
+ if (ret < 0)
+ return ret;
+
+ return ad9545_setup(st);
+}
+EXPORT_SYMBOL_GPL(ad9545_probe);
+
+MODULE_AUTHOR("Alexandru Tachici <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices AD9545");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/clk/adi/clk-ad9545.h b/drivers/clk/adi/clk-ad9545.h
new file mode 100644
index 000000000000..641acabe9c8e
--- /dev/null
+++ b/drivers/clk/adi/clk-ad9545.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * AD9545 Network Clock Generator/Synchronizer
+ *
+ * Copyright 2020 Analog Devices Inc.
+ */
+
+#ifndef _CLK_AD9545_H_
+#define _CLK_AD9545_H_
+
+struct device;
+struct regmap;
+
+int ad9545_probe(struct device *dev, struct regmap *regmap);
+
+#endif /* _CLK_AD9545_H_ */
--
2.25.1

2021-06-14 07:03:19

by Alexandru Tachici

[permalink] [raw]
Subject: [PATCH v2 2/2] dt-bindings: clock: ad9545: Add documentation

From: Alexandru Tachici <[email protected]>

Add dt bindings for ad9545.

Signed-off-by: Alexandru Tachici <[email protected]>
---
.../devicetree/bindings/clock/clk-ad9545.yaml | 556 ++++++++++++++++++
include/dt-bindings/clock/ad9545.h | 69 +++
2 files changed, 625 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/clk-ad9545.yaml
create mode 100644 include/dt-bindings/clock/ad9545.h

diff --git a/Documentation/devicetree/bindings/clock/clk-ad9545.yaml b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml
new file mode 100644
index 000000000000..50553a88ab44
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml
@@ -0,0 +1,556 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/clk-ad9545.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD9545 Quad Input, 10-Output, Dual DPLL/IEEE 1588
+
+maintainers:
+ - Alexandru Tachici <[email protected]>
+
+description: |
+ Analog Devices AD9545 Quad Input, 10-Output, Dual DPLL/IEEE 1588,
+ 1 pps Synchronizer and Jitter Cleaner
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1266.pdf
+
+properties:
+ compatible:
+ enum:
+ - adi,ad9545
+
+ "#clock-cells":
+ const: 2
+
+ reg:
+ description: |
+ I2C address of the secondary device.
+ minimum: 0
+ maximum: 0xFF
+
+ avcc-supply:
+ description: |
+ Phandle to the Avcc power supply.
+
+ adi,freq-doubler:
+ description: |
+ The system clock PLL provides the user with the option of doubling the reference frequency.
+ type: boolean
+
+ adi,ref-crystal:
+ description: |
+ At XOA,XOB there is a crystal connected that needs maintaining.
+ Otherwise it is assumed that there is a TCXO or OCXO connected.
+ type: boolean
+
+ adi,ref-frequency-hz:
+ description: |
+ Reference input frequency at XOA,XOB. This is used for the system clock.
+
+ clocks:
+ items:
+ - description: Ref A clock input
+ - description: Ref AA clock input
+ - description: Ref B clock input
+ - description: Ref BB clock input
+ - description: Ref M0 clock input
+ - description: Ref M1 clock input
+ - description: Ref M2 clock input
+ maxItems: 4
+
+ assigned-clocks:
+ description:
+ Clocks are identified using two cells <&ad9545 clock_type clock_address>.
+ minItems: 1
+ maxItems: 14
+
+ assigned-clock-rates:
+ minItems: 1
+ maxItems: 14
+
+ assigned-clock-phases:
+ minItems: 1
+ maxItems: 14
+
+ clock-output-names:
+ maxItems: 10
+
+ aux-dpll:
+ description: |
+ Auxiliary DPLL used for Closed-Loop method of system clock compensation.
+ type: object
+
+ properties:
+ adi,compensation-source:
+ description: |
+ System clock closed loop compensation source.
+ Choose from Ref-A to Ref-BB [0-3] or aux TDCs [4-5].
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1, 2, 3, 4, 5]
+
+ adi,aux-dpll-bw-mhz:
+ description: |
+ Auxiliary DPLL bandwidth.
+ minimum: 100
+ maximum: 2000000
+
+ adi,rate-change-limit:
+ description: |
+ Error compensation rate change limiting expressed in ppb/s. Disabled if property is
+ missing.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [715, 1430, 2860, 5720, 11440, 22880, 45760]
+
+ required:
+ - adi,compensation-source
+ - adi,aux-dpll-bw-mhz
+
+ aux-tdc-clks:
+ description: |
+ Child nodes represent Mx pin reference clock inputs.
+ type: object
+
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ "^aux-tdc-clk@[0-3]$":
+
+ description: |
+ Represents a Mx pin reference clock input.
+ type: object
+
+ properties:
+ reg:
+ description: |
+ Address of the Auxiliary TDC.
+ maximum: 1
+
+ adi,pin-nr:
+ description: |
+ Pin number to be the source of this TDC.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 6
+
+ required:
+ - reg
+ - adi,pin-nr
+
+ additionalProperties: false
+
+ ref-input-clks:
+ description: |
+ Child nodes represent reference clock inputs.
+ type: object
+
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ "^ref-input-clk@[0-3]$":
+ description: |
+ Represents a reference clock input.
+ type: object
+
+ properties:
+ reg:
+ description: |
+ The reference input number. It can have up to 4 input clocks numbered from 0 to 3.
+ (mapped: [refa, refaa, refb, refbb] -> [0, 1, 2, 3])
+ maxItems: 1
+
+ adi,single-ended-mode:
+ description: |
+ Single-ended configuration mode.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1, 2, 3]
+
+ adi,differential-mode:
+ description: |
+ Differential configuration mode.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1, 2]
+
+ adi,r-divider-ratio:
+ description: |
+ Each reference input has a dedicated divider.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 1073741824
+
+ adi,ref-dtol-pbb:
+ description: |
+ REFx offset limit. Constitutes a fractional portion of the corresponding nominal period.
+ The 24-bit number represents fractional units of parts per billion (ppb) up to a
+ maximum of approximately 17 million ppb (1.7%).
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 16777215
+ default: 100000
+
+ adi,ref-monitor-hysteresis-pbb:
+ description: |
+ Basis points of the offset limit representing per ten thousand of REFx offset limit.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 3125, 6250, 12500, 25000, 50000, 75000, 87500]
+ default: 12500
+
+ adi,ref-validation-timer-ms:
+ description: |
+ Time required for a reference to remain in tolerance condition before being
+ available to be used.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 1048574
+ default: 10
+
+ adi,freq-lock-threshold-ps:
+ description: |
+ Phase lock detector threshold (in picoseconds).
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 16777215
+
+ adi,phase-lock-threshold-ps:
+ description: |
+ Profile 0 frequency lock threshold. Frequency lock detector threshold (in picoseconds).
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 16777215
+
+ adi,phase-lock-fill-rate:
+ description: |
+ Parameter used by the DPLL Phase Lock Detector.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 255
+ default: 10
+
+ adi,phase-lock-drain-rate:
+ description: |
+ Parameter used by the DPLL Phase Lock Detector.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 255
+ default: 10
+
+ adi,freq-lock-fill-rate:
+ description: |
+ Parameter used by the DPLL Frequency Lock Detector.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 255
+ default: 10
+
+ adi,freq-lock-drain-rate:
+ description: |
+ Parameter used by the DPLL Frequency Lock Detector.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 255
+ default: 10
+
+ required:
+ - reg
+ - adi,r-divider-ratio
+ - adi,ref-dtol-pbb
+ - adi,ref-monitor-hysteresis-pbb
+ - adi,ref-validation-timer-ms
+ - adi,freq-lock-threshold-ps
+ - adi,phase-lock-threshold-ps
+
+ additionalProperties: false
+
+ pll-clks:
+ description: |
+ Child nodes represent PLLs.
+ type: object
+
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ "^pll-clk@[0-1]$":
+ description: |
+ Represents a PLL.
+ type: object
+
+ properties:
+ reg:
+ description: |
+ PLL number. AD9545 has two PLLs.
+ maxItems: 1
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ adi,fast-acq-trigger-mode:
+ description: |
+ If this is not specified Fast Acquisition will be used every time. See reg 0x2106
+ for constraints on Fast Acquisition trigger.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 15
+ default: 0
+
+ patternProperties:
+ "^profile@[0-5]$":
+ description: |
+ Represents a DPLL profile. Each DPLL can have up to 6 specified sources
+ wih priorities assigned.
+ type: object
+
+ properties:
+ reg:
+ description: |
+ Profile number. A DPLL can have up to 6 translation profiles.
+ maxItems: 1
+ adi,profile-priority:
+ description: |
+ Profile selection priority. 0 is the highest, 31 is the lowest. For revertive
+ reference switching, ensure that priority difference is > 7.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 31
+
+ adi,pll-source:
+ description: |
+ Each PLL can have 1 signal source. Choose from Ref-A to Ref-BB [0-3] or aux NCOs [4-5].
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1, 2, 3, 4, 5]
+
+ adi,pll-loop-bandwidth-uhz:
+ description: |
+ PLL loop bandwidth in microhertz.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 1850000000
+ default: 200000000
+
+ adi,fast-acq-excess-bw:
+ description: |
+ Controls the DPLL loop bandwidth scaling factor while in fast acquisition mode.
+ 0 means this feature is disabled.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
+ default: 0
+
+ adi,fast-acq-timeout-ms:
+ description: |
+ Fast acquisition timeout controls the maximum amount of time that DPLL waits to
+ achieve phase lock before reducing the loop bandwidth by a factor of two.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [1, 10, 50, 100, 500, 1000, 10000, 50000]
+ default: 1
+
+ adi,fast-acq-lock-settle-ms:
+ description: |
+ Controls how long DPLL must wait after achieving phase lock before reducing
+ the loop bandwidth by a factor of 2.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [1, 10, 50, 100, 500, 1000, 10000, 50000]
+ default: 1
+
+ required:
+ - reg
+ - adi,pll-source
+ - adi,pll-loop-bandwidth-uhz
+
+ additionalProperties: false
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+ aux-ncos:
+ description: |
+ Child nodes represent auxiliary Numerical Controlled Oscilators.
+ type: object
+
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ "^aux-nco-clk@[0-1]$":
+ description: |
+ Represents an auxiliary Numerical Controlled Oscilator. Generates timestamps that
+ can be sent to the DPLL0 or DPLL1.
+ type: object
+
+ properties:
+ reg:
+ description: |
+ Auxiliary NCO address mapped: [NCO0, NCO1] -> [0, 1].
+ maxItems: 1
+
+ adi,freq-lock-threshold-ps:
+ description: |
+ Phase lock detector threshold (in picoseconds).
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 16777215
+
+ adi,phase-lock-threshold-ps:
+ description: |
+ Profile 0 frequency lock threshold. Frequency lock detector threshold (in picoseconds).
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 1
+ maximum: 16777215
+
+ required:
+ - reg
+ - adi,freq-lock-threshold-ps
+ - adi,phase-lock-threshold-ps
+
+ additionalProperties: false
+
+ output-clks:
+ description: |
+ Child nodes represent clock outputs.
+ type: object
+
+ properties:
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+ patternProperties:
+ "^output-clk@([0-9]|1[0-3])$":
+ description: |
+ Represents a clock output.
+ type: object
+
+ properties:
+ reg:
+ description: |
+ The reference input number. It can have up to 10 output clocks mapped:
+ (OUT0AP OUT0AN OUT0BP OUT0BN OUT0CP OUT0CN OUT1AP OUT1AN OUT1BP OUT1BN) ->
+ (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
+ maxItems: 1
+
+ adi,current-source:
+ description: |
+ If specified output is set as current source.
+ type: boolean
+
+ adi,current-source-microamp:
+ description: |
+ The magnitude of the driver current.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [7500, 12500, 15000]
+
+ adi,output-mode:
+ description: |
+ Output driver mode.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1, 2]
+
+ required:
+ - reg
+ - adi,current-source-microamp
+ - adi,output-mode
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - adi,ref-frequency-hz
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/ad9545.h>
+
+ i2c1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ad9545_clock: ad9545@4A {
+ compatible = "adi,ad9545";
+ reg = <0x4A>;
+
+ adi,ref-crystal;
+ adi,ref-frequency-hz = <52000000>;
+
+ #clock-cells = <2>;
+ assigned-clocks = <&ad9545_clock AD9545_CLK_NCO AD9545_NCO0>,
+ <&ad9545_clock AD9545_CLK_PLL AD9545_PLL1>,
+ <&ad9545_clock AD9545_CLK_OUT AD9545_Q1A>,
+ <&ad9545_clock AD9545_CLK_OUT AD9545_Q1B>;
+ assigned-clock-rates = <10000>, <1875000000>, <156250000>, <156250000>;
+ assigned-clock-phases = <0>, <0>, <0>, <180>;
+
+ aux-ncos {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ aux-nco-clk@AD9545_NCO0 {
+ reg = <AD9545_NCO0>;
+ adi,freq-lock-threshold-ps = <16000000>;
+ adi,phase-lock-threshold-ps = <16000000>;
+ };
+ };
+
+ pll-clks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ad9545_apll1: pll-clk@AD9545_PLL1 {
+ reg = <AD9545_PLL1>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ profile@0 {
+ reg = <0>;
+ adi,pll-source = <4>;
+ adi,profile-priority = <0>;
+ adi,pll-loop-bandwidth-uhz = <200000000>;
+ };
+ };
+ };
+
+ output-clks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ output-clk@AD9545_Q1A {
+ reg = <AD9545_Q1A>;
+ adi,output-mode = <DRIVER_MODE_DUAL_DIV>;
+ adi,current-source-microamp = <15000>;
+ };
+
+ output-clk@AD9545_Q1B {
+ reg = <AD9545_Q1B>;
+ adi,output-mode = <DRIVER_MODE_DUAL_DIV>;
+ adi,current-source-microamp = <15000>;
+ };
+ };
+ };
+ };
+...
diff --git a/include/dt-bindings/clock/ad9545.h b/include/dt-bindings/clock/ad9545.h
new file mode 100644
index 000000000000..857d50e5715b
--- /dev/null
+++ b/include/dt-bindings/clock/ad9545.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+/*
+ * AD9545 Network Clock Generator/Synchronizer
+ *
+ * Copyright 2020 Analog Devices Inc.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_AD9545_H_
+#define _DT_BINDINGS_CLOCK_AD9545_H_
+
+/* Input Driver Mode
+ * Use for adi,single-ended-mode:
+ */
+#define DRIVER_MODE_AC_COUPLED_IF 0
+#define DRIVER_MODE_DC_COUPLED_1V2 1
+#define DRIVER_MODE_DC_COUPLED_1V8 2
+#define DRIVER_MODE_IN_PULL_UP 3
+
+/* Input Driver Mode
+ * Use for adi,differential-mode:
+ */
+#define DRIVER_MODE_AC_COUPLED 0
+#define DRIVER_MODE_DC_COUPLED 1
+#define DRIVER_MODE_DC_COUPLED_LVDS 2
+
+/* Output Driver Mode
+ * Use for adi,output-mode:
+ */
+#define DRIVER_MODE_SINGLE_DIV_DIF 0
+#define DRIVER_MODE_SINGLE_DIV 1
+#define DRIVER_MODE_DUAL_DIV 2
+
+/* Clock types */
+#define AD9545_CLK_OUT 0
+#define AD9545_CLK_PLL 1
+#define AD9545_CLK_NCO 2
+#define AD9545_CLK_AUX_TDC 3
+
+/* PLL addresses */
+#define AD9545_PLL0 0
+#define AD9545_PLL1 1
+
+/* Outputs addresses */
+#define AD9545_Q0A 0
+#define AD9545_Q0AA 1
+#define AD9545_Q0B 2
+#define AD9545_Q0BB 3
+#define AD9545_Q0C 4
+#define AD9545_Q0CC 5
+#define AD9545_Q1A 6
+#define AD9545_Q1AA 7
+#define AD9545_Q1B 8
+#define AD9545_Q1BB 9
+
+/* NCO addresses */
+#define AD9545_NCO0 0
+#define AD9545_NCO1 1
+
+/* TDC addresses */
+#define AD9545_CLK_AUX_TDC0 0
+#define AD9545_CLK_AUX_TDC1 1
+
+/* Ex:
+ * Output Q0C clock: <&ad9545_clock AD9545_CLK_OUT AD9545_Q0C>;
+ * PLL0 clock: <&ad9545_clock AD9545_CLK_PLL AD9545_PLL0>;
+ * NCO1 clock: <&ad9545_clock AD9545_CLK_NCO AD9545_NCO1>;
+ */
+
+#endif /* _DT_BINDINGS_CLOCK_AD9545_H_ */
--
2.25.1

2021-06-14 13:41:21

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] dt-bindings: clock: ad9545: Add documentation

On Mon, 14 Jun 2021 10:07:18 +0300, [email protected] wrote:
> From: Alexandru Tachici <[email protected]>
>
> Add dt bindings for ad9545.
>
> Signed-off-by: Alexandru Tachici <[email protected]>
> ---
> .../devicetree/bindings/clock/clk-ad9545.yaml | 556 ++++++++++++++++++
> include/dt-bindings/clock/ad9545.h | 69 +++
> 2 files changed, 625 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/clk-ad9545.yaml
> create mode 100644 include/dt-bindings/clock/ad9545.h
>

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:115:10: [warning] wrong indentation: expected 8 but found 9 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:118:10: [warning] wrong indentation: expected 8 but found 9 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:153:10: [warning] wrong indentation: expected 8 but found 9 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:156:10: [warning] wrong indentation: expected 8 but found 9 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:280:10: [warning] wrong indentation: expected 8 but found 9 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:283:10: [warning] wrong indentation: expected 8 but found 9 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:298:14: [warning] wrong indentation: expected 12 but found 13 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:301:14: [warning] wrong indentation: expected 12 but found 13 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:389:10: [warning] wrong indentation: expected 8 but found 9 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:392:10: [warning] wrong indentation: expected 8 but found 9 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:435:10: [warning] wrong indentation: expected 8 but found 9 (indentation)
./Documentation/devicetree/bindings/clock/clk-ad9545.yaml:438:10: [warning] wrong indentation: expected 8 but found 9 (indentation)

dtschema/dtc warnings/errors:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/clock/clk-ad9545.example.dt.yaml: ad9545@4A: 'clocks' is a dependency of 'assigned-clocks'
From schema: /usr/local/lib/python3.8/dist-packages/dtschema/schemas/clock/clock.yaml
\ndoc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1491545

This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit.

2021-06-15 22:52:25

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] dt-bindings: clock: ad9545: Add documentation

On Mon, Jun 14, 2021 at 10:07:18AM +0300, [email protected] wrote:
> From: Alexandru Tachici <[email protected]>
>
> Add dt bindings for ad9545.

Kind of a lot of properties, not really sure what to do about that...

>
> Signed-off-by: Alexandru Tachici <[email protected]>
> ---
> .../devicetree/bindings/clock/clk-ad9545.yaml | 556 ++++++++++++++++++
> include/dt-bindings/clock/ad9545.h | 69 +++
> 2 files changed, 625 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/clk-ad9545.yaml
> create mode 100644 include/dt-bindings/clock/ad9545.h
>
> diff --git a/Documentation/devicetree/bindings/clock/clk-ad9545.yaml b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml
> new file mode 100644
> index 000000000000..50553a88ab44
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/clk-ad9545.yaml
> @@ -0,0 +1,556 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/clk-ad9545.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Analog Devices AD9545 Quad Input, 10-Output, Dual DPLL/IEEE 1588
> +
> +maintainers:
> + - Alexandru Tachici <[email protected]>
> +
> +description: |
> + Analog Devices AD9545 Quad Input, 10-Output, Dual DPLL/IEEE 1588,
> + 1 pps Synchronizer and Jitter Cleaner
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1266.pdf
> +
> +properties:
> + compatible:
> + enum:
> + - adi,ad9545
> +
> + "#clock-cells":
> + const: 2
> +
> + reg:
> + description: |

Don't need '|' if there's no formatting or anything that has to be
escaped.

Same applies elsewhere.

> + I2C address of the secondary device.
> + minimum: 0
> + maximum: 0xFF
> +
> + avcc-supply:
> + description: |
> + Phandle to the Avcc power supply.
> +
> + adi,freq-doubler:
> + description: |
> + The system clock PLL provides the user with the option of doubling the reference frequency.
> + type: boolean
> +
> + adi,ref-crystal:
> + description: |
> + At XOA,XOB there is a crystal connected that needs maintaining.
> + Otherwise it is assumed that there is a TCXO or OCXO connected.
> + type: boolean
> +
> + adi,ref-frequency-hz:
> + description: |
> + Reference input frequency at XOA,XOB. This is used for the system clock.
> +
> + clocks:
> + items:
> + - description: Ref A clock input
> + - description: Ref AA clock input
> + - description: Ref B clock input
> + - description: Ref BB clock input
> + - description: Ref M0 clock input
> + - description: Ref M1 clock input
> + - description: Ref M2 clock input
> + maxItems: 4

Looks like 7 is the max...

> +
> + assigned-clocks:
> + description:
> + Clocks are identified using two cells <&ad9545 clock_type clock_address>.
> + minItems: 1
> + maxItems: 14
> +
> + assigned-clock-rates:
> + minItems: 1
> + maxItems: 14
> +
> + assigned-clock-phases:
> + minItems: 1
> + maxItems: 14
> +
> + clock-output-names:
> + maxItems: 10
> +
> + aux-dpll:
> + description: |
> + Auxiliary DPLL used for Closed-Loop method of system clock compensation.
> + type: object
> +
> + properties:
> + adi,compensation-source:
> + description: |
> + System clock closed loop compensation source.
> + Choose from Ref-A to Ref-BB [0-3] or aux TDCs [4-5].
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [0, 1, 2, 3, 4, 5]
> +
> + adi,aux-dpll-bw-mhz:
> + description: |
> + Auxiliary DPLL bandwidth.
> + minimum: 100
> + maximum: 2000000
> +
> + adi,rate-change-limit:
> + description: |
> + Error compensation rate change limiting expressed in ppb/s. Disabled if property is
> + missing.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [715, 1430, 2860, 5720, 11440, 22880, 45760]
> +
> + required:
> + - adi,compensation-source
> + - adi,aux-dpll-bw-mhz
> +
> + aux-tdc-clks:
> + description: |
> + Child nodes represent Mx pin reference clock inputs.
> + type: object
> +
> + properties:
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> + patternProperties:
> + "^aux-tdc-clk@[0-3]$":
> +
> + description: |
> + Represents a Mx pin reference clock input.
> + type: object
> +
> + properties:
> + reg:
> + description: |
> + Address of the Auxiliary TDC.
> + maximum: 1

0-3 as the unit-address says or only 1?

> +
> + adi,pin-nr:
> + description: |
> + Pin number to be the source of this TDC.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 0
> + maximum: 6
> +
> + required:
> + - reg
> + - adi,pin-nr
> +
> + additionalProperties: false
> +
> + ref-input-clks:
> + description: |
> + Child nodes represent reference clock inputs.
> + type: object
> +
> + properties:
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> + patternProperties:
> + "^ref-input-clk@[0-3]$":
> + description: |
> + Represents a reference clock input.
> + type: object
> +
> + properties:
> + reg:
> + description: |
> + The reference input number. It can have up to 4 input clocks numbered from 0 to 3.
> + (mapped: [refa, refaa, refb, refbb] -> [0, 1, 2, 3])
> + maxItems: 1
> +
> + adi,single-ended-mode:
> + description: |
> + Single-ended configuration mode.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [0, 1, 2, 3]
> +
> + adi,differential-mode:
> + description: |
> + Differential configuration mode.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [0, 1, 2]
> +
> + adi,r-divider-ratio:
> + description: |
> + Each reference input has a dedicated divider.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 1073741824
> +
> + adi,ref-dtol-pbb:
> + description: |
> + REFx offset limit. Constitutes a fractional portion of the corresponding nominal period.
> + The 24-bit number represents fractional units of parts per billion (ppb) up to a
> + maximum of approximately 17 million ppb (1.7%).
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 0
> + maximum: 16777215
> + default: 100000
> +
> + adi,ref-monitor-hysteresis-pbb:
> + description: |
> + Basis points of the offset limit representing per ten thousand of REFx offset limit.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [0, 3125, 6250, 12500, 25000, 50000, 75000, 87500]
> + default: 12500
> +
> + adi,ref-validation-timer-ms:
> + description: |
> + Time required for a reference to remain in tolerance condition before being
> + available to be used.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 1048574
> + default: 10
> +
> + adi,freq-lock-threshold-ps:
> + description: |
> + Phase lock detector threshold (in picoseconds).
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 16777215
> +
> + adi,phase-lock-threshold-ps:
> + description: |
> + Profile 0 frequency lock threshold. Frequency lock detector threshold (in picoseconds).
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 16777215
> +
> + adi,phase-lock-fill-rate:
> + description: |
> + Parameter used by the DPLL Phase Lock Detector.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 255
> + default: 10
> +
> + adi,phase-lock-drain-rate:
> + description: |
> + Parameter used by the DPLL Phase Lock Detector.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 255
> + default: 10
> +
> + adi,freq-lock-fill-rate:
> + description: |
> + Parameter used by the DPLL Frequency Lock Detector.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 255
> + default: 10
> +
> + adi,freq-lock-drain-rate:
> + description: |
> + Parameter used by the DPLL Frequency Lock Detector.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 255
> + default: 10
> +
> + required:
> + - reg
> + - adi,r-divider-ratio
> + - adi,ref-dtol-pbb
> + - adi,ref-monitor-hysteresis-pbb
> + - adi,ref-validation-timer-ms
> + - adi,freq-lock-threshold-ps
> + - adi,phase-lock-threshold-ps
> +
> + additionalProperties: false
> +
> + pll-clks:
> + description: |
> + Child nodes represent PLLs.
> + type: object
> +
> + properties:
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> + patternProperties:
> + "^pll-clk@[0-1]$":
> + description: |
> + Represents a PLL.
> + type: object
> +
> + properties:
> + reg:
> + description: |
> + PLL number. AD9545 has two PLLs.
> + maxItems: 1
> +
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> + adi,fast-acq-trigger-mode:
> + description: |
> + If this is not specified Fast Acquisition will be used every time. See reg 0x2106
> + for constraints on Fast Acquisition trigger.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 0
> + maximum: 15
> + default: 0
> +
> + patternProperties:
> + "^profile@[0-5]$":
> + description: |
> + Represents a DPLL profile. Each DPLL can have up to 6 specified sources
> + wih priorities assigned.
> + type: object
> +
> + properties:
> + reg:
> + description: |
> + Profile number. A DPLL can have up to 6 translation profiles.
> + maxItems: 1

Blank line

> + adi,profile-priority:
> + description: |
> + Profile selection priority. 0 is the highest, 31 is the lowest. For revertive
> + reference switching, ensure that priority difference is > 7.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 0
> + maximum: 31
> +
> + adi,pll-source:
> + description: |
> + Each PLL can have 1 signal source. Choose from Ref-A to Ref-BB [0-3] or aux NCOs [4-5].
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [0, 1, 2, 3, 4, 5]
> +
> + adi,pll-loop-bandwidth-uhz:
> + description: |
> + PLL loop bandwidth in microhertz.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 1850000000
> + default: 200000000
> +
> + adi,fast-acq-excess-bw:
> + description: |
> + Controls the DPLL loop bandwidth scaling factor while in fast acquisition mode.
> + 0 means this feature is disabled.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
> + default: 0
> +
> + adi,fast-acq-timeout-ms:
> + description: |
> + Fast acquisition timeout controls the maximum amount of time that DPLL waits to
> + achieve phase lock before reducing the loop bandwidth by a factor of two.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [1, 10, 50, 100, 500, 1000, 10000, 50000]
> + default: 1
> +
> + adi,fast-acq-lock-settle-ms:
> + description: |
> + Controls how long DPLL must wait after achieving phase lock before reducing
> + the loop bandwidth by a factor of 2.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [1, 10, 50, 100, 500, 1000, 10000, 50000]
> + default: 1
> +
> + required:
> + - reg
> + - adi,pll-source
> + - adi,pll-loop-bandwidth-uhz
> +
> + additionalProperties: false
> +
> + required:
> + - reg
> +
> + additionalProperties: false
> +
> + aux-ncos:
> + description: |
> + Child nodes represent auxiliary Numerical Controlled Oscilators.
> + type: object
> +
> + properties:
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> + patternProperties:
> + "^aux-nco-clk@[0-1]$":
> + description: |
> + Represents an auxiliary Numerical Controlled Oscilator. Generates timestamps that
> + can be sent to the DPLL0 or DPLL1.
> + type: object
> +
> + properties:
> + reg:
> + description: |
> + Auxiliary NCO address mapped: [NCO0, NCO1] -> [0, 1].
> + maxItems: 1
> +
> + adi,freq-lock-threshold-ps:
> + description: |
> + Phase lock detector threshold (in picoseconds).
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 16777215
> +
> + adi,phase-lock-threshold-ps:
> + description: |
> + Profile 0 frequency lock threshold. Frequency lock detector threshold (in picoseconds).
> + $ref: /schemas/types.yaml#/definitions/uint32
> + minimum: 1
> + maximum: 16777215
> +
> + required:
> + - reg
> + - adi,freq-lock-threshold-ps
> + - adi,phase-lock-threshold-ps
> +
> + additionalProperties: false
> +
> + output-clks:
> + description: |
> + Child nodes represent clock outputs.
> + type: object
> +
> + properties:
> + '#address-cells':
> + const: 1
> +
> + '#size-cells':
> + const: 0
> +
> + patternProperties:
> + "^output-clk@([0-9]|1[0-3])$":
> + description: |
> + Represents a clock output.
> + type: object
> +
> + properties:
> + reg:
> + description: |
> + The reference input number. It can have up to 10 output clocks mapped:
> + (OUT0AP OUT0AN OUT0BP OUT0BN OUT0CP OUT0CN OUT1AP OUT1AN OUT1BP OUT1BN) ->
> + (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Looks like constraints (maximum: 9).

> + maxItems: 1
> +
> + adi,current-source:
> + description: |
> + If specified output is set as current source.
> + type: boolean
> +
> + adi,current-source-microamp:
> + description: |
> + The magnitude of the driver current.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [7500, 12500, 15000]
> +
> + adi,output-mode:
> + description: |
> + Output driver mode.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + enum: [0, 1, 2]
> +
> + required:
> + - reg
> + - adi,current-source-microamp
> + - adi,output-mode
> +
> + additionalProperties: false
> +
> +required:
> + - compatible
> + - reg
> + - adi,ref-frequency-hz
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/ad9545.h>
> +
> + i2c1 {

i2c {

> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ad9545_clock: ad9545@4A {

clock-controller@4a

> + compatible = "adi,ad9545";
> + reg = <0x4A>;
> +
> + adi,ref-crystal;
> + adi,ref-frequency-hz = <52000000>;
> +
> + #clock-cells = <2>;
> + assigned-clocks = <&ad9545_clock AD9545_CLK_NCO AD9545_NCO0>,
> + <&ad9545_clock AD9545_CLK_PLL AD9545_PLL1>,
> + <&ad9545_clock AD9545_CLK_OUT AD9545_Q1A>,
> + <&ad9545_clock AD9545_CLK_OUT AD9545_Q1B>;
> + assigned-clock-rates = <10000>, <1875000000>, <156250000>, <156250000>;
> + assigned-clock-phases = <0>, <0>, <0>, <180>;
> +
> + aux-ncos {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + aux-nco-clk@AD9545_NCO0 {

Can't have defines in unit addresses. We generally don't have defines
for 'reg' values.

> + reg = <AD9545_NCO0>;
> + adi,freq-lock-threshold-ps = <16000000>;
> + adi,phase-lock-threshold-ps = <16000000>;
> + };
> + };
> +
> + pll-clks {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ad9545_apll1: pll-clk@AD9545_PLL1 {
> + reg = <AD9545_PLL1>;
> +
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + profile@0 {
> + reg = <0>;
> + adi,pll-source = <4>;
> + adi,profile-priority = <0>;
> + adi,pll-loop-bandwidth-uhz = <200000000>;
> + };
> + };
> + };
> +
> + output-clks {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + output-clk@AD9545_Q1A {
> + reg = <AD9545_Q1A>;
> + adi,output-mode = <DRIVER_MODE_DUAL_DIV>;
> + adi,current-source-microamp = <15000>;
> + };
> +
> + output-clk@AD9545_Q1B {
> + reg = <AD9545_Q1B>;
> + adi,output-mode = <DRIVER_MODE_DUAL_DIV>;
> + adi,current-source-microamp = <15000>;
> + };
> + };
> + };
> + };
> +...
> diff --git a/include/dt-bindings/clock/ad9545.h b/include/dt-bindings/clock/ad9545.h
> new file mode 100644
> index 000000000000..857d50e5715b
> --- /dev/null
> +++ b/include/dt-bindings/clock/ad9545.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
> +/*
> + * AD9545 Network Clock Generator/Synchronizer
> + *
> + * Copyright 2020 Analog Devices Inc.
> + */
> +
> +#ifndef _DT_BINDINGS_CLOCK_AD9545_H_
> +#define _DT_BINDINGS_CLOCK_AD9545_H_
> +
> +/* Input Driver Mode
> + * Use for adi,single-ended-mode:
> + */
> +#define DRIVER_MODE_AC_COUPLED_IF 0
> +#define DRIVER_MODE_DC_COUPLED_1V2 1
> +#define DRIVER_MODE_DC_COUPLED_1V8 2
> +#define DRIVER_MODE_IN_PULL_UP 3
> +
> +/* Input Driver Mode
> + * Use for adi,differential-mode:
> + */
> +#define DRIVER_MODE_AC_COUPLED 0
> +#define DRIVER_MODE_DC_COUPLED 1
> +#define DRIVER_MODE_DC_COUPLED_LVDS 2
> +
> +/* Output Driver Mode
> + * Use for adi,output-mode:
> + */
> +#define DRIVER_MODE_SINGLE_DIV_DIF 0
> +#define DRIVER_MODE_SINGLE_DIV 1
> +#define DRIVER_MODE_DUAL_DIV 2
> +
> +/* Clock types */
> +#define AD9545_CLK_OUT 0
> +#define AD9545_CLK_PLL 1
> +#define AD9545_CLK_NCO 2
> +#define AD9545_CLK_AUX_TDC 3
> +
> +/* PLL addresses */
> +#define AD9545_PLL0 0
> +#define AD9545_PLL1 1
> +
> +/* Outputs addresses */
> +#define AD9545_Q0A 0
> +#define AD9545_Q0AA 1
> +#define AD9545_Q0B 2
> +#define AD9545_Q0BB 3
> +#define AD9545_Q0C 4
> +#define AD9545_Q0CC 5
> +#define AD9545_Q1A 6
> +#define AD9545_Q1AA 7
> +#define AD9545_Q1B 8
> +#define AD9545_Q1BB 9
> +
> +/* NCO addresses */
> +#define AD9545_NCO0 0
> +#define AD9545_NCO1 1
> +
> +/* TDC addresses */
> +#define AD9545_CLK_AUX_TDC0 0
> +#define AD9545_CLK_AUX_TDC1 1
> +
> +/* Ex:
> + * Output Q0C clock: <&ad9545_clock AD9545_CLK_OUT AD9545_Q0C>;
> + * PLL0 clock: <&ad9545_clock AD9545_CLK_PLL AD9545_PLL0>;
> + * NCO1 clock: <&ad9545_clock AD9545_CLK_NCO AD9545_NCO1>;
> + */
> +
> +#endif /* _DT_BINDINGS_CLOCK_AD9545_H_ */
> --
> 2.25.1

2021-06-17 03:14:04

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] dt-bindings: clock: ad9545: Add documentation

Hi,

I love your patch! Perhaps something to improve:

[auto build test WARNING on clk/clk-next]
[also build test WARNING on robh/for-next linux/master linus/master v5.13-rc6 next-20210616]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/alexandru-tachici-analog-com/clk-ad9545-Add-support/20210616-153412
base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: m68k-allmodconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/b46755cf562ff8a1a9841a4560e344099f3f054e
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review alexandru-tachici-analog-com/clk-ad9545-Add-support/20210616-153412
git checkout b46755cf562ff8a1a9841a4560e344099f3f054e
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=m68k

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> drivers/clk/adi/clk-ad9545.c:2402:5: warning: no previous prototype for 'ad9545_probe' [-Wmissing-prototypes]
2402 | int ad9545_probe(struct device *dev, struct regmap *regmap)
| ^~~~~~~~~~~~


vim +/ad9545_probe +2402 drivers/clk/adi/clk-ad9545.c

f88d17c990b731 Alexandru Tachici 2021-06-14 2401
f88d17c990b731 Alexandru Tachici 2021-06-14 @2402 int ad9545_probe(struct device *dev, struct regmap *regmap)
f88d17c990b731 Alexandru Tachici 2021-06-14 2403 {
f88d17c990b731 Alexandru Tachici 2021-06-14 2404 struct ad9545_state *st;
f88d17c990b731 Alexandru Tachici 2021-06-14 2405 int ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 2406
f88d17c990b731 Alexandru Tachici 2021-06-14 2407 st = devm_kzalloc(dev, sizeof(struct ad9545_state), GFP_KERNEL);
f88d17c990b731 Alexandru Tachici 2021-06-14 2408 if (!st)
f88d17c990b731 Alexandru Tachici 2021-06-14 2409 return -ENOMEM;
f88d17c990b731 Alexandru Tachici 2021-06-14 2410
f88d17c990b731 Alexandru Tachici 2021-06-14 2411 st->dev = dev;
f88d17c990b731 Alexandru Tachici 2021-06-14 2412 st->regmap = regmap;
f88d17c990b731 Alexandru Tachici 2021-06-14 2413
f88d17c990b731 Alexandru Tachici 2021-06-14 2414 ret = ad9545_check_id(st);
f88d17c990b731 Alexandru Tachici 2021-06-14 2415 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 2416 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 2417
f88d17c990b731 Alexandru Tachici 2021-06-14 2418 ret = ad9545_parse_dt(st);
f88d17c990b731 Alexandru Tachici 2021-06-14 2419 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 2420 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 2421
f88d17c990b731 Alexandru Tachici 2021-06-14 2422 return ad9545_setup(st);
f88d17c990b731 Alexandru Tachici 2021-06-14 2423 }
f88d17c990b731 Alexandru Tachici 2021-06-14 2424 EXPORT_SYMBOL_GPL(ad9545_probe);
f88d17c990b731 Alexandru Tachici 2021-06-14 2425

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (3.50 kB)
.config.gz (57.71 kB)
Download all attachments

2021-06-17 07:57:05

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] dt-bindings: clock: ad9545: Add documentation

Hi,

I love your patch! Perhaps something to improve:

[auto build test WARNING on clk/clk-next]
[also build test WARNING on robh/for-next linux/master linus/master v5.13-rc6 next-20210616]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/alexandru-tachici-analog-com/clk-ad9545-Add-support/20210616-153412
base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: i386-randconfig-s032-20210617 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce:
# apt-get install sparse
# sparse version: v0.6.3-341-g8af24329-dirty
# https://github.com/0day-ci/linux/commit/b46755cf562ff8a1a9841a4560e344099f3f054e
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review alexandru-tachici-analog-com/clk-ad9545-Add-support/20210616-153412
git checkout b46755cf562ff8a1a9841a4560e344099f3f054e
# save the attached .config to linux build tree
make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=i386

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>


sparse warnings: (new ones prefixed by >>)
>> drivers/clk/adi/clk-ad9545.c:1114:43: sparse: sparse: cast from restricted __le32
>> drivers/clk/adi/clk-ad9545.c:1114:43: sparse: sparse: restricted __le32 degrades to integer
>> drivers/clk/adi/clk-ad9545.c:1407:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [addressable] [assigned] [usertype] regval @@ got unsigned int freq_lock_fill_rate @@
drivers/clk/adi/clk-ad9545.c:1407:24: sparse: expected restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1407:24: sparse: got unsigned int freq_lock_fill_rate
>> drivers/clk/adi/clk-ad9545.c:1409:88: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int val @@ got restricted __le32 [addressable] [assigned] [usertype] regval @@
drivers/clk/adi/clk-ad9545.c:1409:88: sparse: expected unsigned int val
drivers/clk/adi/clk-ad9545.c:1409:88: sparse: got restricted __le32 [addressable] [assigned] [usertype] regval
>> drivers/clk/adi/clk-ad9545.c:1414:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [addressable] [assigned] [usertype] regval @@ got unsigned int freq_lock_drain_rate @@
drivers/clk/adi/clk-ad9545.c:1414:24: sparse: expected restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1414:24: sparse: got unsigned int freq_lock_drain_rate
drivers/clk/adi/clk-ad9545.c:1416:89: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int val @@ got restricted __le32 [addressable] [assigned] [usertype] regval @@
drivers/clk/adi/clk-ad9545.c:1416:89: sparse: expected unsigned int val
drivers/clk/adi/clk-ad9545.c:1416:89: sparse: got restricted __le32 [addressable] [assigned] [usertype] regval
>> drivers/clk/adi/clk-ad9545.c:1421:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [addressable] [assigned] [usertype] regval @@ got unsigned int phase_lock_fill_rate @@
drivers/clk/adi/clk-ad9545.c:1421:24: sparse: expected restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1421:24: sparse: got unsigned int phase_lock_fill_rate
drivers/clk/adi/clk-ad9545.c:1423:89: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int val @@ got restricted __le32 [addressable] [assigned] [usertype] regval @@
drivers/clk/adi/clk-ad9545.c:1423:89: sparse: expected unsigned int val
drivers/clk/adi/clk-ad9545.c:1423:89: sparse: got restricted __le32 [addressable] [assigned] [usertype] regval
>> drivers/clk/adi/clk-ad9545.c:1428:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [addressable] [assigned] [usertype] regval @@ got unsigned int phase_lock_drain_rate @@
drivers/clk/adi/clk-ad9545.c:1428:24: sparse: expected restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1428:24: sparse: got unsigned int phase_lock_drain_rate
drivers/clk/adi/clk-ad9545.c:1430:90: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int val @@ got restricted __le32 [addressable] [assigned] [usertype] regval @@
drivers/clk/adi/clk-ad9545.c:1430:90: sparse: expected unsigned int val
drivers/clk/adi/clk-ad9545.c:1430:90: sparse: got restricted __le32 [addressable] [assigned] [usertype] regval

vim +1114 drivers/clk/adi/clk-ad9545.c

f88d17c990b731 Alexandru Tachici 2021-06-14 1089
f88d17c990b731 Alexandru Tachici 2021-06-14 1090 static int ad9545_out_clk_get_phase(struct clk_hw *hw)
f88d17c990b731 Alexandru Tachici 2021-06-14 1091 {
f88d17c990b731 Alexandru Tachici 2021-06-14 1092 struct ad9545_out_clk *clk = to_out_clk(hw);
f88d17c990b731 Alexandru Tachici 2021-06-14 1093 u64 input_edges_nr;
f88d17c990b731 Alexandru Tachici 2021-06-14 1094 u64 phase_code;
f88d17c990b731 Alexandru Tachici 2021-06-14 1095 __le32 regval;
f88d17c990b731 Alexandru Tachici 2021-06-14 1096 u32 phase_conf;
f88d17c990b731 Alexandru Tachici 2021-06-14 1097 u32 qdiv;
f88d17c990b731 Alexandru Tachici 2021-06-14 1098 int ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 1099
f88d17c990b731 Alexandru Tachici 2021-06-14 1100 ret = ad9545_get_q_div(clk->st, clk->address, &qdiv);
f88d17c990b731 Alexandru Tachici 2021-06-14 1101 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 1102 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 1103
f88d17c990b731 Alexandru Tachici 2021-06-14 1104 ret = regmap_read(clk->st->regmap, AD9545_QX_PHASE_CONF(clk->address), &phase_conf);
f88d17c990b731 Alexandru Tachici 2021-06-14 1105 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 1106 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 1107
f88d17c990b731 Alexandru Tachici 2021-06-14 1108 ret = regmap_bulk_read(clk->st->regmap, AD9545_QX_PHASE(clk->address), &regval, 4);
f88d17c990b731 Alexandru Tachici 2021-06-14 1109 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 1110 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 1111
f88d17c990b731 Alexandru Tachici 2021-06-14 1112 /* Qxy phase bitfield is 33 bits long, with last bit in PHASE_CONF reg */
f88d17c990b731 Alexandru Tachici 2021-06-14 1113 phase_code = !!(phase_conf & AD9545_QX_PHASE_32_MSK);
f88d17c990b731 Alexandru Tachici 2021-06-14 @1114 phase_code = (phase_code >> 32) + cpu_to_le32(regval);
f88d17c990b731 Alexandru Tachici 2021-06-14 1115
f88d17c990b731 Alexandru Tachici 2021-06-14 1116 input_edges_nr = 2 * qdiv + !!(phase_conf & AD9545_QX_HALF_DIV_MSK);
f88d17c990b731 Alexandru Tachici 2021-06-14 1117
f88d17c990b731 Alexandru Tachici 2021-06-14 1118 /*
f88d17c990b731 Alexandru Tachici 2021-06-14 1119 * phase = 360 * (Qxy Phase / E) where:
f88d17c990b731 Alexandru Tachici 2021-06-14 1120 * E is the total number of input edges per output period of the Q-divider.
f88d17c990b731 Alexandru Tachici 2021-06-14 1121 */
f88d17c990b731 Alexandru Tachici 2021-06-14 1122 return div64_u64(phase_code * 360, input_edges_nr);
f88d17c990b731 Alexandru Tachici 2021-06-14 1123 }
f88d17c990b731 Alexandru Tachici 2021-06-14 1124

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (7.87 kB)
.config.gz (34.83 kB)
Download all attachments

2021-06-18 07:26:02

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] dt-bindings: clock: ad9545: Add documentation

Hi,

I love your patch! Perhaps something to improve:

[auto build test WARNING on clk/clk-next]
[also build test WARNING on robh/for-next linux/master linus/master v5.13-rc6 next-20210617]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/alexandru-tachici-analog-com/clk-ad9545-Add-support/20210616-153412
base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: h8300-randconfig-s031-20210618 (attached as .config)
compiler: h8300-linux-gcc (GCC) 9.3.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.3-341-g8af24329-dirty
# https://github.com/0day-ci/linux/commit/b46755cf562ff8a1a9841a4560e344099f3f054e
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review alexandru-tachici-analog-com/clk-ad9545-Add-support/20210616-153412
git checkout b46755cf562ff8a1a9841a4560e344099f3f054e
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=h8300

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>


sparse warnings: (new ones prefixed by >>)
drivers/clk/adi/clk-ad9545.c:1114:43: sparse: sparse: cast from restricted __le32
>> drivers/clk/adi/clk-ad9545.c:1114:43: sparse: sparse: incorrect type in argument 1 (different base types) @@ expected unsigned int [usertype] val @@ got restricted __le32 [addressable] [usertype] regval @@
drivers/clk/adi/clk-ad9545.c:1114:43: sparse: expected unsigned int [usertype] val
drivers/clk/adi/clk-ad9545.c:1114:43: sparse: got restricted __le32 [addressable] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1114:43: sparse: sparse: cast from restricted __le32
drivers/clk/adi/clk-ad9545.c:1114:43: sparse: sparse: cast from restricted __le32
drivers/clk/adi/clk-ad9545.c:1114:43: sparse: sparse: cast from restricted __le32
drivers/clk/adi/clk-ad9545.c:1114:43: sparse: sparse: cast from restricted __le32
drivers/clk/adi/clk-ad9545.c:1114:43: sparse: sparse: restricted __le32 degrades to integer
drivers/clk/adi/clk-ad9545.c:1407:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [addressable] [assigned] [usertype] regval @@ got unsigned int freq_lock_fill_rate @@
drivers/clk/adi/clk-ad9545.c:1407:24: sparse: expected restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1407:24: sparse: got unsigned int freq_lock_fill_rate
drivers/clk/adi/clk-ad9545.c:1409:88: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int val @@ got restricted __le32 [addressable] [assigned] [usertype] regval @@
drivers/clk/adi/clk-ad9545.c:1409:88: sparse: expected unsigned int val
drivers/clk/adi/clk-ad9545.c:1409:88: sparse: got restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1414:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [addressable] [assigned] [usertype] regval @@ got unsigned int freq_lock_drain_rate @@
drivers/clk/adi/clk-ad9545.c:1414:24: sparse: expected restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1414:24: sparse: got unsigned int freq_lock_drain_rate
drivers/clk/adi/clk-ad9545.c:1416:89: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int val @@ got restricted __le32 [addressable] [assigned] [usertype] regval @@
drivers/clk/adi/clk-ad9545.c:1416:89: sparse: expected unsigned int val
drivers/clk/adi/clk-ad9545.c:1416:89: sparse: got restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1421:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [addressable] [assigned] [usertype] regval @@ got unsigned int phase_lock_fill_rate @@
drivers/clk/adi/clk-ad9545.c:1421:24: sparse: expected restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1421:24: sparse: got unsigned int phase_lock_fill_rate
drivers/clk/adi/clk-ad9545.c:1423:89: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int val @@ got restricted __le32 [addressable] [assigned] [usertype] regval @@
drivers/clk/adi/clk-ad9545.c:1423:89: sparse: expected unsigned int val
drivers/clk/adi/clk-ad9545.c:1423:89: sparse: got restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1428:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted __le32 [addressable] [assigned] [usertype] regval @@ got unsigned int phase_lock_drain_rate @@
drivers/clk/adi/clk-ad9545.c:1428:24: sparse: expected restricted __le32 [addressable] [assigned] [usertype] regval
drivers/clk/adi/clk-ad9545.c:1428:24: sparse: got unsigned int phase_lock_drain_rate
drivers/clk/adi/clk-ad9545.c:1430:90: sparse: sparse: incorrect type in argument 3 (different base types) @@ expected unsigned int val @@ got restricted __le32 [addressable] [assigned] [usertype] regval @@
drivers/clk/adi/clk-ad9545.c:1430:90: sparse: expected unsigned int val
drivers/clk/adi/clk-ad9545.c:1430:90: sparse: got restricted __le32 [addressable] [assigned] [usertype] regval

vim +1114 drivers/clk/adi/clk-ad9545.c

f88d17c990b731 Alexandru Tachici 2021-06-14 1089
f88d17c990b731 Alexandru Tachici 2021-06-14 1090 static int ad9545_out_clk_get_phase(struct clk_hw *hw)
f88d17c990b731 Alexandru Tachici 2021-06-14 1091 {
f88d17c990b731 Alexandru Tachici 2021-06-14 1092 struct ad9545_out_clk *clk = to_out_clk(hw);
f88d17c990b731 Alexandru Tachici 2021-06-14 1093 u64 input_edges_nr;
f88d17c990b731 Alexandru Tachici 2021-06-14 1094 u64 phase_code;
f88d17c990b731 Alexandru Tachici 2021-06-14 1095 __le32 regval;
f88d17c990b731 Alexandru Tachici 2021-06-14 1096 u32 phase_conf;
f88d17c990b731 Alexandru Tachici 2021-06-14 1097 u32 qdiv;
f88d17c990b731 Alexandru Tachici 2021-06-14 1098 int ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 1099
f88d17c990b731 Alexandru Tachici 2021-06-14 1100 ret = ad9545_get_q_div(clk->st, clk->address, &qdiv);
f88d17c990b731 Alexandru Tachici 2021-06-14 1101 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 1102 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 1103
f88d17c990b731 Alexandru Tachici 2021-06-14 1104 ret = regmap_read(clk->st->regmap, AD9545_QX_PHASE_CONF(clk->address), &phase_conf);
f88d17c990b731 Alexandru Tachici 2021-06-14 1105 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 1106 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 1107
f88d17c990b731 Alexandru Tachici 2021-06-14 1108 ret = regmap_bulk_read(clk->st->regmap, AD9545_QX_PHASE(clk->address), &regval, 4);
f88d17c990b731 Alexandru Tachici 2021-06-14 1109 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 1110 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 1111
f88d17c990b731 Alexandru Tachici 2021-06-14 1112 /* Qxy phase bitfield is 33 bits long, with last bit in PHASE_CONF reg */
f88d17c990b731 Alexandru Tachici 2021-06-14 1113 phase_code = !!(phase_conf & AD9545_QX_PHASE_32_MSK);
f88d17c990b731 Alexandru Tachici 2021-06-14 @1114 phase_code = (phase_code >> 32) + cpu_to_le32(regval);
f88d17c990b731 Alexandru Tachici 2021-06-14 1115
f88d17c990b731 Alexandru Tachici 2021-06-14 1116 input_edges_nr = 2 * qdiv + !!(phase_conf & AD9545_QX_HALF_DIV_MSK);
f88d17c990b731 Alexandru Tachici 2021-06-14 1117
f88d17c990b731 Alexandru Tachici 2021-06-14 1118 /*
f88d17c990b731 Alexandru Tachici 2021-06-14 1119 * phase = 360 * (Qxy Phase / E) where:
f88d17c990b731 Alexandru Tachici 2021-06-14 1120 * E is the total number of input edges per output period of the Q-divider.
f88d17c990b731 Alexandru Tachici 2021-06-14 1121 */
f88d17c990b731 Alexandru Tachici 2021-06-14 1122 return div64_u64(phase_code * 360, input_edges_nr);
f88d17c990b731 Alexandru Tachici 2021-06-14 1123 }
f88d17c990b731 Alexandru Tachici 2021-06-14 1124

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (8.81 kB)
.config.gz (23.66 kB)
Download all attachments

2021-06-22 07:04:11

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 2/2] dt-bindings: clock: ad9545: Add documentation

Hi,

I love your patch! Perhaps something to improve:

[auto build test WARNING on clk/clk-next]
[also build test WARNING on robh/for-next linux/master linus/master v5.13-rc7 next-20210621]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/alexandru-tachici-analog-com/clk-ad9545-Add-support/20210616-153412
base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
config: x86_64-randconfig-r005-20210622 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project b3634d3e88b7f26534a5057bff182b7dced584fc)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install x86_64 cross compiling tool for clang build
# apt-get install binutils-x86-64-linux-gnu
# https://github.com/0day-ci/linux/commit/b46755cf562ff8a1a9841a4560e344099f3f054e
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review alexandru-tachici-analog-com/clk-ad9545-Add-support/20210616-153412
git checkout b46755cf562ff8a1a9841a4560e344099f3f054e
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> drivers/clk/adi/clk-ad9545.c:2402:5: warning: no previous prototype for function 'ad9545_probe' [-Wmissing-prototypes]
int ad9545_probe(struct device *dev, struct regmap *regmap)
^
drivers/clk/adi/clk-ad9545.c:2402:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int ad9545_probe(struct device *dev, struct regmap *regmap)
^
static
1 warning generated.


vim +/ad9545_probe +2402 drivers/clk/adi/clk-ad9545.c

f88d17c990b731 Alexandru Tachici 2021-06-14 2401
f88d17c990b731 Alexandru Tachici 2021-06-14 @2402 int ad9545_probe(struct device *dev, struct regmap *regmap)
f88d17c990b731 Alexandru Tachici 2021-06-14 2403 {
f88d17c990b731 Alexandru Tachici 2021-06-14 2404 struct ad9545_state *st;
f88d17c990b731 Alexandru Tachici 2021-06-14 2405 int ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 2406
f88d17c990b731 Alexandru Tachici 2021-06-14 2407 st = devm_kzalloc(dev, sizeof(struct ad9545_state), GFP_KERNEL);
f88d17c990b731 Alexandru Tachici 2021-06-14 2408 if (!st)
f88d17c990b731 Alexandru Tachici 2021-06-14 2409 return -ENOMEM;
f88d17c990b731 Alexandru Tachici 2021-06-14 2410
f88d17c990b731 Alexandru Tachici 2021-06-14 2411 st->dev = dev;
f88d17c990b731 Alexandru Tachici 2021-06-14 2412 st->regmap = regmap;
f88d17c990b731 Alexandru Tachici 2021-06-14 2413
f88d17c990b731 Alexandru Tachici 2021-06-14 2414 ret = ad9545_check_id(st);
f88d17c990b731 Alexandru Tachici 2021-06-14 2415 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 2416 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 2417
f88d17c990b731 Alexandru Tachici 2021-06-14 2418 ret = ad9545_parse_dt(st);
f88d17c990b731 Alexandru Tachici 2021-06-14 2419 if (ret < 0)
f88d17c990b731 Alexandru Tachici 2021-06-14 2420 return ret;
f88d17c990b731 Alexandru Tachici 2021-06-14 2421
f88d17c990b731 Alexandru Tachici 2021-06-14 2422 return ad9545_setup(st);
f88d17c990b731 Alexandru Tachici 2021-06-14 2423 }
f88d17c990b731 Alexandru Tachici 2021-06-14 2424 EXPORT_SYMBOL_GPL(ad9545_probe);
f88d17c990b731 Alexandru Tachici 2021-06-14 2425

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]


Attachments:
(No filename) (3.92 kB)
.config.gz (36.78 kB)
Download all attachments