lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <3agb73fmwhcoho4uowhwh3tchux5wb5amgzrmr2fj66uiw4grg@oddcbaeqmneu>
Date: Mon, 22 Dec 2025 09:45:30 +0000
From: Rodrigo Alencar <455.rodrigo.alencar@...il.com>
To: Jonathan Cameron <jic23@...nel.org>, 
	Rodrigo Alencar via B4 Relay <devnull+rodrigo.alencar.analog.com@...nel.org>
Cc: rodrigo.alencar@...log.com, linux-kernel@...r.kernel.org, 
	linux-iio@...r.kernel.org, devicetree@...r.kernel.org, linux-doc@...r.kernel.org, 
	David Lechner <dlechner@...libre.com>, Andy Shevchenko <andy@...nel.org>, 
	Lars-Peter Clausen <lars@...afoo.de>, Michael Hennerich <Michael.Hennerich@...log.com>, 
	Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>, 
	Conor Dooley <conor+dt@...nel.org>, Jonathan Corbet <corbet@....net>
Subject: Re: [PATCH v2 2/6] iio: frequency: adf41513: driver implementation

On 25/12/21 05:49PM, Jonathan Cameron wrote:
> On Fri, 19 Dec 2025 12:34:49 +0000
> Rodrigo Alencar via B4 Relay <devnull+rodrigo.alencar.analog.com@...nel.org> wrote:
> 
> > From: Rodrigo Alencar <rodrigo.alencar@...log.com>
> > 
> > The driver is based on existing PLL drivers in the IIO subsystem and
> > implements the following key features:
> > 
> > - Integer-N and fractional-N (fixed/variable modulus) synthesis modes
> > - High-resolution frequency calculations using microhertz (µHz) precision
> >   to handle sub-Hz resolution across multi-GHz frequency ranges
> > - IIO debugfs interface for direct register access
> > - FW property parsing from devicetree including charge pump settings,
> >   reference path configuration and muxout options
> > - Power management support with suspend/resume callbacks
> > - Lock detect GPIO monitoring
> > 
> > The driver uses 64-bit microhertz values throughout PLL calculations to
> > maintain precision when working with frequencies that exceed 32-bit Hz
> > representation while requiring fractional Hz resolution.
> > 
> > Signed-off-by: Rodrigo Alencar <rodrigo.alencar@...log.com>
> Hi Rodrigo,
> 
> Various comments inline.
> 
> Thanks,
> 
> Jonathan

Hi Jonathan,

valuable review, thanks!

kind regards,

Rodrigo Alencar
 
