linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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; +Cc: ekigwana, jic23, devicetree, linux-kernel, linux-iio, lars

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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).