* [PATCH v2 1/3] iio: frequency: adf4360: Add support for ADF4360 PLLs
@ 2020-01-22 13:20 Alexandru Ardelean
2020-01-22 13:20 ` [PATCH v2 2/3] dt-bindings: iio: frequency: Add docs for ADF4360 PLL Alexandru Ardelean
2020-01-22 13:20 ` [PATCH v2 3/3] MAINTAINERS: add entry for ADF4360 PLL driver Alexandru Ardelean
0 siblings, 2 replies; 5+ messages in thread
From: Alexandru Ardelean @ 2020-01-22 13:20 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: ekigwana, jic23, lars, robh+dt, Alexandru Ardelean
From: Edward Kigwana <ekigwana@gmail.com>
The ADF4360-N (N is 0..9) are a family of integrated integer-N synthesizer
and voltage controlled oscillator (VCO).
Control of all the on-chip registers is through a simple 3-wire SPI
interface. The device operates with a power supply ranging from 3.0 V to
3.6 V and can be powered down when not in use.
The initial draft-work was done by Lars-Peter Clausen <lars@metafoo.de>
The current/latest/complete version was implemented by
Edward Kigwana <ekigwana@gmail.com>.
The ADF4360-9 is also present on the Analog Devices 'Advanced Active
Learning Module 2000' (ADALM-2000).
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-0.pdf
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-1.pdf
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-2.pdf
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-3.pdf
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-4.pdf
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-5.pdf
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-6.pdf
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-7.pdf
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-8.pdf
Link: https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-9.pdf
Link: https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/ADALM2000.html
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Edward Kigwana <ekigwana@gmail.com>
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
Changelog v1 -> v2:
* validate dt-bindings file with
make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
drivers/iio/frequency/Kconfig | 11 +
drivers/iio/frequency/Makefile | 1 +
drivers/iio/frequency/adf4360.c | 1263 +++++++++++++++++++++++++++++++
3 files changed, 1275 insertions(+)
create mode 100644 drivers/iio/frequency/adf4360.c
diff --git a/drivers/iio/frequency/Kconfig b/drivers/iio/frequency/Kconfig
index 240b81502512..781236496661 100644
--- a/drivers/iio/frequency/Kconfig
+++ b/drivers/iio/frequency/Kconfig
@@ -39,6 +39,17 @@ config ADF4350
To compile this driver as a module, choose M here: the
module will be called adf4350.
+config ADF4360
+ tristate "Analog Devices ADF4360 Wideband Synthesizers"
+ depends on SPI
+ depends on COMMON_CLK
+ help
+ Say yes here to build support for Analog Devices ADF4360
+ Wideband Synthesizers. The driver provides direct access via sysfs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adf4360.
+
config ADF4371
tristate "Analog Devices ADF4371/ADF4372 Wideband Synthesizers"
depends on SPI
diff --git a/drivers/iio/frequency/Makefile b/drivers/iio/frequency/Makefile
index 518b1e50caef..85f2f81da662 100644
--- a/drivers/iio/frequency/Makefile
+++ b/drivers/iio/frequency/Makefile
@@ -6,4 +6,5 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD9523) += ad9523.o
obj-$(CONFIG_ADF4350) += adf4350.o
+obj-$(CONFIG_ADF4360) += adf4360.o
obj-$(CONFIG_ADF4371) += adf4371.o
diff --git a/drivers/iio/frequency/adf4360.c b/drivers/iio/frequency/adf4360.c
new file mode 100644
index 000000000000..85abfe5e0575
--- /dev/null
+++ b/drivers/iio/frequency/adf4360.c
@@ -0,0 +1,1263 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ADF4360 PLL with Integrated Synthesizer and VCO
+ *
+ * Copyright 2014-2019 Analog Devices Inc.
+ * Copyright 2019-2020 Edward Kigwana.
+ */
+
+#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/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/util_macros.h>
+
+#include <linux/iio/iio.h>
+
+/* Register address macro */
+#define ADF4360_REG(x) (x)
+
+/* ADF4360_CTRL */
+#define ADF4360_ADDR_CPL_MSK GENMASK(3, 2)
+#define ADF4360_CPL(x) FIELD_PREP(ADF4360_ADDR_CPL_MSK, x)
+#define ADF4360_ADDR_MUXOUT_MSK GENMASK(7, 5)
+#define ADF4360_MUXOUT(x) FIELD_PREP(ADF4360_ADDR_MUXOUT_MSK, x)
+#define ADF4360_ADDR_PDP_MSK BIT(8)
+#define ADF4360_PDP(x) FIELD_PREP(ADF4360_ADDR_PDP_MSK, x)
+#define ADF4360_ADDR_MTLD_MSK BIT(11)
+#define ADF4360_MTLD(x) FIELD_PREP(ADF4360_ADDR_MTLD_MSK, x)
+#define ADF4360_ADDR_OPL_MSK GENMASK(13, 12)
+#define ADF4360_OPL(x) FIELD_PREP(ADF4360_ADDR_OPL_MSK, x)
+#define ADF4360_ADDR_CPI1_MSK GENMASK(16, 14)
+#define ADF4360_CPI1(x) FIELD_PREP(ADF4360_ADDR_CPI1_MSK, x)
+#define ADF4360_ADDR_CPI2_MSK GENMASK(19, 17)
+#define ADF4360_CPI2(x) FIELD_PREP(ADF4360_ADDR_CPI2_MSK, x)
+#define ADF4360_ADDR_PWR_DWN_MSK GENMASK(21, 20)
+#define ADF4360_POWERDOWN(x) FIELD_PREP(ADF4360_ADDR_PWR_DWN_MSK, x)
+#define ADF4360_ADDR_PRESCALER_MSK GENMASK(23, 22)
+#define ADF4360_PRESCALER(x) FIELD_PREP(ADF4360_ADDR_PRESCALER_MSK, x)
+
+/* ADF4360_NDIV */
+#define ADF4360_ADDR_A_CNTR_MSK GENMASK(6, 2)
+#define ADF4360_A_COUNTER(x) FIELD_PREP(ADF4360_ADDR_A_CNTR_MSK, x)
+#define ADF4360_ADDR_B_CNTR_MSK GENMASK(20, 8)
+#define ADF4360_B_COUNTER(x) FIELD_PREP(ADF4360_ADDR_B_CNTR_MSK, x)
+#define ADF4360_ADDR_OUT_DIV2_MSK BIT(22)
+#define ADF4360_OUT_DIV2(x) FIELD_PREP(ADF4360_ADDR_OUT_DIV2_MSK, x)
+#define ADF4360_ADDR_DIV2_SEL_MSK BIT(23)
+#define ADF4360_PRESCALER_DIV2(x) FIELD_PREP(ADF4360_ADDR_DIV2_SEL_MSK, x)
+
+/* ADF4360_RDIV */
+#define ADF4360_ADDR_R_CNTR_MSK GENMASK(15, 2)
+#define ADF4360_R_COUNTER(x) FIELD_PREP(ADF4360_ADDR_R_CNTR_MSK, x)
+#define ADF4360_ADDR_ABP_MSK GENMASK(17, 16)
+#define ADF4360_ABP(x) FIELD_PREP(ADF4360_ADDR_ABP_MSK, x)
+#define ADF4360_ADDR_BSC_MSK GENMASK(21, 20)
+#define ADF4360_BSC(x) FIELD_PREP(ADF4360_ADDR_BSC_MSK, x)
+
+/* Specifications */
+#define ADF4360_MAX_PFD_RATE 8000000 /* 8 MHz */
+#define ADF4360_MAX_COUNTER_RATE 300000000 /* 300 MHz */
+#define ADF4360_MAX_REFIN_RATE 250000000 /* 250 MHz */
+
+enum {
+ ADF4360_CTRL,
+ ADF4360_RDIV,
+ ADF4360_NDIV,
+ ADF4360_REG_NUM,
+};
+
+enum {
+ ADF4360_GEN1_PC_5,
+ ADF4360_GEN1_PC_10,
+ ADF4360_GEN1_PC_15,
+ ADF4360_GEN1_PC_20,
+};
+
+enum {
+ ADF4360_GEN2_PC_2_5,
+ ADF4360_GEN2_PC_5,
+ ADF4360_GEN2_PC_7_5,
+ ADF4360_GEN2_PC_10,
+};
+
+enum {
+ ADF4360_MUXOUT_THREE_STATE,
+ ADF4360_MUXOUT_LOCK_DETECT,
+ ADF4360_MUXOUT_NDIV,
+ ADF4360_MUXOUT_DVDD,
+ ADF4360_MUXOUT_RDIV,
+ ADF4360_MUXOUT_OD_LD,
+ ADF4360_MUXOUT_SDO,
+ ADF4360_MUXOUT_GND,
+};
+
+enum {
+ ADF4360_PL_3_5,
+ ADF4360_PL_5,
+ ADF4360_PL_7_5,
+ ADF4360_PL_11,
+};
+
+enum {
+ ADF4360_CPI_0_31,
+ ADF4360_CPI_0_62,
+ ADF4360_CPI_0_93,
+ ADF4360_CPI_1_25,
+ ADF4360_CPI_1_56,
+ ADF4360_CPI_1_87,
+ ADF4360_CPI_2_18,
+ ADF4360_CPI_2_50,
+};
+
+enum {
+ ADF4360_POWER_DOWN_NORMAL,
+ ADF4360_POWER_DOWN_SOFT_ASYNC,
+ ADF4360_POWER_DOWN_CE,
+ ADF4360_POWER_DOWN_SOFT_SYNC,
+ ADF4360_POWER_DOWN_REGULATOR,
+};
+
+enum {
+ ADF4360_PRESCALER_8,
+ ADF4360_PRESCALER_16,
+ ADF4360_PRESCALER_32,
+};
+
+enum {
+ ADF4360_ABP_3_0NS,
+ ADF4360_ABP_1_3NS,
+ ADF4360_ABP_6_0NS,
+};
+
+enum {
+ ADF4360_BSC_1,
+ ADF4360_BSC_2,
+ ADF4360_BSC_4,
+ ADF4360_BSC_8,
+};
+
+enum {
+ ID_ADF4360_0,
+ ID_ADF4360_1,
+ ID_ADF4360_2,
+ ID_ADF4360_3,
+ ID_ADF4360_4,
+ ID_ADF4360_5,
+ ID_ADF4360_6,
+ ID_ADF4360_7,
+ ID_ADF4360_8,
+ ID_ADF4360_9,
+};
+
+enum {
+ ADF4360_FREQ_REFIN,
+ ADF4360_MTLD,
+ ADF4360_FREQ_PFD,
+};
+
+static const char * const adf4360_power_level_modes[] = {
+ [ADF4360_PL_3_5] = "3500-uA",
+ [ADF4360_PL_5] = "5000-uA",
+ [ADF4360_PL_7_5] = "7500-uA",
+ [ADF4360_PL_11] = "11000-uA",
+};
+
+static const unsigned int adf4360_power_lvl_microamp[] = {
+ [ADF4360_PL_3_5] = 3500,
+ [ADF4360_PL_5] = 5000,
+ [ADF4360_PL_7_5] = 7500,
+ [ADF4360_PL_11] = 11000,
+};
+
+static const unsigned int adf4360_cpi_modes[] = {
+ [ADF4360_CPI_0_31] = 310,
+ [ADF4360_CPI_0_62] = 620,
+ [ADF4360_CPI_0_93] = 930,
+ [ADF4360_CPI_1_25] = 1250,
+ [ADF4360_CPI_1_56] = 1560,
+ [ADF4360_CPI_1_87] = 1870,
+ [ADF4360_CPI_2_18] = 2180,
+ [ADF4360_CPI_2_50] = 2500,
+};
+
+static const char * const adf4360_muxout_modes[] = {
+ [ADF4360_MUXOUT_THREE_STATE] = "three-state",
+ [ADF4360_MUXOUT_LOCK_DETECT] = "lock-detect",
+ [ADF4360_MUXOUT_NDIV] = "ndiv",
+ [ADF4360_MUXOUT_DVDD] = "dvdd",
+ [ADF4360_MUXOUT_RDIV] = "rdiv",
+ [ADF4360_MUXOUT_OD_LD] = "od-ld",
+ [ADF4360_MUXOUT_SDO] = "sdo",
+ [ADF4360_MUXOUT_GND] = "gnd",
+};
+
+static const char * const adf4360_power_down_modes[] = {
+ [ADF4360_POWER_DOWN_NORMAL] = "normal",
+ [ADF4360_POWER_DOWN_SOFT_ASYNC] = "soft-async",
+ [ADF4360_POWER_DOWN_CE] = "ce",
+ [ADF4360_POWER_DOWN_SOFT_SYNC] = "soft-sync",
+ [ADF4360_POWER_DOWN_REGULATOR] = "regulator",
+};
+
+struct adf4360_output {
+ struct clk_hw hw;
+ struct iio_dev *indio_dev;
+};
+
+#define to_output(_hw) container_of(_hw, struct adf4360_output, hw)
+
+struct adf4360_chip_info {
+ unsigned int vco_min;
+ unsigned int vco_max;
+ unsigned int default_cpl;
+};
+
+struct adf4360_state {
+ struct spi_device *spi;
+ const struct adf4360_chip_info *info;
+ struct adf4360_output output;
+ struct clk *clkin;
+ struct gpio_desc *muxout_gpio;
+ struct gpio_desc *chip_en_gpio;
+ struct regulator *vdd_reg;
+ struct mutex lock; /* Protect PLL state. */
+ unsigned int part_id;
+ unsigned long clkin_freq;
+ unsigned long freq_req;
+ unsigned long r;
+ unsigned long n;
+ unsigned int vco_min;
+ unsigned int vco_max;
+ unsigned int pfd_freq;
+ unsigned int cpi;
+ bool pdp;
+ bool mtld;
+ unsigned int power_level;
+ unsigned int muxout_mode;
+ unsigned int power_down_mode;
+ bool initial_reg_seq;
+ const char *clk_out_name;
+ unsigned int regs[ADF4360_REG_NUM];
+ u8 spi_data[3] ____cacheline_aligned;
+};
+
+static const struct adf4360_chip_info adf4360_chip_info_tbl[] = {
+ { /* ADF4360-0 */
+ .vco_min = 2400000000U,
+ .vco_max = 2725000000U,
+ .default_cpl = ADF4360_GEN1_PC_10,
+ }, { /* ADF4360-1 */
+ .vco_min = 2050000000U,
+ .vco_max = 2450000000U,
+ .default_cpl = ADF4360_GEN1_PC_15,
+ }, { /* ADF4360-2 */
+ .vco_min = 1850000000U,
+ .vco_max = 2170000000U,
+ .default_cpl = ADF4360_GEN1_PC_15,
+ }, { /* ADF4360-3 */
+ .vco_min = 1600000000U,
+ .vco_max = 1950000000U,
+ .default_cpl = ADF4360_GEN1_PC_15,
+ }, { /* ADF4360-4 */
+ .vco_min = 1450000000U,
+ .vco_max = 1750000000U,
+ .default_cpl = ADF4360_GEN1_PC_15,
+ }, { /* ADF4360-5 */
+ .vco_min = 1200000000U,
+ .vco_max = 1400000000U,
+ .default_cpl = ADF4360_GEN1_PC_10,
+ }, { /* ADF4360-6 */
+ .vco_min = 1050000000U,
+ .vco_max = 1250000000U,
+ .default_cpl = ADF4360_GEN1_PC_10,
+ }, { /* ADF4360-7 */
+ .vco_min = 350000000U,
+ .vco_max = 1800000000U,
+ .default_cpl = ADF4360_GEN1_PC_5,
+ }, { /* ADF4360-8 */
+ .vco_min = 65000000U,
+ .vco_max = 400000000U,
+ .default_cpl = ADF4360_GEN2_PC_5,
+ }, { /* ADF4360-9 */
+ .vco_min = 65000000U,
+ .vco_max = 400000000U,
+ .default_cpl = ADF4360_GEN2_PC_5,
+ }
+};
+
+static int adf4360_write_reg(struct adf4360_state *st, unsigned int reg,
+ unsigned int val)
+{
+ int ret;
+
+ val |= reg;
+
+ st->spi_data[0] = (val >> 16) & 0xff;
+ st->spi_data[1] = (val >> 8) & 0xff;
+ st->spi_data[2] = val & 0xff;
+
+ ret = spi_write(st->spi, st->spi_data, ARRAY_SIZE(st->spi_data));
+ if (ret == 0)
+ st->regs[reg] = val;
+
+ return ret;
+}
+
+/* fVCO = B * fREFIN / R */
+
+static unsigned long adf4360_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct iio_dev *indio_dev = to_output(hw)->indio_dev;
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ if (st->r == 0)
+ return 0;
+
+ /*
+ * The result is guaranteed to fit in 32-bit, but the intermediate
+ * result might require 64-bit.
+ */
+ return DIV_ROUND_CLOSEST_ULL((uint64_t)parent_rate * st->n, st->r);
+}
+
+static unsigned int adf4360_calc_prescaler(unsigned int pfd_freq,
+ unsigned int n,
+ unsigned int *out_p,
+ unsigned int *out_a,
+ unsigned int *out_b)
+{
+ unsigned int rate = pfd_freq * n;
+ unsigned int p, a, b;
+
+ /* Make sure divider counter input frequency is low enough */
+ p = 8;
+ while (p < 32 && rate / p > ADF4360_MAX_COUNTER_RATE)
+ p *= 2;
+
+ /*
+ * The range of dividers that can be produced using the dual-modulus
+ * pre-scaler is not continuous for values of n < p*(p-1). If we end up
+ * with a non supported divider value, pick the next closest one.
+ */
+ a = n % p;
+ b = n / p;
+
+ if (b < 3) {
+ b = 3;
+ a = 0;
+ } else if (a > b) {
+ if (a - b < p - a) {
+ a = b;
+ } else {
+ a = 0;
+ b++;
+ }
+ }
+
+ if (out_p)
+ *out_p = p;
+ if (out_a)
+ *out_a = a;
+ if (out_b)
+ *out_b = b;
+
+ return p * b + a;
+}
+
+static long adf4360_clk_round_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct iio_dev *indio_dev = to_output(hw)->indio_dev;
+ struct adf4360_state *st = iio_priv(indio_dev);
+ unsigned int r, n;
+ unsigned int pfd_freq;
+
+ if (*parent_rate == 0)
+ return 0;
+
+ if (st->part_id == ID_ADF4360_9)
+ return *parent_rate * st->n / st->r;
+
+ if (rate > st->vco_max)
+ return st->vco_max;
+
+ /* ADF4360-0 to AD4370-7 have an optional by two divider */
+ if (st->part_id <= ID_ADF4360_7) {
+ if (rate < st->vco_min / 2)
+ return st->vco_min / 2;
+ if (rate < st->vco_min && rate > st->vco_max / 2) {
+ if (st->vco_min - rate < rate - st->vco_max / 2)
+ return st->vco_min;
+ else
+ return st->vco_max / 2;
+ }
+ } else {
+ if (rate < st->vco_min)
+ return st->vco_min;
+ }
+
+ r = DIV_ROUND_CLOSEST(*parent_rate, st->pfd_freq);
+ pfd_freq = *parent_rate / r;
+ n = DIV_ROUND_CLOSEST(rate, pfd_freq);
+
+ if (st->part_id <= ID_ADF4360_7)
+ n = adf4360_calc_prescaler(pfd_freq, n, NULL, NULL, NULL);
+
+ return pfd_freq * n;
+}
+
+static inline bool adf4360_is_powerdown(struct adf4360_state *st)
+{
+ return (st->power_down_mode != ADF4360_POWER_DOWN_NORMAL);
+}
+
+static int adf4360_set_freq(struct adf4360_state *st, unsigned long rate)
+{
+ unsigned int val_r, val_n, val_ctrl;
+ unsigned int pfd_freq;
+ unsigned long r, n;
+ int ret;
+
+ if (!st->clkin_freq || (st->clkin_freq > ADF4360_MAX_REFIN_RATE))
+ return -EINVAL;
+
+ if ((rate < st->vco_min) || (rate > st->vco_max))
+ return -EINVAL;
+
+ if (adf4360_is_powerdown(st))
+ ret = -EBUSY;
+
+ r = DIV_ROUND_CLOSEST(st->clkin_freq, st->pfd_freq);
+ pfd_freq = st->clkin_freq / r;
+ n = DIV_ROUND_CLOSEST(rate, pfd_freq);
+
+ val_ctrl = ADF4360_CPL(st->info->default_cpl) |
+ ADF4360_MUXOUT(st->muxout_mode) |
+ ADF4360_PDP(!st->pdp) |
+ ADF4360_MTLD(st->mtld) |
+ ADF4360_OPL(st->power_level) |
+ ADF4360_CPI1(st->cpi) |
+ ADF4360_CPI2(st->cpi) |
+ ADF4360_POWERDOWN(st->power_down_mode);
+
+ /* ADF4360-0 to ADF4360-7 have a dual-modulous prescaler */
+ if (st->part_id <= ID_ADF4360_7) {
+ unsigned int p, a, b;
+
+ n = adf4360_calc_prescaler(pfd_freq, n, &p, &a, &b);
+
+ switch (p) {
+ case 8:
+ val_ctrl |= ADF4360_PRESCALER(ADF4360_PRESCALER_8);
+ break;
+ case 16:
+ val_ctrl |= ADF4360_PRESCALER(ADF4360_PRESCALER_16);
+ break;
+ default:
+ val_ctrl |= ADF4360_PRESCALER(ADF4360_PRESCALER_32);
+ break;
+ }
+
+ val_n = ADF4360_A_COUNTER(a) |
+ ADF4360_B_COUNTER(b);
+
+ if (rate < st->vco_min)
+ val_n |= ADF4360_OUT_DIV2(true) |
+ ADF4360_PRESCALER_DIV2(true);
+ } else {
+ val_n = ADF4360_B_COUNTER(n);
+ }
+
+ /*
+ * Always use BSC divider of 8, see Analog Devices AN-1347.
+ * http://www.analog.com/media/en/technical-documentation/application-notes/AN-1347.pdf
+ */
+ val_r = ADF4360_R_COUNTER(r) |
+ ADF4360_ABP(ADF4360_ABP_3_0NS) |
+ ADF4360_BSC(ADF4360_BSC_8);
+
+ ret = adf4360_write_reg(st, ADF4360_REG(ADF4360_RDIV), val_r);
+ if (ret)
+ return ret;
+
+ ret = adf4360_write_reg(st, ADF4360_REG(ADF4360_CTRL), val_ctrl);
+ if (ret)
+ return ret;
+
+ /*
+ * Allow the transient behavior of the ADF4360-7 during initial
+ * power-up to settle.
+ */
+ if (st->initial_reg_seq) {
+ usleep_range(15000, 20000);
+ st->initial_reg_seq = false;
+ }
+
+ ret = adf4360_write_reg(st, ADF4360_REG(ADF4360_NDIV), val_n);
+ if (ret)
+ return ret;
+
+ st->freq_req = rate;
+ st->n = n;
+ st->r = r;
+
+ return 0;
+}
+
+static int adf4360_clk_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct iio_dev *indio_dev = to_output(hw)->indio_dev;
+ struct adf4360_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if ((parent_rate == 0) || (parent_rate > ADF4360_MAX_REFIN_RATE))
+ return -EINVAL;
+
+ mutex_lock(&st->lock);
+ if (st->clkin_freq != parent_rate)
+ st->clkin_freq = parent_rate;
+
+ ret = adf4360_set_freq(st, rate);
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int __adf4360_power_down(struct adf4360_state *st, unsigned int mode)
+{
+ struct device *dev = &st->spi->dev;
+ unsigned int val;
+ int ret = 0;
+
+ switch (mode) {
+ case ADF4360_POWER_DOWN_NORMAL:
+ if (st->vdd_reg) {
+ ret = regulator_enable(st->vdd_reg);
+ if (ret) {
+ dev_err(dev, "Supply enable error: %d\n", ret);
+ return ret;
+ }
+ }
+
+ st->initial_reg_seq = true;
+ st->power_down_mode = mode;
+ ret = adf4360_set_freq(st, st->freq_req);
+ break;
+ case ADF4360_POWER_DOWN_SOFT_ASYNC: /* fallthrough */
+ case ADF4360_POWER_DOWN_SOFT_SYNC:
+ val = st->regs[ADF4360_CTRL] & ~ADF4360_ADDR_MUXOUT_MSK;
+ val |= ADF4360_POWERDOWN(mode);
+ ret = adf4360_write_reg(st, ADF4360_REG(ADF4360_CTRL), val);
+ break;
+ case ADF4360_POWER_DOWN_CE:
+ if (st->chip_en_gpio)
+ gpiod_set_value(st->chip_en_gpio, 0x0);
+ else
+ return -ENODEV;
+ break;
+ case ADF4360_POWER_DOWN_REGULATOR:
+ if (!st->vdd_reg)
+ return -ENODEV;
+
+ if (st->chip_en_gpio)
+ ret = __adf4360_power_down(st, ADF4360_POWER_DOWN_CE);
+ else
+ ret = __adf4360_power_down(st,
+ ADF4360_POWER_DOWN_SOFT_ASYNC);
+
+ ret = regulator_disable(st->vdd_reg);
+ if (ret)
+ dev_err(dev, "Supply disable error: %d\n", ret);
+ break;
+ }
+ if (ret == 0)
+ st->power_down_mode = mode;
+
+ return 0;
+}
+
+static int adf4360_power_down(struct adf4360_state *st, unsigned int mode)
+{
+ int ret;
+
+ mutex_lock(&st->lock);
+ ret = __adf4360_power_down(st, mode);
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int adf4360_clk_prepare(struct clk_hw *hw)
+{
+ struct iio_dev *indio_dev = to_output(hw)->indio_dev;
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ return adf4360_power_down(st, ADF4360_POWER_DOWN_NORMAL);
+}
+
+static void adf4360_clk_unprepare(struct clk_hw *hw)
+{
+ struct iio_dev *indio_dev = to_output(hw)->indio_dev;
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ adf4360_power_down(st, ADF4360_POWER_DOWN_SOFT_ASYNC);
+}
+
+static int adf4360_clk_enable(struct clk_hw *hw)
+{
+ struct iio_dev *indio_dev = to_output(hw)->indio_dev;
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ if (st->chip_en_gpio)
+ gpiod_set_value(st->chip_en_gpio, 0x1);
+
+ return 0;
+}
+
+static void adf4360_clk_disable(struct clk_hw *hw)
+{
+ struct iio_dev *indio_dev = to_output(hw)->indio_dev;
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ if (st->chip_en_gpio)
+ adf4360_power_down(st, ADF4360_POWER_DOWN_CE);
+}
+
+static int adf4360_clk_is_enabled(struct clk_hw *hw)
+{
+ struct iio_dev *indio_dev = to_output(hw)->indio_dev;
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ return adf4360_is_powerdown(st);
+}
+
+static const struct clk_ops adf4360_clk_ops = {
+ .recalc_rate = adf4360_clk_recalc_rate,
+ .round_rate = adf4360_clk_round_rate,
+ .set_rate = adf4360_clk_set_rate,
+ .prepare = adf4360_clk_prepare,
+ .unprepare = adf4360_clk_unprepare,
+ .enable = adf4360_clk_enable,
+ .disable = adf4360_clk_disable,
+ .is_enabled = adf4360_clk_is_enabled,
+};
+
+static ssize_t adf4360_read(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+ unsigned long val;
+ int ret = 0;
+
+ switch ((u32)private) {
+ case ADF4360_FREQ_REFIN:
+ val = st->clkin_freq;
+ break;
+ case ADF4360_MTLD:
+ val = st->mtld;
+ break;
+ case ADF4360_FREQ_PFD:
+ val = st->pfd_freq;
+ break;
+ default:
+ ret = -EINVAL;
+ val = 0;
+ }
+
+ return ret < 0 ? ret : sprintf(buf, "%lu\n", val);
+}
+
+static ssize_t adf4360_write(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+ unsigned long readin, tmp;
+ bool mtld;
+ int ret = 0;
+
+ mutex_lock(&st->lock);
+ switch ((u32)private) {
+ case ADF4360_FREQ_REFIN:
+ ret = kstrtoul(buf, 10, &readin);
+ if (ret)
+ break;
+
+ if ((readin > ADF4360_MAX_REFIN_RATE) || (readin == 0)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (st->clkin) {
+ tmp = clk_round_rate(st->clkin, readin);
+ if (tmp != readin) {
+ ret = -EINVAL;
+ break;
+ }
+
+ ret = clk_set_rate(st->clkin, tmp);
+ if (ret)
+ break;
+ }
+
+ st->clkin_freq = readin;
+ break;
+ case ADF4360_MTLD:
+ ret = kstrtobool(buf, &mtld);
+ if (ret)
+ break;
+
+ st->mtld = mtld;
+ break;
+ case ADF4360_FREQ_PFD:
+ ret = kstrtoul(buf, 10, &readin);
+ if (ret)
+ break;
+
+ if ((readin > ADF4360_MAX_PFD_RATE) || (readin == 0)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ st->pfd_freq = readin;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret == 0)
+ ret = adf4360_set_freq(st, st->freq_req);
+ mutex_unlock(&st->lock);
+
+ return ret ? ret : len;
+}
+
+static int adf4360_get_muxout_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ return st->muxout_mode;
+}
+
+static int adf4360_set_muxout_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+ unsigned int writeval;
+ int ret = 0;
+
+ mutex_lock(&st->lock);
+ writeval = st->regs[ADF4360_CTRL] & ~ADF4360_ADDR_MUXOUT_MSK;
+ writeval |= ADF4360_MUXOUT(mode & 0x7);
+ ret = adf4360_write_reg(st, ADF4360_REG(ADF4360_CTRL), writeval);
+ if (ret == 0)
+ st->muxout_mode = mode & 0x7;
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static const struct iio_enum adf4360_muxout_modes_available = {
+ .items = adf4360_muxout_modes,
+ .num_items = ARRAY_SIZE(adf4360_muxout_modes),
+ .get = adf4360_get_muxout_mode,
+ .set = adf4360_set_muxout_mode,
+};
+
+static int adf4360_get_power_down(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ return st->power_down_mode;
+}
+
+static int adf4360_set_power_down(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ return adf4360_power_down(st, mode);
+}
+
+static const struct iio_enum adf4360_pwr_dwn_modes_available = {
+ .items = adf4360_power_down_modes,
+ .num_items = ARRAY_SIZE(adf4360_power_down_modes),
+ .get = adf4360_get_power_down,
+ .set = adf4360_set_power_down,
+};
+
+static int adf4360_get_power_level(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+
+ return st->power_level;
+}
+
+static int adf4360_set_power_level(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int level)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+ unsigned int val;
+ int ret;
+
+ if (adf4360_is_powerdown(st))
+ return -EBUSY;
+
+ mutex_lock(&st->lock);
+ val = st->regs[ADF4360_CTRL] & ~ADF4360_ADDR_OPL_MSK;
+ val |= ADF4360_OPL(level);
+ ret = adf4360_write_reg(st, ADF4360_REG(ADF4360_CTRL), val);
+ st->power_level = level;
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static const struct iio_enum adf4360_pwr_lvl_modes_available = {
+ .items = adf4360_power_level_modes,
+ .num_items = ARRAY_SIZE(adf4360_power_level_modes),
+ .get = adf4360_get_power_level,
+ .set = adf4360_set_power_level,
+};
+
+#define _ADF4360_EXT_INFO(_name, _ident) { \
+ .name = _name, \
+ .read = adf4360_read, \
+ .write = adf4360_write, \
+ .private = _ident, \
+ .shared = IIO_SEPARATE, \
+}
+
+static const struct iio_chan_spec_ext_info adf4360_ext_info[] = {
+ _ADF4360_EXT_INFO("refin_frequency", ADF4360_FREQ_REFIN),
+ _ADF4360_EXT_INFO("mute_till_lock_detect", ADF4360_MTLD),
+ _ADF4360_EXT_INFO("pfd_frequency", ADF4360_FREQ_PFD),
+ IIO_ENUM_AVAILABLE("muxout_mode", &adf4360_muxout_modes_available),
+ IIO_ENUM("muxout_mode", false, &adf4360_muxout_modes_available),
+ IIO_ENUM_AVAILABLE("power_down", &adf4360_pwr_dwn_modes_available),
+ IIO_ENUM("power_down", false, &adf4360_pwr_dwn_modes_available),
+ IIO_ENUM_AVAILABLE("power_level", &adf4360_pwr_lvl_modes_available),
+ IIO_ENUM("power_level", false, &adf4360_pwr_lvl_modes_available),
+ { },
+};
+
+static const struct iio_chan_spec adf4360_chan = {
+ .type = IIO_ALTVOLTAGE,
+ .indexed = 1,
+ .output = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_FREQUENCY),
+ .ext_info = adf4360_ext_info,
+};
+
+static int adf4360_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+ bool lk_det;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ if (adf4360_is_powerdown(st))
+ return -EBUSY;
+
+ lk_det = (ADF4360_MUXOUT_LOCK_DETECT | ADF4360_MUXOUT_OD_LD) &
+ st->muxout_mode;
+ if (lk_det && st->muxout_gpio) {
+ if (!gpiod_get_value(st->muxout_gpio)) {
+ dev_dbg(&st->spi->dev, "PLL un-locked\n");
+ return -EBUSY;
+ }
+ }
+
+ *val = st->freq_req;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+};
+
+static int adf4360_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+ switch (mask) {
+ case IIO_CHAN_INFO_FREQUENCY:
+ ret = adf4360_set_freq(st, val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int adf4360_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg,
+ unsigned int writeval,
+ unsigned int *readval)
+{
+ struct adf4360_state *st = iio_priv(indio_dev);
+ int ret = 0;
+
+ if (reg >= ADF4360_REG_NUM)
+ return -EFAULT;
+
+ mutex_lock(&st->lock);
+ if (readval) {
+ *readval = st->regs[reg];
+ } else {
+ writeval &= 0xFFFFFC;
+ ret = adf4360_write_reg(st, reg, writeval);
+ }
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static const struct iio_info adf4360_iio_info = {
+ .read_raw = &adf4360_read_raw,
+ .write_raw = &adf4360_write_raw,
+ .debugfs_reg_access = &adf4360_reg_access,
+};
+
+static int adf4360_get_gpio(struct adf4360_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ unsigned int val;
+ int ret, i;
+
+ st->chip_en_gpio = devm_gpiod_get_optional(dev, "adi,enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(st->chip_en_gpio)) {
+ dev_err(dev, "Chip enable GPIO error\n");
+ return PTR_ERR(st->chip_en_gpio);
+ }
+
+ if (st->chip_en_gpio)
+ st->power_down_mode = ADF4360_POWER_DOWN_CE;
+
+ st->muxout_gpio = devm_gpiod_get_optional(dev, "adi,muxout", GPIOD_IN);
+ if (IS_ERR(st->muxout_gpio)) {
+ dev_err(dev, "Muxout GPIO error\n");
+ return PTR_ERR(st->muxout_gpio);
+ }
+
+ if (!st->muxout_gpio)
+ return 0;
+
+ /* ADF4360 PLLs are write only devices, try to probe using GPIO. */
+ for (i = 0; i < 4; i++) {
+ if (i & 1)
+ val = ADF4360_MUXOUT(ADF4360_MUXOUT_DVDD);
+ else
+ val = ADF4360_MUXOUT(ADF4360_MUXOUT_GND);
+
+ ret = adf4360_write_reg(st, ADF4360_REG(ADF4360_CTRL), val);
+ if (ret)
+ return ret;
+
+ ret = gpiod_get_value(st->muxout_gpio);
+ if (ret ^ (i & 1)) {
+ dev_err(dev, "Probe failed (muxout)");
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+static void adf4360_clkin_disable(void *data)
+{
+ struct adf4360_state *st = data;
+
+ clk_disable_unprepare(st->clkin);
+}
+
+static int adf4360_get_clkin(struct adf4360_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct clk *clk;
+ int ret;
+
+ clk = devm_clk_get(dev, "clkin");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, adf4360_clkin_disable, st);
+ if (ret)
+ return ret;
+
+ st->clkin = clk;
+ st->clkin_freq = clk_get_rate(clk);
+
+ return 0;
+}
+
+static void adf4360_clk_del_provider(void *data)
+{
+ struct adf4360_state *st = data;
+
+ of_clk_del_provider(st->spi->dev.of_node);
+}
+
+static int adf4360_clk_register(struct adf4360_state *st)
+{
+ struct spi_device *spi = st->spi;
+ struct clk_init_data init;
+ struct clk *clk;
+ const char *parent_name;
+ int ret;
+
+ parent_name = of_clk_get_parent_name(spi->dev.of_node, 0);
+ if (!parent_name)
+ return -EINVAL;
+
+ init.name = st->clk_out_name;
+ init.ops = &adf4360_clk_ops;
+ init.flags = CLK_SET_RATE_GATE;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ st->output.hw.init = &init;
+
+ clk = devm_clk_register(&spi->dev, &st->output.hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ ret = of_clk_add_provider(spi->dev.of_node, of_clk_src_simple_get, clk);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(&spi->dev, adf4360_clk_del_provider, st);
+}
+
+static int adf4360_parse_dt(struct adf4360_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ u32 tmp;
+ int ret;
+
+ ret = device_property_read_string(dev, "clock-output-names",
+ &st->clk_out_name);
+ if ((ret < 0) && dev->of_node)
+ st->clk_out_name = dev->of_node->name;
+
+ if (st->part_id >= ID_ADF4360_7) {
+ /*
+ * ADF4360-7 to ADF4360-9 have a VCO that is tuned to a specific
+ * range using an external inductor. These properties describe
+ * the range selected by the external inductor.
+ */
+ ret = device_property_read_u32(dev,
+ "adi,vco-minimum-frequency-hz",
+ &tmp);
+ if (ret == 0)
+ st->vco_min = max(st->info->vco_min, tmp);
+ else
+ st->vco_min = st->info->vco_min;
+
+ ret = device_property_read_u32(dev,
+ "adi,vco-maximum-frequency-hz",
+ &tmp);
+ if (ret == 0)
+ st->vco_max = min(st->info->vco_max, tmp);
+ else
+ st->vco_max = st->info->vco_max;
+ } else {
+ st->vco_min = st->info->vco_min;
+ st->vco_max = st->info->vco_max;
+ }
+
+ st->pdp = device_property_read_bool(dev, "adi,loop-filter-inverting");
+
+ ret = device_property_read_u32(dev,
+ "adi,loop-filter-pfd-frequency-hz",
+ &tmp);
+ if (ret == 0) {
+ st->pfd_freq = tmp;
+ } else {
+ dev_err(dev, "PFD frequency property missing\n");
+ return ret;
+ }
+
+ ret = device_property_read_u32(dev,
+ "adi,loop-filter-charge-pump-current-microamp",
+ &tmp);
+ if (ret == 0) {
+ st->cpi = find_closest(tmp, adf4360_cpi_modes,
+ ARRAY_SIZE(adf4360_cpi_modes));
+ } else {
+ dev_err(dev, "CPI property missing\n");
+ return ret;
+ }
+
+ ret = device_property_read_u32(dev, "adi,power-up-frequency-hz", &tmp);
+ if (ret == 0)
+ st->freq_req = tmp;
+ else
+ st->freq_req = st->vco_min;
+
+ ret = device_property_read_u32(dev, "adi,power-out-level-microamp",
+ &tmp);
+ if (ret == 0)
+ st->power_level = find_closest(tmp, adf4360_power_lvl_microamp,
+ ARRAY_SIZE(adf4360_power_lvl_microamp));
+ else
+ st->power_level = ADF4360_PL_5;
+
+ return 0;
+}
+
+static int adf4360_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct adf4360_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ mutex_init(&st->lock);
+
+ spi_set_drvdata(spi, indio_dev);
+
+ st->spi = spi;
+ st->info = &adf4360_chip_info_tbl[id->driver_data];
+ st->part_id = id->driver_data;
+ st->muxout_mode = ADF4360_MUXOUT_LOCK_DETECT;
+ st->mtld = true;
+
+ ret = adf4360_parse_dt(st);
+ if (ret) {
+ dev_err(&spi->dev, "Parsing properties failed (%d)\n", ret);
+ return -ENODEV;
+ }
+
+ indio_dev->dev.parent = &spi->dev;
+
+ if (spi->dev.of_node)
+ indio_dev->name = spi->dev.of_node->name;
+ else
+ indio_dev->name = spi_get_device_id(spi)->name;
+
+ indio_dev->info = &adf4360_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = &adf4360_chan;
+ indio_dev->num_channels = 1;
+ st->output.indio_dev = indio_dev;
+
+ ret = adf4360_get_gpio(st);
+ if (ret)
+ return ret;
+
+ ret = adf4360_get_clkin(st);
+ if (ret)
+ return ret;
+
+ st->vdd_reg = devm_regulator_get_optional(&spi->dev, "adi,vdd");
+ if (IS_ERR(st->vdd_reg)) {
+ if (PTR_ERR(st->vdd_reg) != -ENODEV) {
+ dev_err(&spi->dev, "Regulator error\n");
+ return PTR_ERR(st->vdd_reg);
+ }
+
+ st->vdd_reg = NULL;
+ }
+
+ ret = adf4360_power_down(st, ADF4360_POWER_DOWN_NORMAL);
+ if (ret)
+ return ret;
+
+ ret = adf4360_clk_register(st);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id adf4360_of_match[] = {
+ { .compatible = "adi,adf4360-0", },
+ { .compatible = "adi,adf4360-1", },
+ { .compatible = "adi,adf4360-2", },
+ { .compatible = "adi,adf4360-3", },
+ { .compatible = "adi,adf4360-4", },
+ { .compatible = "adi,adf4360-5", },
+ { .compatible = "adi,adf4360-6", },
+ { .compatible = "adi,adf4360-7", },
+ { .compatible = "adi,adf4360-8", },
+ { .compatible = "adi,adf4360-9", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, adf4360_of_match);
+
+static const struct spi_device_id adf4360_id[] = {
+ {"adf4360-0", ID_ADF4360_0},
+ {"adf4360-1", ID_ADF4360_1},
+ {"adf4360-2", ID_ADF4360_2},
+ {"adf4360-3", ID_ADF4360_3},
+ {"adf4360-4", ID_ADF4360_4},
+ {"adf4360-5", ID_ADF4360_5},
+ {"adf4360-6", ID_ADF4360_6},
+ {"adf4360-7", ID_ADF4360_7},
+ {"adf4360-8", ID_ADF4360_8},
+ {"adf4360-9", ID_ADF4360_9},
+ {}
+};
+
+static struct spi_driver adf4360_driver = {
+ .driver = {
+ .name = "adf4360",
+ .of_match_table = adf4360_of_match,
+ .owner = THIS_MODULE,
+ },
+ .probe = adf4360_probe,
+ .id_table = adf4360_id,
+};
+module_spi_driver(adf4360_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_AUTHOR("Edward Kigwana <ekigwana@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADF4360 PLL");
--
2.20.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/3] dt-bindings: iio: frequency: Add docs for ADF4360 PLL
2020-01-22 13:20 [PATCH v2 1/3] iio: frequency: adf4360: Add support for ADF4360 PLLs Alexandru Ardelean
@ 2020-01-22 13:20 ` Alexandru Ardelean
2020-01-27 21:35 ` Rob Herring
2020-01-22 13:20 ` [PATCH v2 3/3] MAINTAINERS: add entry for ADF4360 PLL driver Alexandru Ardelean
1 sibling, 1 reply; 5+ messages in thread
From: Alexandru Ardelean @ 2020-01-22 13:20 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: ekigwana, jic23, lars, robh+dt, Alexandru Ardelean
From: Edward Kigwana <ekigwana@gmail.com>
This change adds the device-tree bindings documentation for the ADF4360
family of PLLs.
Signed-off-by: Edward Kigwana <ekigwana@gmail.com>
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
.../bindings/iio/frequency/adf4371.yaml | 24 +--
.../bindings/iio/frequency/adi,adf4360.yaml | 158 ++++++++++++++++++
2 files changed, 170 insertions(+), 12 deletions(-)
create mode 100644 Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
diff --git a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
index 7ec3ec94356b..6edb68e8febf 100644
--- a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
+++ b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
@@ -48,16 +48,16 @@ required:
examples:
- |
- spi0 {
- #address-cells = <1>;
- #size-cells = <0>;
-
- frequency@0 {
- compatible = "adi,adf4371";
- reg = <0>;
- spi-max-frequency = <1000000>;
- clocks = <&adf4371_clkin>;
- clock-names = "clkin";
- };
- };
+ spi0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ frequency@0 {
+ compatible = "adi,adf4371";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ clocks = <&adf4371_clkin>;
+ clock-names = "clkin";
+ };
+ };
...
diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
new file mode 100644
index 000000000000..1a7f166d2a3f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
@@ -0,0 +1,158 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright 2019-2020 Edward Kigwana
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/frequency/adi,adf4360.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices ADF4360 PLL device driver
+
+maintainers:
+ - Lars-Peter Clausen <lars@metafoo.de>
+ - Edward Kigwana <ekigwana@gmail.com>
+
+description: |
+ Bindings for the Analog Devices ADF4360 family of clock generator phase-locked
+ loop (PLL) devices with an integrated voltage-controlled oscillator (VCO).
+ Each of the parts in the family supports a specific frequency range.
+ Datasheets can be found here:
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-0.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-1.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-2.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-3.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-4.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-5.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-6.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-7.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-8.pdf
+ https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-9.pdf
+
+properties:
+ compatible:
+ enum:
+ - adi,adf4360-0
+ - adi,adf4360-1
+ - adi,adf4360-2
+ - adi,adf4360-3
+ - adi,adf4360-4
+ - adi,adf4360-5
+ - adi,adf4360-6
+ - adi,adf4360-7
+ - adi,adf4360-8
+ - adi,adf4360-9
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ description: phandle to external reference clock.
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: clkin
+
+ '#clock-cells':
+ const: 0
+
+ adi,loop-filter-pfd-frequency-hz:
+ description: |
+ The phase-frequency-detector frequency that the external loop filter was
+ designed for.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ maxItems: 1
+
+ adi,loop-filter-charger-pump-current-microamp:
+ description: |
+ The charge pump current that the external loop filter was designed for.
+ The provided value is clamped to the closest enumerated value.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - enum: [310, 620, 930, 1250, 1560, 1870, 2180, 2500]
+ maxItems: 1
+
+ adi,vco-minimum-frequency-hz:
+ description: |
+ Required for ADF4360-7, ADF4360-8 and ADF4360-9. Minimum VCO frequency
+ that can be supported by the tuning range set by the external inductor.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ maxItems: 1
+
+ adi,vco-maximum-frequency-hz:
+ description: |
+ Required for ADF4360-7, ADF4360-8 and ADF4360-9. Maximum VCO frequency
+ that can be supported by the tuning range set by the external inductor.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ maxItems: 1
+
+ adi,loop-filter-inverting:
+ description: Indicates that the external loop filter is an inverting filter.
+ type: boolean
+
+ adi,power-up-frequency-hz:
+ description: |
+ PLL tunes to the set frequency on probe or defaults to either the minimum
+ for the part or value set using adi,vco-minimum-frequency-hz.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ maxItems: 1
+
+ adi,vdd-supply:
+ description: |
+ vdd supply is used to enable or disable chip when regulator power down
+ mode is set. Other power down modes are used to mitigate the case of a
+ shared regulator.
+ maxItems: 1
+
+ adi,enable-gpios:
+ description: |
+ Chip enable gpio is used to enable or disable chip when chip enable power
+ down mode is set.
+ maxItems: 1
+
+ adi,muxout-gpios:
+ description: |
+ MUX out gpio is used to detect chip and test pll lock state on read when
+ muxout control is set to lock detect.
+ maxItems: 1
+
+ adi,power-out-level-microamp:
+ description: |
+ Chip support setting of output power level. This property is optional.
+ If it is not provided by default 11000 uA will be set.
+ allOf:
+ - enum: [3500, 5000, 7500, 11000]
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - adi,loop-filter-charge-pump-current
+ - adi,loop-filter-pfd-frequency-hz
+
+examples:
+ - |
+ spi0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pll@0 {
+ compatible = "adi,adf4360-7";
+ reg = <0>;
+ spi-max-frequency = <2000000>;
+ clocks = <&ref_clock>;
+ #clock-cells = <0>;
+ clock-names = "clkin";
+ clock-output-names = "adf4360-7";
+
+ adi,loop-filter-charge-pump-current = <5>;
+ adi,loop-filter-pfd-frequency-hz = <2500000>;
+ adi,vco-minimum-frequency-hz = <700000000>;
+ adi,vco-maximum-frequency-hz = <840000000>;
+ };
+ };
+...
--
2.20.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 3/3] MAINTAINERS: add entry for ADF4360 PLL driver
2020-01-22 13:20 [PATCH v2 1/3] iio: frequency: adf4360: Add support for ADF4360 PLLs Alexandru Ardelean
2020-01-22 13:20 ` [PATCH v2 2/3] dt-bindings: iio: frequency: Add docs for ADF4360 PLL Alexandru Ardelean
@ 2020-01-22 13:20 ` Alexandru Ardelean
1 sibling, 0 replies; 5+ messages in thread
From: Alexandru Ardelean @ 2020-01-22 13:20 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: ekigwana, jic23, lars, robh+dt, Alexandru Ardelean
From: Edward Kigwana <ekigwana@gmail.com>
Add entry in the MAINTAINERS file for the ADF4360 PLL driver.
Signed-off-by: Edward Kigwana <ekigwana@gmail.com>
Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
MAINTAINERS | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index e699fe378e71..d7a404084ad9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -462,6 +462,14 @@ ADDRESS SPACE LAYOUT RANDOMIZATION (ASLR)
M: Jiri Kosina <jikos@kernel.org>
S: Maintained
+ADF4360 PLL DRIVER
+M: Edward Kigwana <ekigwana@gmail.com>
+W: http://ez.analog.com/community/linux-device-drivers
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
+F: drivers/iio/frequency/adf4360.c
+
ADF7242 IEEE 802.15.4 RADIO DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
W: https://wiki.analog.com/ADF7242
--
2.20.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/3] dt-bindings: iio: frequency: Add docs for ADF4360 PLL
2020-01-22 13:20 ` [PATCH v2 2/3] dt-bindings: iio: frequency: Add docs for ADF4360 PLL Alexandru Ardelean
@ 2020-01-27 21:35 ` Rob Herring
2020-01-28 6:40 ` Ardelean, Alexandru
0 siblings, 1 reply; 5+ messages in thread
From: Rob Herring @ 2020-01-27 21:35 UTC (permalink / raw)
To: Alexandru Ardelean
Cc: linux-iio, devicetree, linux-kernel, ekigwana, jic23, lars
On Wed, Jan 22, 2020 at 03:20:03PM +0200, Alexandru Ardelean wrote:
> From: Edward Kigwana <ekigwana@gmail.com>
>
> This change adds the device-tree bindings documentation for the ADF4360
> family of PLLs.
>
> Signed-off-by: Edward Kigwana <ekigwana@gmail.com>
> Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
> ---
> .../bindings/iio/frequency/adf4371.yaml | 24 +--
> .../bindings/iio/frequency/adi,adf4360.yaml | 158 ++++++++++++++++++
> 2 files changed, 170 insertions(+), 12 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
>
> diff --git a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
> index 7ec3ec94356b..6edb68e8febf 100644
> --- a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
> +++ b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
> @@ -48,16 +48,16 @@ required:
>
> examples:
> - |
> - spi0 {
> - #address-cells = <1>;
> - #size-cells = <0>;
> -
> - frequency@0 {
> - compatible = "adi,adf4371";
> - reg = <0>;
> - spi-max-frequency = <1000000>;
> - clocks = <&adf4371_clkin>;
> - clock-names = "clkin";
> - };
> - };
> + spi0 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + frequency@0 {
> + compatible = "adi,adf4371";
> + reg = <0>;
> + spi-max-frequency = <1000000>;
> + clocks = <&adf4371_clkin>;
> + clock-names = "clkin";
> + };
> + };
What's this change for?
> ...
> diff --git a/Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml b/Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
> new file mode 100644
> index 000000000000..1a7f166d2a3f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
> @@ -0,0 +1,158 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright 2019-2020 Edward Kigwana
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/frequency/adi,adf4360.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Analog Devices ADF4360 PLL device driver
> +
> +maintainers:
> + - Lars-Peter Clausen <lars@metafoo.de>
> + - Edward Kigwana <ekigwana@gmail.com>
> +
> +description: |
> + Bindings for the Analog Devices ADF4360 family of clock generator phase-locked
> + loop (PLL) devices with an integrated voltage-controlled oscillator (VCO).
> + Each of the parts in the family supports a specific frequency range.
> + Datasheets can be found here:
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-0.pdf
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-1.pdf
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-2.pdf
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-3.pdf
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-4.pdf
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-5.pdf
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-6.pdf
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-7.pdf
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-8.pdf
> + https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-9.pdf
> +
> +properties:
> + compatible:
> + enum:
> + - adi,adf4360-0
> + - adi,adf4360-1
> + - adi,adf4360-2
> + - adi,adf4360-3
> + - adi,adf4360-4
> + - adi,adf4360-5
> + - adi,adf4360-6
> + - adi,adf4360-7
> + - adi,adf4360-8
> + - adi,adf4360-9
The enum can be just:
pattern: '^adi,adf4360-[0-9]$'
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + description: phandle to external reference clock.
Not all that specific to this define, so drop.
> + maxItems: 1
> +
> + clock-names:
> + items:
> + - const: clkin
> +
> + '#clock-cells':
> + const: 0
> +
> + adi,loop-filter-pfd-frequency-hz:
> + description: |
> + The phase-frequency-detector frequency that the external loop filter was
> + designed for.
> + allOf:
> + - $ref: /schemas/types.yaml#/definitions/uint32
Standard type suffixes have a type already, so you can drop this.
> + maxItems: 1
Any constraints in the value?
> +
> + adi,loop-filter-charger-pump-current-microamp:
> + description: |
> + The charge pump current that the external loop filter was designed for.
> + The provided value is clamped to the closest enumerated value.
> + allOf:
> + - $ref: /schemas/types.yaml#/definitions/uint32
Can be dropped. Same goes for the rest.
> + - enum: [310, 620, 930, 1250, 1560, 1870, 2180, 2500]
> + maxItems: 1
> +
> + adi,vco-minimum-frequency-hz:
> + description: |
> + Required for ADF4360-7, ADF4360-8 and ADF4360-9. Minimum VCO frequency
> + that can be supported by the tuning range set by the external inductor.
> + allOf:
> + - $ref: /schemas/types.yaml#/definitions/uint32
> + maxItems: 1
> +
> + adi,vco-maximum-frequency-hz:
> + description: |
> + Required for ADF4360-7, ADF4360-8 and ADF4360-9. Maximum VCO frequency
> + that can be supported by the tuning range set by the external inductor.
> + allOf:
> + - $ref: /schemas/types.yaml#/definitions/uint32
> + maxItems: 1
> +
> + adi,loop-filter-inverting:
> + description: Indicates that the external loop filter is an inverting filter.
> + type: boolean
> +
> + adi,power-up-frequency-hz:
> + description: |
> + PLL tunes to the set frequency on probe or defaults to either the minimum
> + for the part or value set using adi,vco-minimum-frequency-hz.
> + allOf:
> + - $ref: /schemas/types.yaml#/definitions/uint32
> + maxItems: 1
> +
> + adi,vdd-supply:
> + description: |
> + vdd supply is used to enable or disable chip when regulator power down
> + mode is set. Other power down modes are used to mitigate the case of a
> + shared regulator.
> + maxItems: 1
-supply is always 1 item, so drop.
> +
> + adi,enable-gpios:
enable-gpios is a standard name, so drop the vendor prefix.
> + description: |
> + Chip enable gpio is used to enable or disable chip when chip enable power
> + down mode is set.
> + maxItems: 1
> +
> + adi,muxout-gpios:
> + description: |
> + MUX out gpio is used to detect chip and test pll lock state on read when
> + muxout control is set to lock detect.
> + maxItems: 1
> +
> + adi,power-out-level-microamp:
> + description: |
> + Chip support setting of output power level. This property is optional.
> + If it is not provided by default 11000 uA will be set.
> + allOf:
> + - enum: [3500, 5000, 7500, 11000]
Don't need the 'allOf'.
> +
> +required:
> + - compatible
> + - reg
> + - clocks
> + - clock-names
> + - adi,loop-filter-charge-pump-current
> + - adi,loop-filter-pfd-frequency-hz
> +
> +examples:
> + - |
> + spi0 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + pll@0 {
> + compatible = "adi,adf4360-7";
> + reg = <0>;
> + spi-max-frequency = <2000000>;
> + clocks = <&ref_clock>;
> + #clock-cells = <0>;
> + clock-names = "clkin";
> + clock-output-names = "adf4360-7";
> +
> + adi,loop-filter-charge-pump-current = <5>;
> + adi,loop-filter-pfd-frequency-hz = <2500000>;
> + adi,vco-minimum-frequency-hz = <700000000>;
> + adi,vco-maximum-frequency-hz = <840000000>;
> + };
> + };
> +...
> --
> 2.20.1
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/3] dt-bindings: iio: frequency: Add docs for ADF4360 PLL
2020-01-27 21:35 ` Rob Herring
@ 2020-01-28 6:40 ` Ardelean, Alexandru
0 siblings, 0 replies; 5+ messages in thread
From: Ardelean, Alexandru @ 2020-01-28 6:40 UTC (permalink / raw)
To: robh@kernel.org
Cc: ekigwana@gmail.com, jic23@kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-iio@vger.kernel.org,
lars@metafoo.de
On Mon, 2020-01-27 at 15:35 -0600, Rob Herring wrote:
> On Wed, Jan 22, 2020 at 03:20:03PM +0200, Alexandru Ardelean wrote:
> > From: Edward Kigwana <ekigwana@gmail.com>
> >
> > This change adds the device-tree bindings documentation for the ADF4360
> > family of PLLs.
> >
> > Signed-off-by: Edward Kigwana <ekigwana@gmail.com>
> > Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
> > ---
> > .../bindings/iio/frequency/adf4371.yaml | 24 +--
> > .../bindings/iio/frequency/adi,adf4360.yaml | 158 ++++++++++++++++++
> > 2 files changed, 170 insertions(+), 12 deletions(-)
> > create mode 100644
> > Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
> > b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
> > index 7ec3ec94356b..6edb68e8febf 100644
> > --- a/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
> > +++ b/Documentation/devicetree/bindings/iio/frequency/adf4371.yaml
> > @@ -48,16 +48,16 @@ required:
> >
> > examples:
> > - |
> > - spi0 {
> > - #address-cells = <1>;
> > - #size-cells = <0>;
> > -
> > - frequency@0 {
> > - compatible = "adi,adf4371";
> > - reg = <0>;
> > - spi-max-frequency = <1000000>;
> > - clocks = <&adf4371_clkin>;
> > - clock-names = "clkin";
> > - };
> > - };
> > + spi0 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + frequency@0 {
> > + compatible = "adi,adf4371";
> > + reg = <0>;
> > + spi-max-frequency = <1000000>;
> > + clocks = <&adf4371_clkin>;
> > + clock-names = "clkin";
> > + };
> > + };
>
> What's this change for?
Wait... what?
I'll drop this.
I'll implement the rest.
>
> > ...
> > diff --git
> > a/Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
> > b/Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
> > new file mode 100644
> > index 000000000000..1a7f166d2a3f
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/iio/frequency/adi,adf4360.yaml
> > @@ -0,0 +1,158 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +# Copyright 2019-2020 Edward Kigwana
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/iio/frequency/adi,adf4360.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Analog Devices ADF4360 PLL device driver
> > +
> > +maintainers:
> > + - Lars-Peter Clausen <lars@metafoo.de>
> > + - Edward Kigwana <ekigwana@gmail.com>
> > +
> > +description: |
> > + Bindings for the Analog Devices ADF4360 family of clock generator phase-
> > locked
> > + loop (PLL) devices with an integrated voltage-controlled oscillator
> > (VCO).
> > + Each of the parts in the family supports a specific frequency range.
> > + Datasheets can be found here:
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-0.pdf
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-1.pdf
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-2.pdf
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-3.pdf
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-4.pdf
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-5.pdf
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-6.pdf
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-7.pdf
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-8.pdf
> > +
> > https://www.analog.com/media/en/technical-documentation/data-sheets/ADF4360-9.pdf
> > +
> > +properties:
> > + compatible:
> > + enum:
> > + - adi,adf4360-0
> > + - adi,adf4360-1
> > + - adi,adf4360-2
> > + - adi,adf4360-3
> > + - adi,adf4360-4
> > + - adi,adf4360-5
> > + - adi,adf4360-6
> > + - adi,adf4360-7
> > + - adi,adf4360-8
> > + - adi,adf4360-9
>
> The enum can be just:
>
> pattern: '^adi,adf4360-[0-9]$'
>
>
> > +
> > + reg:
> > + maxItems: 1
> > +
> > + clocks:
> > + description: phandle to external reference clock.
>
> Not all that specific to this define, so drop.
>
> > + maxItems: 1
> > +
> > + clock-names:
> > + items:
> > + - const: clkin
> > +
> > + '#clock-cells':
> > + const: 0
> > +
> > + adi,loop-filter-pfd-frequency-hz:
> > + description: |
> > + The phase-frequency-detector frequency that the external loop filter
> > was
> > + designed for.
> > + allOf:
> > + - $ref: /schemas/types.yaml#/definitions/uint32
>
> Standard type suffixes have a type already, so you can drop this.
>
> > + maxItems: 1
>
> Any constraints in the value?
>
> > +
> > + adi,loop-filter-charger-pump-current-microamp:
> > + description: |
> > + The charge pump current that the external loop filter was designed
> > for.
> > + The provided value is clamped to the closest enumerated value.
> > + allOf:
> > + - $ref: /schemas/types.yaml#/definitions/uint32
>
> Can be dropped. Same goes for the rest.
>
> > + - enum: [310, 620, 930, 1250, 1560, 1870, 2180, 2500]
> > + maxItems: 1
> > +
> > + adi,vco-minimum-frequency-hz:
> > + description: |
> > + Required for ADF4360-7, ADF4360-8 and ADF4360-9. Minimum VCO
> > frequency
> > + that can be supported by the tuning range set by the external
> > inductor.
> > + allOf:
> > + - $ref: /schemas/types.yaml#/definitions/uint32
> > + maxItems: 1
> > +
> > + adi,vco-maximum-frequency-hz:
> > + description: |
> > + Required for ADF4360-7, ADF4360-8 and ADF4360-9. Maximum VCO
> > frequency
> > + that can be supported by the tuning range set by the external
> > inductor.
> > + allOf:
> > + - $ref: /schemas/types.yaml#/definitions/uint32
> > + maxItems: 1
> > +
> > + adi,loop-filter-inverting:
> > + description: Indicates that the external loop filter is an inverting
> > filter.
> > + type: boolean
> > +
> > + adi,power-up-frequency-hz:
> > + description: |
> > + PLL tunes to the set frequency on probe or defaults to either the
> > minimum
> > + for the part or value set using adi,vco-minimum-frequency-hz.
> > + allOf:
> > + - $ref: /schemas/types.yaml#/definitions/uint32
> > + maxItems: 1
> > +
> > + adi,vdd-supply:
> > + description: |
> > + vdd supply is used to enable or disable chip when regulator power
> > down
> > + mode is set. Other power down modes are used to mitigate the case of
> > a
> > + shared regulator.
> > + maxItems: 1
>
> -supply is always 1 item, so drop.
>
> > +
> > + adi,enable-gpios:
>
> enable-gpios is a standard name, so drop the vendor prefix.
>
> > + description: |
> > + Chip enable gpio is used to enable or disable chip when chip enable
> > power
> > + down mode is set.
> > + maxItems: 1
> > +
> > + adi,muxout-gpios:
> > + description: |
> > + MUX out gpio is used to detect chip and test pll lock state on read
> > when
> > + muxout control is set to lock detect.
> > + maxItems: 1
> > +
> > + adi,power-out-level-microamp:
> > + description: |
> > + Chip support setting of output power level. This property is
> > optional.
> > + If it is not provided by default 11000 uA will be set.
> > + allOf:
> > + - enum: [3500, 5000, 7500, 11000]
>
> Don't need the 'allOf'.
>
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - clocks
> > + - clock-names
> > + - adi,loop-filter-charge-pump-current
> > + - adi,loop-filter-pfd-frequency-hz
> > +
> > +examples:
> > + - |
> > + spi0 {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + pll@0 {
> > + compatible = "adi,adf4360-7";
> > + reg = <0>;
> > + spi-max-frequency = <2000000>;
> > + clocks = <&ref_clock>;
> > + #clock-cells = <0>;
> > + clock-names = "clkin";
> > + clock-output-names = "adf4360-7";
> > +
> > + adi,loop-filter-charge-pump-current = <5>;
> > + adi,loop-filter-pfd-frequency-hz = <2500000>;
> > + adi,vco-minimum-frequency-hz = <700000000>;
> > + adi,vco-maximum-frequency-hz = <840000000>;
> > + };
> > + };
> > +...
> > --
> > 2.20.1
> >
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2020-01-28 6:41 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-01-22 13:20 [PATCH v2 1/3] iio: frequency: adf4360: Add support for ADF4360 PLLs Alexandru Ardelean
2020-01-22 13:20 ` [PATCH v2 2/3] dt-bindings: iio: frequency: Add docs for ADF4360 PLL Alexandru Ardelean
2020-01-27 21:35 ` Rob Herring
2020-01-28 6:40 ` Ardelean, Alexandru
2020-01-22 13:20 ` [PATCH v2 3/3] MAINTAINERS: add entry for ADF4360 PLL driver Alexandru Ardelean
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.