> -----Original Message----- > From: Jonathan Cameron <jic23@xxxxxxxxxx> > Sent: Saturday, July 3, 2021 6:57 PM > To: Miclaus, Antoniu <Antoniu.Miclaus@xxxxxxxxxx> > Cc: linux-iio@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; > devicetree@xxxxxxxxxxxxxxx; robh+dt@xxxxxxxxxx > Subject: Re: [PATCH v4 1/2] iio: frequency: adrf6780: add support for > ADRF6780 > > On Fri, 2 Jul 2021 14:12:38 +0300 > Antoniu Miclaus <antoniu.miclaus@xxxxxxxxxx> wrote: > > > The ADRF6780 is a silicon germanium (SiGe) design, wideband, > > microwave upconverter optimized for point to point microwave > > radio designs operating in the 5.9 GHz to 23.6 GHz frequency > > range. > > > > Datasheet: > > https://www.analog.com/media/en/technical-documentation/data- > sheets/ADRF6780.pdf > > > > Signed-off-by: Antoniu Miclaus <antoniu.miclaus@xxxxxxxxxx> > > Hi Antoniu, > > Frequency drivers are fairly unusual so if you could add a listing of > the attributes in sysfs that would be great (it's nice practice anyway but > I don't insist on it!) > > Various fairly minor comments inline. > > Thanks, > > Jonathan > > > > --- > > changes in v4: > > - change license to: GPL-2.0-only > > drivers/iio/frequency/Kconfig | 13 + > > drivers/iio/frequency/Makefile | 1 + > > drivers/iio/frequency/adrf6780.c | 498 > +++++++++++++++++++++++++++++++ > > 3 files changed, 512 insertions(+) > > create mode 100644 drivers/iio/frequency/adrf6780.c > > > > diff --git a/drivers/iio/frequency/Kconfig > b/drivers/iio/frequency/Kconfig > > index 240b81502512..fc9751c48f59 100644 > > --- a/drivers/iio/frequency/Kconfig > > +++ b/drivers/iio/frequency/Kconfig > > @@ -49,5 +49,18 @@ config ADF4371 > > > > To compile this driver as a module, choose M here: the > > module will be called adf4371. > > + > > +config ADRF6780 > > + tristate "Analog Devices ADRF6780 Microwave Upconverter" > > + depends on SPI > > + depends on COMMON_CLK > > + depends on OF > > Why? Pretty much everything seems to have defaults if not provided > via OF. > I've asked for the generic firmware functions anyway, so you can drop > this > for that reason if nothing else! > > > + help > > + Say yes here to build support for Analog Devices ADRF6780 > > + 5.9 GHz to 23.6 GHz, Wideband, Microwave Upconverter. > > + > > + To compile this driver as a module, choose M here: the > > + module will be called adrf6780. > > + > > endmenu > > endmenu > > diff --git a/drivers/iio/frequency/Makefile > b/drivers/iio/frequency/Makefile > > index 518b1e50caef..ae3136c79202 100644 > > --- a/drivers/iio/frequency/Makefile > > +++ b/drivers/iio/frequency/Makefile > > @@ -7,3 +7,4 @@ > > obj-$(CONFIG_AD9523) += ad9523.o > > obj-$(CONFIG_ADF4350) += adf4350.o > > obj-$(CONFIG_ADF4371) += adf4371.o > > +obj-$(CONFIG_ADRF6780) += adrf6780.o > > diff --git a/drivers/iio/frequency/adrf6780.c > b/drivers/iio/frequency/adrf6780.c > > new file mode 100644 > > index 000000000000..472a66f90c7f > > --- /dev/null > > +++ b/drivers/iio/frequency/adrf6780.c > > @@ -0,0 +1,498 @@ > > +// SPDX-License-Identifier: GPL-2.0-only > > +/* > > + * ADRF6780 driver > > + * > > + * Copyright 2021 Analog Devices Inc. > > + */ > > + > > +#include <linux/bitfield.h> > > +#include <linux/bits.h> > > +#include <linux/clk.h> > > +#include <linux/clkdev.h> > > +#include <linux/clk-provider.h> > > +#include <linux/delay.h> > > +#include <linux/device.h> > > +#include <linux/iio/iio.h> > > +#include <linux/module.h> > > #include <linux/mod_devicetable.h> > > > +#include <linux/spi/spi.h> > > + > > +/* ADRF6780 Register Map */ > > +#define ADRF6780_REG_CONTROL 0x00 > > +#define ADRF6780_REG_ALARM_READBACK 0x01 > > +#define ADRF6780_REG_ALARM_MASKS 0x02 > > +#define ADRF6780_REG_ENABLE 0x03 > > +#define ADRF6780_REG_LINEARIZE 0x04 > > +#define ADRF6780_REG_LO_PATH 0x05 > > +#define ADRF6780_REG_ADC_CONTROL 0x06 > > +#define ADRF6780_REG_ADC_OUTPUT 0x0C > > + > > +/* ADRF6780_REG_CONTROL Map */ > > +#define ADRF6780_PARITY_EN_MSK BIT(15) > > +#define ADRF6780_PARITY_EN(x) > FIELD_PREP(ADRF6780_PARITY_EN_MSK, x) > > +#define ADRF6780_SOFT_RESET_MSK BIT(14) > > +#define ADRF6780_SOFT_RESET(x) > FIELD_PREP(ADRF6780_SOFT_RESET_MSK, x) > > +#define ADRF6780_CHIP_ID_MSK GENMASK(11, 4) > > +#define ADRF6780_CHIP_ID 0xA > > +#define ADRF6780_CHIP_REVISION_MSK GENMASK(3, 0) > > +#define ADRF6780_CHIP_REVISION(x) > FIELD_PREP(ADRF6780_CHIP_REVISION_MSK, x) > > + > > +/* ADRF6780_REG_ALARM_READBACK Map */ > > +#define ADRF6780_PARITY_ERROR_MSK BIT(15) > > +#define ADRF6780_PARITY_ERROR(x) > FIELD_PREP(ADRF6780_PARITY_ERROR_MSK, x) > > +#define ADRF6780_TOO_FEW_ERRORS_MSK BIT(14) > > +#define ADRF6780_TOO_FEW_ERRORS(x) > FIELD_PREP(ADRF6780_TOO_FEW_ERRORS_MSK, x) > > +#define ADRF6780_TOO_MANY_ERRORS_MSK BIT(13) > > +#define ADRF6780_TOO_MANY_ERRORS(x) > FIELD_PREP(ADRF6780_TOO_MANY_ERRORS_MSK, x) > > +#define ADRF6780_ADDRESS_RANGE_ERROR_MSK BIT(12) > > +#define ADRF6780_ADDRESS_RANGE_ERROR(x) > FIELD_PREP(ADRF6780_ADDRESS_RANGE_ERROR_MSK, x) > > + > > +/* ADRF6780_REG_ENABLE Map */ > > +#define ADRF6780_VGA_BUFFER_EN_MSK BIT(8) > > +#define ADRF6780_VGA_BUFFER_EN(x) > FIELD_PREP(ADRF6780_VGA_BUFFER_EN_MSK, x) > > +#define ADRF6780_DETECTOR_EN_MSK BIT(7) > > +#define ADRF6780_DETECTOR_EN(x) > FIELD_PREP(ADRF6780_DETECTOR_EN_MSK, x) > > +#define ADRF6780_LO_BUFFER_EN_MSK BIT(6) > > +#define ADRF6780_LO_BUFFER_EN(x) > FIELD_PREP(ADRF6780_LO_BUFFER_EN_MSK, x) > > +#define ADRF6780_IF_MODE_EN_MSK BIT(5) > > +#define ADRF6780_IF_MODE_EN(x) > FIELD_PREP(ADRF6780_IF_MODE_EN_MSK, x) > > +#define ADRF6780_IQ_MODE_EN_MSK BIT(4) > > +#define ADRF6780_IQ_MODE_EN(x) > FIELD_PREP(ADRF6780_IQ_MODE_EN_MSK, x) > > +#define ADRF6780_LO_X2_EN_MSK BIT(3) > > +#define ADRF6780_LO_X2_EN(x) > FIELD_PREP(ADRF6780_LO_X2_EN_MSK, x) > > +#define ADRF6780_LO_PPF_EN_MSK BIT(2) > > +#define ADRF6780_LO_PPF_EN(x) > FIELD_PREP(ADRF6780_LO_PPF_EN_MSK, x) > > +#define ADRF6780_LO_EN_MSK BIT(1) > > +#define ADRF6780_LO_EN(x) > FIELD_PREP(ADRF6780_LO_EN_MSK, x) > > +#define ADRF6780_UC_BIAS_EN_MSK BIT(0) > > +#define ADRF6780_UC_BIAS_EN(x) > FIELD_PREP(ADRF6780_UC_BIAS_EN_MSK, x) > > + > > +/* ADRF6780_REG_LINEARIZE Map */ > > +#define ADRF6780_RDAC_LINEARIZE_MSK GENMASK(7, 0) > > +#define ADRF6780_RDAC_LINEARIZE(x) > FIELD_PREP(ADRF6780_RDAC_LINEARIZE_MSK, x) > > + > > +/* ADRF6780_REG_LO_PATH Map */ > > +#define ADRF6780_LO_SIDEBAND_MSK BIT(10) > > +#define ADRF6780_LO_SIDEBAND(x) > FIELD_PREP(ADRF6780_LO_SIDEBAND_MSK, x) > > +#define ADRF6780_Q_PATH_PHASE_ACCURACY_MSK > GENMASK(7, 4) > > +#define ADRF6780_Q_PATH_PHASE_ACCURACY(x) > FIELD_PREP(ADRF6780_Q_PATH_PHASE_ACCURACY_MSK, x) > > +#define ADRF6780_I_PATH_PHASE_ACCURACY_MSK > GENMASK(3, 0) > > +#define ADRF6780_I_PATH_PHASE_ACCURACY(x) > FIELD_PREP(ADRF6780_I_PATH_PHASE_ACCURACY_MSK, x) > > + > > +/* ADRF6780_REG_ADC_CONTROL Map */ > > +#define ADRF6780_VDET_OUTPUT_SELECT_MSK BIT(3) > > +#define ADRF6780_VDET_OUTPUT_SELECT(x) > FIELD_PREP(ADRF6780_VDET_OUTPUT_SELECT_MSK, x) > > +#define ADRF6780_ADC_START_MSK BIT(2) > > +#define ADRF6780_ADC_START(x) > FIELD_PREP(ADRF6780_ADC_START_MSK, x) > > +#define ADRF6780_ADC_EN_MSK BIT(1) > > +#define ADRF6780_ADC_EN(x) > FIELD_PREP(ADRF6780_ADC_EN_MSK, x) > > +#define ADRF6780_ADC_CLOCK_EN_MSK BIT(0) > > +#define ADRF6780_ADC_CLOCK_EN(x) > FIELD_PREP(ADRF6780_ADC_CLOCK_EN_MSK, x) > > + > > +/* ADRF6780_REG_ADC_OUTPUT Map */ > > +#define ADRF6780_ADC_STATUS_MSK BIT(8) > > +#define ADRF6780_ADC_STATUS(x) > FIELD_PREP(ADRF6780_ADC_STATUS_MSK, x) > > +#define ADRF6780_ADC_VALUE_MSK > GENMASK(7, 0) > > +#define ADRF6780_ADC_VALUE(x) > FIELD_PREP(ADRF6780_ADC_VALUE_MSK, x) > > Not used. In general, just use FIELD_PREP / FIELD_GET inline rather > than having extra > macros like these. That approach is simpler for reviewers to follow. > > > + > > +struct adrf6780_dev { > > + struct spi_device *spi; > > + struct clk *clkin; > > + /* Protect against concurrent accesses to the device */ > > + struct mutex lock; > > + bool vga_buff_en; > > + bool lo_buff_en; > > + bool if_mode_en; > > + bool iq_mode_en; > > + bool lo_x2_en; > > + bool lo_ppf_en; > > + bool lo_en; > > + bool uc_bias_en; > > + bool lo_sideband; > > + bool vdet_out_en; > > +}; > > + > > +static int adrf6780_spi_read(struct adrf6780_dev *dev, unsigned int > reg, > > + unsigned int *val) > > +{ > > + int ret; > > + unsigned int temp; > > + struct spi_transfer t = {0}; > > + u8 data[3]; > > + > > + data[0] = 0x80 | (reg << 1); > > + data[1] = 0x0; > > + data[2] = 0x0; > > + > > + t.rx_buf = &data[0]; > > + t.tx_buf = &data[0]; > > + t.len = 3; > > + > > + ret = spi_sync_transfer(dev->spi, &t, 1); > > data needs to be dma safe. > > > + if (ret < 0) > > + return ret; > > + > > + temp = ((data[0] | 0x80 | (reg << 1)) << 16) | > > + (data[1] << 8) | data[2]; > > Ouch. That's a bit nasty, but why are you writing the reg into > it? Looks like a get_unaligned_be24() >> 1 and a 16bit mask. > (use GENMASK(15, 0) for that to make it apparent what is happening. > > > + > > + *val = (temp >> 1) & 0xFFFF; > > + > > + return ret; > > +} > > + > > +static int adrf6780_spi_write(struct adrf6780_dev *dev, > > + unsigned int reg, > > + unsigned int val) > > +{ > > + u8 data[3]; > > + > > + val = (val << 1); > > + > > + data[0] = (reg << 1) | (val >> 16); > > + data[1] = val >> 8; > > + data[2] = val; > > An opportunity for > put_unaligned_be24() with a value of (I think) > > (val << 1) | (reg << 17) > > > > + > > + return spi_write(dev->spi, &data[0], 3); > > Needs a dma safe buffer, which basically means it can't be on the > stack. > Lots of ways of handling that, but look for __cacheline_aligned in IIO > drivers > to see the one we probably use mostly commonly in IIO drivers. Hi Jonathan, This is something I wanted to ask for some time so I will take the opportunity here :). Is this something you prefer just not to risk at all and make it an hard requirement (which is fair)? ... I'm asking this because, tbh, I would be very surprised if any spi/i2c controller out there is using dma for a 3byte transfer. I guess the overhead of setting it up is probably not worth it... For instance, in i2c [1], the "educated guess" is around 8byte (to start using dma safe buffers). [1]: https://elixir.bootlin.com/linux/latest/source/Documentation/i2c/dma-considerations.rst#L15 - Nuno Sá