> > diff --git a/drivers/iio/frequency/adf41513.c b/drivers/iio/frequency/adf41513.c
> > new file mode 100644
> > index 000000000000..a967dc4479e7
> > --- /dev/null
> > +++ b/drivers/iio/frequency/adf41513.c
> 
> 
> > +
> > +static int adf41513_sync_config(struct adf41513_state *st, u16 sync_mask)
> > +{
> > +	int ret;
> > +	int i;
> > +
> > +	/* write registers in reverse order (R13 to R0)*/
> > +	for (i = ADF41513_REG13; i >= ADF41513_REG0; i--) {
> > +		if (st->regs_hw[i] != st->regs[i] || sync_mask & BIT(i)) {
> For code cases like this where you want to only do something if a condition is matched
> it can be neater to invert the condition.  e.g.
> 
> 		if (st->regs_hw[i] == st->regs[i] && !(sync_mask & BIT(i)))
> 			continue;
> 
> 		st->buf = cpu...
> 
> > +			st->buf = cpu_to_be32(st->regs[i] | i);
> > +			ret = spi_write(st->spi, &st->buf, sizeof(st->buf));
> > +			if (ret < 0)
> > +				return ret;
> > +			st->regs_hw[i] = st->regs[i];
> > +			dev_dbg(&st->spi->dev, "REG%d <= 0x%08X\n", i, st->regs[i] | i);
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static u64 adf41513_pll_get_rate(struct adf41513_state *st)
> > +{
> > +	struct adf41513_pll_settings *cfg = &st->settings;
> > +
> > +	if (cfg->mode != ADF41513_MODE_INVALID)
> > +		return cfg->actual_frequency_uhz;
> > +
> > +	/* get pll settings from regs_hw */
> > +	cfg->int_value = FIELD_GET(ADF41513_REG0_INT_MSK,
> > +				   st->regs_hw[ADF41513_REG0]);
> > +	cfg->frac1 = FIELD_GET(ADF41513_REG1_FRAC1_MSK,
> > +			       st->regs_hw[ADF41513_REG1]);
> > +	cfg->frac2 = FIELD_GET(ADF41513_REG3_FRAC2_MSK,
> > +			       st->regs_hw[ADF41513_REG3]);
> > +	cfg->mod2 = FIELD_GET(ADF41513_REG4_MOD2_MSK,
> > +			      st->regs_hw[ADF41513_REG4]);
> > +	cfg->r_counter = FIELD_GET(ADF41513_REG5_R_CNT_MSK,
> > +				   st->regs_hw[ADF41513_REG5]);
> > +	cfg->ref_doubler = FIELD_GET(ADF41513_REG5_REF_DOUBLER_MSK,
> > +				     st->regs_hw[ADF41513_REG5]);
> > +	cfg->ref_div2 = FIELD_GET(ADF41513_REG5_RDIV2_MSK,
> > +				  st->regs_hw[ADF41513_REG5]);
> > +	cfg->prescaler = FIELD_GET(ADF41513_REG5_PRESCALER_MSK,
> > +				   st->regs_hw[ADF41513_REG5]);
> For cases like this I think keeping to 80 chars is hurting readability
> and so it is fine to go a little higher. 
> 	cfg->int_value = FIELD_GET(ADF41513_REG0_INT_MSK, st->regs_hw[ADF41513_REG0]);
> 	cfg->frac1 = FIELD_GET(ADF41513_REG1_FRAC1_MSK, st->regs_hw[ADF41513_REG1]);
> 	cfg->frac2 = FIELD_GET(ADF41513_REG3_FRAC2_MSK, st->regs_hw[ADF41513_REG3]);
> 	cfg->mod2 = FIELD_GET(ADF41513_REG4_MOD2_MSK, st->regs_hw[ADF41513_REG4]);
> 	cfg->r_counter = FIELD_GET(ADF41513_REG5_R_CNT_MSK, st->regs_hw[ADF41513_REG5]);
> 	cfg->ref_doubler = FIELD_GET(ADF41513_REG5_REF_DOUBLER_MSK, st->regs_hw[ADF41513_REG5]);
> 	cfg->ref_div2 = FIELD_GET(ADF41513_REG5_RDIV2_MSK, st->regs_hw[ADF41513_REG5]);
> 	cfg->prescaler = FIELD_GET(ADF41513_REG5_PRESCALER_MSK,st->regs_hw[ADF41513_REG5]);
> Is fine here. I'd also be fine with wrapping the ref_doubler line as it's rather
> longer than the others.

ack
 
> > +
> > +	/* calculate pfd frequency */
> > +	cfg->pfd_frequency_uhz = st->ref_freq_hz * MICROHZ_PER_HZ;
> > +	if (cfg->ref_doubler)
> > +		cfg->pfd_frequency_uhz <<= 1;
> > +	if (cfg->ref_div2)
> > +		cfg->pfd_frequency_uhz >>= 1;
> > +	cfg->pfd_frequency_uhz = div_u64(cfg->pfd_frequency_uhz,
> > +					 cfg->r_counter);
> > +	cfg->actual_frequency_uhz = (u64)cfg->int_value * cfg->pfd_frequency_uhz;
> > +
> > +	/* check if int mode is selected */
> > +	if (FIELD_GET(ADF41513_REG6_INT_MODE_MSK, st->regs_hw[ADF41513_REG6])) {
> > +		cfg->mode = ADF41513_MODE_INTEGER_N;
> > +	} else {
> > +		cfg->actual_frequency_uhz += mul_u64_u64_div_u64(cfg->frac1,
> > +								 cfg->pfd_frequency_uhz,
> > +								 ADF41513_FIXED_MODULUS);
> > +
> > +		/* check if variable modulus is selected */
> > +		if (FIELD_GET(ADF41513_REG0_VAR_MOD_MSK, st->regs_hw[ADF41513_REG0])) {
> > +			cfg->actual_frequency_uhz +=
> > +				mul_u64_u64_div_u64(cfg->frac2,
> > +						    cfg->pfd_frequency_uhz,
> > +						    ADF41513_FIXED_MODULUS * cfg->mod2);
> > +
> > +			cfg->mode = ADF41513_MODE_VARIABLE_MODULUS;
> > +		} else {
> > +			/* LSB_P1 offset */
> > +			if (!FIELD_GET(ADF41513_REG5_LSB_P1_MSK, st->regs_hw[ADF41513_REG5]))
> > +				cfg->actual_frequency_uhz +=
> > +					div_u64(cfg->pfd_frequency_uhz,
> > +						ADF41513_FIXED_MODULUS * 2);
> > +			cfg->mode = ADF41513_MODE_FIXED_MODULUS;
> > +		}
> > +	}
> > +
> > +	cfg->target_frequency_uhz = cfg->actual_frequency_uhz;
> > +
> > +	return cfg->actual_frequency_uhz;
> > +}
> 
> 
> > +static int adf41513_calc_pll_settings(struct adf41513_state *st,
> > +				      struct adf41513_pll_settings *result,
> > +				      u64 rf_out_uhz)
> > +{
> > +	u64 max_rf_freq_uhz = st->chip_info->max_rf_freq_hz * MICROHZ_PER_HZ;
> > +	u64 min_rf_freq_uhz = ADF41513_MIN_RF_FREQ * MICROHZ_PER_HZ;
> > +	u64 pfd_freq_limit_uhz;
> > +	int ret;
> > +
> > +	/* input validation */
> 
> That's obvious.  No need to have the comment.

ack

> > +	if (rf_out_uhz < min_rf_freq_uhz || rf_out_uhz > max_rf_freq_uhz) {
> > +		dev_err(&st->spi->dev, "RF frequency %llu uHz out of range [%llu, %llu] uHz\n",
> > +			rf_out_uhz, min_rf_freq_uhz, max_rf_freq_uhz);
> > +		return -EINVAL;
> > +	}
> > +
> > +	result->target_frequency_uhz = rf_out_uhz;
> > +
> > +	/* try integer-N first (best phase noise performance) */
> > +	pfd_freq_limit_uhz = min(div_u64(rf_out_uhz, ADF41513_MIN_INT_4_5),
> > +				 ADF41513_MAX_PFD_FREQ_INT_N_UHZ);
> > +	ret = adf41513_calc_pfd_frequency(st, result, pfd_freq_limit_uhz);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	ret = adf41513_calc_integer_n(st, result);
> > +	if (ret < 0) {
> > +		/* try fractional-N: recompute pfd frequency if necessary */
> > +		pfd_freq_limit_uhz = min(div_u64(rf_out_uhz, ADF41513_MIN_INT_FRAC_4_5),
> > +					 ADF41513_MAX_PFD_FREQ_FRAC_N_UHZ);
> > +		if (pfd_freq_limit_uhz < result->pfd_frequency_uhz) {
> > +			ret = adf41513_calc_pfd_frequency(st, result, pfd_freq_limit_uhz);
> > +			if (ret < 0)
> > +				return ret;
> > +		}
> > +
> > +		/* fixed-modulus attempt */
> > +		ret = adf41513_calc_fixed_mod(st, result);
> > +		if (ret < 0) {
> > +			/* variable-modulus attempt */
> > +			ret = adf41513_calc_variable_mod(st, result);
> > +			if (ret < 0) {
> > +				dev_err(&st->spi->dev,
> > +					"no valid PLL configuration found for %llu uHz\n",
> > +					rf_out_uhz);
> > +				return -EINVAL;
> > +			}
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int adf41513_set_frequency(struct adf41513_state *st, u64 freq_uhz, u16 sync_mask)
> > +{
> > +	struct adf41513_pll_settings result;
> > +	int ret;
> > +
> > +	/* calculate pll settings candidate */
> > +	ret = adf41513_calc_pll_settings(st, &result, freq_uhz);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	/* apply computed results to pll settings */
> > +	memcpy(&st->settings, &result, sizeof(struct adf41513_pll_settings));
> 
> sizeof(st->settings)
> 
> > +
> > +	dev_dbg(&st->spi->dev,
> > +		"%s mode: int=%u, frac1=%u, frac2=%u, mod2=%u, fpdf=%llu Hz, prescaler=%s\n",
> > +		(result.mode == ADF41513_MODE_INTEGER_N) ? "integer-n" :
> > +		(result.mode == ADF41513_MODE_FIXED_MODULUS) ? "fixed-modulus" : "variable-modulus",
> > +		result.int_value, result.frac1, result.frac2, result.mod2,
> > +		div64_u64(result.pfd_frequency_uhz, MICROHZ_PER_HZ),
> > +		result.prescaler ? "8/9" : "4/5");
> > +
> > +	/* int */
> > +	st->regs[ADF41513_REG0] = FIELD_PREP(ADF41513_REG0_INT_MSK,
> > +					     st->settings.int_value);
> > +	if (st->settings.mode == ADF41513_MODE_VARIABLE_MODULUS)
> > +		st->regs[ADF41513_REG0] |= ADF41513_REG0_VAR_MOD_MSK;
> > +	/* frac1 */
> > +	st->regs[ADF41513_REG1] = FIELD_PREP(ADF41513_REG1_FRAC1_MSK,
> > +					     st->settings.frac1);
> > +	if (st->settings.mode != ADF41513_MODE_INTEGER_N)
> > +		st->regs[ADF41513_REG1] |= ADF41513_REG1_DITHER2_MSK;
> > +
> > +	/* frac2 */
> 
> Where the field name makes it obvious there is little point in
> adding a comment to say the same thing. I'd clear out most if not all
> of these. Stick to comments that add significant value.

ack

> > +	st->regs[ADF41513_REG3] = FIELD_PREP(ADF41513_REG3_FRAC2_MSK,
> > +					     st->settings.frac2);
> > +	/* mod2 */
> > +	st->regs[ADF41513_REG4] &= ADF41513_REG4_MOD2_MSK;
> > +	st->regs[ADF41513_REG4] |= FIELD_PREP(ADF41513_REG4_MOD2_MSK,
> > +					      st->settings.mod2);
> > +
> > +	/* r-cnt | doubler | rdiv2 | prescaler */
> > +	st->regs[ADF41513_REG5] &= ~(ADF41513_REG5_R_CNT_MSK |
> > +				     ADF41513_REG5_REF_DOUBLER_MSK |
> > +				     ADF41513_REG5_RDIV2_MSK |
> > +				     ADF41513_REG5_PRESCALER_MSK);
> > +	st->regs[ADF41513_REG5] |= FIELD_PREP(ADF41513_REG5_R_CNT_MSK,
> > +					      st->settings.r_counter);
> > +	st->regs[ADF41513_REG5] |= FIELD_PREP(ADF41513_REG5_REF_DOUBLER_MSK,
> > +					      st->settings.ref_doubler);
> > +	st->regs[ADF41513_REG5] |= FIELD_PREP(ADF41513_REG5_RDIV2_MSK,
> > +					      st->settings.ref_div2);
> > +	st->regs[ADF41513_REG5] |= FIELD_PREP(ADF41513_REG5_PRESCALER_MSK,
> > +					      st->settings.prescaler);
> 
> Probably better to use FIELD_MODIFY for all of these and let the compiler
> figure out it can mask them all in one go.

ack

> > +
> > +	if (st->settings.mode == ADF41513_MODE_INTEGER_N) {
> > +		st->regs[ADF41513_REG6] |= ADF41513_REG6_INT_MODE_MSK;
> > +		st->regs[ADF41513_REG6] &= ~ADF41513_REG6_BLEED_ENABLE_MSK;
> > +	} else {
> > +		st->regs[ADF41513_REG6] &= ~ADF41513_REG6_INT_MODE_MSK;
> > +		st->regs[ADF41513_REG6] |= ADF41513_REG6_BLEED_ENABLE_MSK;
> > +	}
> > +
> > +	return adf41513_sync_config(st, sync_mask | ADF41513_SYNC_REG0);
> > +}
> 
> > +static ssize_t adf41513_read_uhz(struct iio_dev *indio_dev,
> > +				 uintptr_t private,
> > +				 const struct iio_chan_spec *chan,
> > +				 char *buf)
> > +{
> > +	struct adf41513_state *st = iio_priv(indio_dev);
> > +	u64 freq_uhz;
> > +
> > +	guard(mutex)(&st->lock);
> > +
> > +	switch ((u32)private) {
> > +	case ADF41513_FREQ:
> > +		freq_uhz = adf41513_pll_get_rate(st);
> > +		if (st->lock_detect)
> > +			if (!gpiod_get_value_cansleep(st->lock_detect)) {
> > +				dev_dbg(&st->spi->dev, "PLL un-locked\n");
> > +				return -EBUSY;
> > +			}
> > +		break;
> > +	case ADF41513_FREQ_RESOLUTION:
> > +		freq_uhz = st->data.freq_resolution_uhz;
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return adf41513_uhz_to_str(freq_uhz, buf);
> This is a more marginal case than the ones below wrt to a common
> function making sense as there is more overlap. I''m not sure it
> is worth doing even so (rather than separate callbacks).

ack. will split them.

> > +}
> > +
> > +static ssize_t adf41513_read(struct iio_dev *indio_dev,
> > +			     uintptr_t private,
> > +			     const struct iio_chan_spec *chan,
> > +			     char *buf)
> > +{
> > +	struct adf41513_state *st = iio_priv(indio_dev);
> > +	u32 val;
> > +
> > +	guard(mutex)(&st->lock);
> > +
> > +	switch ((u32)private) {
> > +	case ADF41513_FREQ_REFIN:
> > +		st->ref_freq_hz = clk_get_rate(st->ref_clk);
> > +		return sysfs_emit(buf, "%llu\n", st->ref_freq_hz);
> 
> Not much sharing here either (see below). I'd be tempted to just spit this
> into specific callbacks.

ack.

> > +	case ADF41513_POWER_DOWN:
> > +		val = FIELD_GET(ADF41513_REG6_POWER_DOWN_MSK,
> > +				st->regs_hw[ADF41513_REG6]);
> > +		return sysfs_emit(buf, "%u\n", val);
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> 
> > +
> > +static ssize_t adf41513_write(struct iio_dev *indio_dev,
> > +			      uintptr_t private,
> > +			      const struct iio_chan_spec *chan,
> > +			      const char *buf, size_t len)
> > +{
> > +	struct adf41513_state *st = iio_priv(indio_dev);
> > +	unsigned long readin, tmp;
> > +	int ret;
> > +
> > +	ret = kstrtoul(buf, 10, &readin);
> > +	if (ret)
> > +		return ret;
> > +
> > +	guard(mutex)(&st->lock);
> > +
> > +	switch ((u32)private) {
> > +	case ADF41513_FREQ_REFIN:
> 
> There isn't a lot of shared code between different calls of this.
> Perhaps just have separate callbacks for each one.

ack.

> > +		if (readin < ADF41513_MIN_REF_FREQ || readin > ADF41513_MAX_REF_FREQ)
> > +			return -EINVAL;
> > +
> > +		tmp = clk_round_rate(st->ref_clk, readin);
> > +		if (tmp != readin)
> > +			return -EINVAL;
> > +
> > +		ret = clk_set_rate(st->ref_clk, tmp);
> > +		if (ret < 0)
> > +			return ret;
> > +
> > +		st->ref_freq_hz = readin;
> > +		ret = adf41513_set_frequency(st, st->settings.target_frequency_uhz,
> > +					     ADF41513_SYNC_DIFF);
> > +		break;
> > +	case ADF41513_POWER_DOWN:
> > +		if (readin)
> > +			ret = adf41513_suspend(st);
> > +		else
> > +			ret = adf41513_resume(st);
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return ret ? ret : len;
> > +}
> > +
> > +#define _ADF41513_EXT_INFO(_name, _ident) { \
> > +	.name = _name, \
> > +	.read = adf41513_read, \
> > +	.write = adf41513_write, \
> > +	.private = _ident, \
> > +	.shared = IIO_SEPARATE, \
> > +}
> > +
> > +#define _ADF41513_EXT_UHZ_INFO(_name, _ident) { \
> > +	.name = _name, \
> > +	.read = adf41513_read_uhz, \
> > +	.write = adf41513_write_uhz, \
> > +	.private = _ident, \
> > +	.shared = IIO_SEPARATE, \
> > +}
> > +
> > +static const struct iio_chan_spec_ext_info adf41513_ext_info[] = {
> > +	/*
> > +	 * Ideally we would use IIO_CHAN_INFO_FREQUENCY, but the device supports
> > +	 * frequency values greater 2^32 with sub-Hz resolution, i.e. 64-bit
> > +	 * fixed point with 6 decimal places values are used to represent
> > +	 * frequencies.
> > +	 */
> > +	_ADF41513_EXT_UHZ_INFO("frequency", ADF41513_FREQ),
> > +	_ADF41513_EXT_UHZ_INFO("frequency_resolution", ADF41513_FREQ_RESOLUTION),
> > +	_ADF41513_EXT_INFO("refin_frequency", ADF41513_FREQ_REFIN),
> Some of these are not things I recall as being standard ABI.
> This one is in one other driver but to make it generic you need to promote
> the ABI documentation to a shared file.

ack. will create the shared ABI file.

> > +	_ADF41513_EXT_INFO("powerdown", ADF41513_POWER_DOWN),
> > +	{ },
> 
> No comma on terminating entries like this.

ack

> > +};
> > +
> > +static const struct iio_chan_spec adf41513_chan = {
> > +	.type = IIO_ALTVOLTAGE,
> > +	.indexed = 1,
> > +	.output = 1,
> > +	.channel = 0,
> > +	.info_mask_separate = BIT(IIO_CHAN_INFO_PHASE),
> > +	.ext_info = adf41513_ext_info,
> > +};
> > +
> > +static int adf41513_read_raw(struct iio_dev *indio_dev,
> > +			     struct iio_chan_spec const *chan,
> > +			     int *val, int *val2, long info)
> > +{
> > +	struct adf41513_state *st = iio_priv(indio_dev);
> > +	u32 phase_mdeg;
> > +	u16 phase_val;
> > +
> > +	guard(mutex)(&st->lock);
> > +
> > +	switch (info) {
> > +	case IIO_CHAN_INFO_PHASE:
> > +		phase_val = FIELD_GET(ADF41513_REG2_PHASE_VAL_MSK,
> > +				      st->regs_hw[ADF41513_REG2]);
> > +		phase_mdeg = DIV_ROUND_CLOSEST(360 * MILLI * phase_val, BIT(12));
> > +		*val = phase_mdeg / MILLI;
> > +		*val2 = (phase_mdeg % MILLI) * 1000;
> 
> This sounds like it is in degrees. Note _phase attributes are in the documented
> ABI Documentation/ABI/testing/sysfs-bus-iio as in radians.

ack. will use radians conversion.

> > +		return IIO_VAL_INT_PLUS_MICRO;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> > +
> > +static int adf41513_write_raw(struct iio_dev *indio_dev,
> > +			      struct iio_chan_spec const *chan,
> > +			      int val, int val2, long info)
> > +{
> > +	struct adf41513_state *st = iio_priv(indio_dev);
> > +	u32 phase_mdeg;
> > +	u16 phase_val;
> > +
> > +	guard(mutex)(&st->lock);
> > +
> > +	switch (info) {
> > +	case IIO_CHAN_INFO_PHASE:
> > +		val %= 360;
> > +		if (val < 0)
> > +			val += 360;
> > +		phase_mdeg = val * MILLI + val2 / 1000;
> > +		phase_val = DIV_ROUND_CLOSEST(phase_mdeg << 12, 360 * MILLI);
> > +
> > +		st->regs[ADF41513_REG2] |= ADF41513_REG2_PHASE_ADJ_MSK;
> > +		st->regs[ADF41513_REG2] &= ~ADF41513_REG2_PHASE_VAL_MSK;
> 
> FIELD_MODIFY() can save doing the clear and fill as separate calls.

ack.

> > +		st->regs[ADF41513_REG2] |= FIELD_PREP(ADF41513_REG2_PHASE_VAL_MSK, phase_val);
> > +		return adf41513_sync_config(st, ADF41513_SYNC_REG0);
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +}
> 
> 
> > +static int adf41513_parse_fw(struct adf41513_state *st)
> > +{
> > +	struct device *dev = &st->spi->dev;
> > +	int ret;
> > +	u32 tmp;
> > +	u32 cp_resistance;
> > +	u32 cp_current;
> Where you have set of variables of same type and grouping doesn't hurt
> readability, declare them all on one line.
> 
> 	u32 tmp, cp_resistance, cp_current;

ack

> I'll not repeat comments I made on the dt-binding in here but I'd expect
> this code to change somewhat in response to those.

understood. for now, will use -mhz for the power-up frequency, but I will
see how the discussion follows.

> > +
> 
> ...
> 
> 
> > +static int adf41513_setup(struct adf41513_state *st)
> > +{
> > +	u32 tmp;
> > +
> > +	memset(st->regs_hw, 0xFF, sizeof(st->regs_hw));
> > +
> > +	/* assume DLD pin is used for digital lock detect */
> > +	st->regs[ADF41513_REG5] = FIELD_PREP(ADF41513_REG5_DLD_MODES_MSK,
> > +					     ADF41513_DLD_DIG_LD);
> > +
> > +	/* configure charge pump current settings */
> > +	tmp = DIV_ROUND_CLOSEST(st->data.charge_pump_voltage_mv, ADF41513_MIN_CP_VOLTAGE_mV);
> > +	st->regs[ADF41513_REG5] |= FIELD_PREP(ADF41513_REG5_CP_CURRENT_MSK, tmp - 1);
> > +
> > +	/* narrow ABP | loss of lock detect enable | SD reset | LDP from data */
> 
> I'm not sure what LPD from data means. Can't correlate that with the datasheet.
> Perhaps add more info or reword.

will remove, this is not applicable anymore.

> > +	st->regs[ADF41513_REG6] = ADF41513_REG6_ABP_MSK |
> > +				  ADF41513_REG6_LOL_ENABLE_MSK |
> > +				  ADF41513_REG6_SD_RESET_MSK;
> > +	if (st->data.phase_detector_polarity)
> > +		st->regs[ADF41513_REG6] |= ADF41513_REG6_PD_POLARITY_MSK;
> > +
> > +	/* PS bias | lock detect count */
> Confusing comment as covering multiple bits of code. I'd just drop
> it on basis the field names in the code are less confusing than the comment.

ack. will drop.

> > +	st->regs[ADF41513_REG7] = FIELD_PREP(ADF41513_REG7_PS_BIAS_MSK, 2);
> 
> That magic 2 is interesting as it is truely magic with no explanation on
> the datasheet beyond 'program this value'. Even better, on the datasheet I'm
> looking at the Prescaler (PS) bias section says set it to 3 and figure 30
> say set it to 2.  Maybe add a commeon on this.

understood. 2 should be the correct vallue, but I will ask around.

> > +	tmp = ilog2(st->data.lock_detect_count);
> > +	if (st->data.lock_detect_count < ADF41513_LD_COUNT_FAST_LIMIT) {
> > +		tmp -= const_ilog2(ADF41513_LD_COUNT_FAST_MIN);
> > +		st->regs[ADF41513_REG7] |= ADF41513_REG7_LD_CLK_SEL_MSK;
> > +	} else {
> > +		tmp -= const_ilog2(ADF41513_LD_COUNT_MIN);
> > +	}
> > +	st->regs[ADF41513_REG7] |= FIELD_PREP(ADF41513_REG7_LD_COUNT_MSK, tmp);
> > +
> > +	/* power down select */
> > +	st->regs[ADF41513_REG11] = ADF41513_REG11_POWER_DOWN_SEL_MSK;
> > +
> > +	/* muxout */
> > +	st->regs[ADF41513_REG12] = FIELD_PREP(ADF41513_REG12_MUXOUT_MSK,
> > +					      st->data.muxout_select);
> > +	st->regs[ADF41513_REG12] |= FIELD_PREP(ADF41513_REG12_LOGIC_LEVEL_MSK,
> > +					       st->data.muxout_1v8_en ? 0 : 1);
> > +
> > +	/* perform initialization sequence with power-up frequency */
> > +	return adf41513_set_frequency(st, (u64)st->data.power_up_frequency_hz * MICROHZ_PER_HZ,
> > +				      ADF41513_SYNC_ALL);
> > +}
> 
> ...
> 
> > +
> > +static int adf41513_pm_suspend(struct device *dev)
> > +{
> > +	struct adf41513_state *st = dev_get_drvdata(dev);
> > +
> > +	return adf41513_suspend(st);
> 
> Not at lot in point in the local variable
> 
> 	return adf41513_suspend(dev_get_drvdata(dev));

ack

> > +}
> > +
> > +static int adf41513_pm_resume(struct device *dev)
> > +{
> > +	struct adf41513_state *st = dev_get_drvdata(dev);
> > +
> > +	return adf41513_resume(st);
> As above.
> > +}
> > +
> > +static const struct adf41513_chip_info adf41513_chip_info = {
> > +	.name = "adf41513",
> > +	.has_prescaler_8_9 = true,
> > +	.max_rf_freq_hz = ADF41513_MAX_RF_FREQ,
> > +};
> > +
> > +static const struct adf41513_chip_info adf41510_chip_info = {
> 
> Just for long term organization when many devices are supported:
> keep these structures in alphanumeric order.

ack

> > +	.name = "adf41510",
> > +	.has_prescaler_8_9 = false,
> > +	.max_rf_freq_hz = ADF41510_MAX_RF_FREQ,
> > +};
> > +
> > +static int adf41513_probe(struct spi_device *spi)
> > +{
> > +	struct iio_dev *indio_dev;
> > +	struct adf41513_state *st;
> > +	int ret;
> > +
> > +	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
> 
> I'd use a 
> 	struct device *dev = &spi->dev;
> so that you can shorten all the lines where spi->dev is used in here.

ack

> > +	if (!indio_dev)
> > +		return -ENOMEM;
> > +
> > +	st = iio_priv(indio_dev);
> > +	st->spi = spi;
> > +	st->chip_info = spi_get_device_match_data(spi);
> > +	if (!st->chip_info)
> > +		return -EINVAL;
> > +
> > +	spi_set_drvdata(spi, st);
> > +
> > +	st->ref_clk = devm_clk_get_enabled(&spi->dev, NULL);
> > +	if (IS_ERR(st->ref_clk))
> > +		return PTR_ERR(st->ref_clk);
> > +
> > +	st->ref_freq_hz = clk_get_rate(st->ref_clk);
> > +	if (st->ref_freq_hz < ADF41513_MIN_REF_FREQ || st->ref_freq_hz > ADF41513_MAX_REF_FREQ)
> > +		return dev_err_probe(&spi->dev, -ERANGE,
> > +				     "reference frequency %llu Hz out of range\n",
> > +				     st->ref_freq_hz);
> > +
> > +	ret = adf41513_parse_fw(st);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = devm_regulator_bulk_get_enable(&spi->dev,
> > +					     ARRAY_SIZE(adf41513_power_supplies),
> > +					     adf41513_power_supplies);
> > +	if (ret)
> > +		return dev_err_probe(&spi->dev, ret,
> > +				     "failed to get and enable regulators\n");
> > +
> > +	st->chip_enable = devm_gpiod_get_optional(&spi->dev, "enable", GPIOD_OUT_HIGH);
> > +	if (IS_ERR(st->chip_enable))
> > +		return dev_err_probe(&spi->dev, PTR_ERR(st->chip_enable),
> > +				     "fail to request chip enable GPIO\n");
> > +
> > +	st->lock_detect = devm_gpiod_get_optional(&spi->dev, "lock-detect", GPIOD_IN);
> > +	if (IS_ERR(st->lock_detect))
> > +		return dev_err_probe(&spi->dev, PTR_ERR(st->lock_detect),
> > +				     "fail to request lock detect GPIO\n");
> > +
> > +	ret = devm_mutex_init(&spi->dev, &st->lock);
> > +	if (ret)
> > +		return ret;
> > +
> > +	indio_dev->name = st->chip_info->name;
> > +	indio_dev->info = &adf41513_info;
> > +	indio_dev->modes = INDIO_DIRECT_MODE;
> > +	indio_dev->channels = &adf41513_chan;
> > +	indio_dev->num_channels = 1;
> > +
> > +	ret = adf41513_setup(st);
> > +	if (ret < 0)
> > +		return dev_err_probe(&spi->dev, ret, "failed to setup device: %d\n", ret);
> Look at what dev_err_probe() prints.  (short answer, it includes a much nicer print
> of the error value than the one you have here).  So dev_err_probe() should never
> include the error value itself as that is duplicating the info.

yes, that looks bad. will adjust.

> > +
> > +	ret = devm_add_action_or_reset(&spi->dev, adf41513_power_down, st);
> > +	if (ret)
> > +		return dev_err_probe(&spi->dev, ret, "Failed to add power down action: %d\n", ret);
> 
> As above.  No printing ret by hand in dev_err_probe() calls.

ack

> > +
> > +	return devm_iio_device_register(&spi->dev, indio_dev);
> > +}

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